Skip to content
This repository was archived by the owner on Dec 20, 2024. It is now read-only.

Commit 7e04f05

Browse files
committed
feature: define the interface SupernodeLocator
Signed-off-by: lowzj <[email protected]>
1 parent ab71c0d commit 7e04f05

File tree

4 files changed

+402
-1
lines changed

4 files changed

+402
-1
lines changed

dfget/config/constants.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ const (
120120
ServerAliveTime = 5 * time.Minute
121121
DefaultDownloadTimeout = 5 * time.Minute
122122

123-
DefaultSupernodePort = 8002
123+
DefaultSupernodeSchema = "http"
124+
DefaultSupernodePort = 8002
124125
)
125126

126127
/* errors code */

dfget/locator/locator.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright The Dragonfly Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package locator
18+
19+
// SupernodeLocator defines the way how to get available supernodes.
20+
// Developers can implement their own locator more flexibly , not just get the
21+
// supernode list from configuration or CLI.
22+
type SupernodeLocator interface {
23+
// Get returns the current selected supernode, it should be idempotent.
24+
Get() *Supernode
25+
26+
// Next chooses the next available supernode for retrying or other
27+
// purpose. The current supernode should be set as this result.
28+
Next() *Supernode
29+
30+
// GetGroup returns the group with the giving name.
31+
GetGroup(name string) *SupernodeGroup
32+
33+
// All returns all the supernodes.
34+
All() []*SupernodeGroup
35+
36+
// Report records the metrics of the current supernode in order to choose a
37+
// more appropriate supernode for the next time if necessary.
38+
Report(node string, metrics *SupernodeMetrics)
39+
40+
// Refresh refreshes all the supernodes.
41+
Refresh() bool
42+
}
43+
44+
// SupernodeGroup groups supernodes which have same attributes.
45+
// For example, we can group supernodes by region, business, version and so on.
46+
// The implementation of SupernodeLocator can select a supernode based on the
47+
// group.
48+
type SupernodeGroup struct {
49+
Name string
50+
Nodes []*Supernode
51+
52+
// Infos stores other information that user can customized.
53+
Infos map[string]string
54+
}
55+
56+
// GetNode return the node with the giving index.
57+
func (sg *SupernodeGroup) GetNode(idx int) *Supernode {
58+
if idx < 0 || idx >= len(sg.Nodes) {
59+
return nil
60+
}
61+
return sg.Nodes[idx]
62+
}
63+
64+
// Supernode holds the basic information of supernodes.
65+
type Supernode struct {
66+
Schema string
67+
IP string
68+
Port int
69+
Weight int
70+
GroupName string
71+
Metrics *SupernodeMetrics
72+
}
73+
74+
// SupernodeMetrics holds metrics used for the locator to choose supernode.
75+
type SupernodeMetrics struct {
76+
Metrics map[string]interface{}
77+
}

dfget/locator/static_locator.go

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*
2+
* Copyright The Dragonfly Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package locator
18+
19+
import (
20+
"math/rand"
21+
"sync/atomic"
22+
"time"
23+
24+
"github.com/dragonflyoss/Dragonfly/dfget/config"
25+
"github.com/dragonflyoss/Dragonfly/pkg/algorithm"
26+
"github.com/dragonflyoss/Dragonfly/pkg/netutils"
27+
)
28+
29+
func init() {
30+
rand.Seed(time.Now().UnixNano())
31+
}
32+
33+
const staticLocatorGroupName = "config"
34+
35+
// StaticLocator uses the nodes passed from configuration or CLI.
36+
type StaticLocator struct {
37+
idx int32
38+
Group *SupernodeGroup
39+
}
40+
41+
// ----------------------------------------------------------------------------
42+
// constructors
43+
44+
// NewStaticLocator constructs StaticLocator which uses the nodes passed from
45+
// configuration or CLI.
46+
func NewStaticLocator(nodes []*config.NodeWeight) *StaticLocator {
47+
locator := &StaticLocator{}
48+
if len(nodes) == 0 {
49+
return locator
50+
}
51+
group := &SupernodeGroup{
52+
Name: staticLocatorGroupName,
53+
}
54+
for _, node := range nodes {
55+
ip, port := netutils.GetIPAndPortFromNode(node.Node, config.DefaultSupernodePort)
56+
if ip == "" {
57+
continue
58+
}
59+
supernode := &Supernode{
60+
Schema: config.DefaultSupernodeSchema,
61+
IP: ip,
62+
Port: port,
63+
Weight: node.Weight,
64+
GroupName: staticLocatorGroupName,
65+
}
66+
for i := 0; i < supernode.Weight; i++ {
67+
group.Nodes = append(group.Nodes, supernode)
68+
}
69+
}
70+
shuffleNodes(group.Nodes)
71+
locator.Group = group
72+
return locator
73+
}
74+
75+
// NewStaticLocatorFromStr constructs StaticLocator from string list.
76+
// The format of nodes is: ip:port=weight
77+
func NewStaticLocatorFromStr(nodes []string) (*StaticLocator, error) {
78+
nodeWeight, err := config.ParseNodesSlice(nodes)
79+
if err != nil {
80+
return nil, err
81+
}
82+
return NewStaticLocator(nodeWeight), nil
83+
}
84+
85+
// ----------------------------------------------------------------------------
86+
// implement api methods
87+
88+
func (s *StaticLocator) Get() *Supernode {
89+
if s.Group == nil {
90+
return nil
91+
}
92+
return s.Group.GetNode(s.load())
93+
}
94+
95+
func (s *StaticLocator) Next() *Supernode {
96+
if s.Group == nil || s.load() >= len(s.Group.Nodes) {
97+
return nil
98+
}
99+
return s.Group.GetNode(s.inc())
100+
}
101+
102+
func (s *StaticLocator) GetGroup(name string) *SupernodeGroup {
103+
if s.Group == nil || s.Group.Name != name {
104+
return nil
105+
}
106+
return s.Group
107+
}
108+
109+
func (s *StaticLocator) All() []*SupernodeGroup {
110+
if s.Group == nil {
111+
return nil
112+
}
113+
return []*SupernodeGroup{s.Group}
114+
}
115+
116+
func (s *StaticLocator) Report(node string, metrics *SupernodeMetrics) {
117+
// unnecessary to implement this method
118+
return
119+
}
120+
121+
func (s *StaticLocator) Refresh() bool {
122+
atomic.StoreInt32(&s.idx, 0)
123+
return true
124+
}
125+
126+
// ----------------------------------------------------------------------------
127+
// private methods of StaticLocator
128+
129+
func (s *StaticLocator) load() int {
130+
return int(atomic.LoadInt32(&s.idx))
131+
}
132+
133+
func (s *StaticLocator) inc() int {
134+
return int(atomic.AddInt32(&s.idx, 1))
135+
}
136+
137+
// ----------------------------------------------------------------------------
138+
// helper functions
139+
140+
func shuffleNodes(nodes []*Supernode) []*Supernode {
141+
if length := len(nodes); length > 1 {
142+
algorithm.Shuffle(length, func(i, j int) {
143+
nodes[i], nodes[j] = nodes[j], nodes[i]
144+
})
145+
}
146+
return nodes
147+
}

0 commit comments

Comments
 (0)