@@ -11,9 +11,14 @@ import (
11
11
"github.com/uber/h3-go/v3"
12
12
)
13
13
14
- // ErrNoSlots means that the number of virtual nodes is distributed by 100%.
15
- // It is necessary to change the configuration of virtual nodes.
16
- var ErrNoSlots = errors .New ("h3geodist: no distribute slots" )
14
+ var (
15
+ // ErrNoSlots means that the number of virtual nodes is distributed by 100%.
16
+ // It is necessary to change the configuration of virtual nodes.
17
+ ErrNoSlots = errors .New ("h3geodist: no distribute slots" )
18
+
19
+ // ErrVNodes returns when there are no virtual nodes.
20
+ ErrVNodes = errors .New ("h3geodist: vnodes not found" )
21
+ )
17
22
18
23
// Distributed holds information about nodes,
19
24
// and scheduler of virtual nodes with replicas.
@@ -32,12 +37,20 @@ type Distributed struct {
32
37
}
33
38
34
39
// Cell is a type to represent a distributed cell
35
- // with specifying the hostname and H3 index .
40
+ // with specifying the hostname and H3 Index .
36
41
type Cell struct {
37
42
H3ID h3.H3Index
38
43
Host string
39
44
}
40
45
46
+ func (c Cell ) String () string {
47
+ return fmt .Sprintf ("Cell{Host: %s, ID: %s}" , c .Host , h3 .ToString (c .H3ID ))
48
+ }
49
+
50
+ func (c Cell ) HexID () string {
51
+ return h3 .ToString (c .H3ID )
52
+ }
53
+
41
54
// NodeInfo is a type to represent a node load statistic.
42
55
type NodeInfo struct {
43
56
Host string
@@ -156,7 +169,7 @@ func (d *Distributed) WhereIsMyParent(child h3.H3Index) (c Cell, err error) {
156
169
cell := h3 .ToParent (child , d .level )
157
170
addr , ok := d .lookup (cell )
158
171
if ! ok {
159
- return c , fmt . Errorf ( "h3geodist: distributed cell %v not found" , cell )
172
+ return c , ErrVNodes
160
173
}
161
174
c .H3ID = cell
162
175
c .Host = addr
@@ -170,11 +183,54 @@ func (d *Distributed) LookupFromLatLon(lat float64, lon float64) (c Cell, err er
170
183
cell := h3 .FromGeo (h3.GeoCoord {Latitude : lat , Longitude : lon }, d .level )
171
184
addr , ok := d .lookup (cell )
172
185
if ! ok {
173
- return c , fmt . Errorf ( "h3geodist: distributed cell %v not found" , cell )
186
+ return c , ErrVNodes
174
187
}
175
188
return Cell {H3ID : cell , Host : addr }, nil
176
189
}
177
190
191
+ // Neighbor is a type for represent a neighbor distributed cell,
192
+ // with the distance from a target point to the center of each neighbor.
193
+ type Neighbor struct {
194
+ Cell Cell
195
+ DistanceM float64
196
+ }
197
+
198
+ // NeighborsFromLatLon returns the current distributed cell
199
+ // for a geographic coordinate and neighbors sorted by distance in descending order.
200
+ // Distance is measured from geographic coordinates to the center of each neighbor.
201
+ func (d * Distributed ) NeighborsFromLatLon (lat float64 , lon float64 ) (target Cell , neighbors []Neighbor , err error ) {
202
+ d .mu .RLock ()
203
+ defer d .mu .RUnlock ()
204
+ src := h3.GeoCoord {Latitude : lat , Longitude : lon }
205
+ cell := h3 .FromGeo (src , d .level )
206
+ addr , ok := d .lookup (cell )
207
+ if ! ok {
208
+ return target , nil , ErrVNodes
209
+ }
210
+ target .Host = addr
211
+ target .H3ID = cell
212
+ ring := h3 .KRing (cell , 1 )
213
+ neighbors = make ([]Neighbor , 0 , len (ring ))
214
+ for i := 0 ; i < len (ring ); i ++ {
215
+ if ! h3 .AreNeighbors (cell , ring [i ]) {
216
+ continue
217
+ }
218
+ addr , ok := d .lookup (ring [i ])
219
+ if ! ok {
220
+ continue
221
+ }
222
+ dest := h3 .ToGeo (ring [i ])
223
+ neighbors = append (neighbors , Neighbor {
224
+ Cell : Cell {Host : addr , H3ID : ring [i ]},
225
+ DistanceM : h3 .PointDistM (src , dest ),
226
+ })
227
+ }
228
+ sort .Slice (neighbors , func (i , j int ) bool {
229
+ return neighbors [i ].DistanceM < neighbors [j ].DistanceM
230
+ })
231
+ return
232
+ }
233
+
178
234
// ReplicaFor returns a list of hosts for replication.
179
235
func (d * Distributed ) ReplicaFor (cell h3.H3Index , n int ) ([]string , error ) {
180
236
d .mu .RLock ()
@@ -189,7 +245,7 @@ func (d *Distributed) ReplicaFor(cell h3.H3Index, n int) ([]string, error) {
189
245
var next int
190
246
myaddr , ok := d .lookup (cell )
191
247
if ! ok {
192
- return nil , fmt . Errorf ( "h3geodist: vnode for cell %v not found" , cell )
248
+ return nil , ErrVNodes
193
249
}
194
250
keys := make ([]uint64 , 0 , 4 )
195
251
hosts := make (map [uint64 ]* node )
@@ -241,7 +297,7 @@ func (d *Distributed) LookupMany(cell []h3.H3Index, iter func(c Cell) bool) bool
241
297
return true
242
298
}
243
299
244
- // VNodeIndex returns the index of the virtual node by H3Index.
300
+ // VNodeIndex returns the Index of the virtual node by H3Index.
245
301
func (d * Distributed ) VNodeIndex (cell h3.H3Index ) int {
246
302
hashKey := uint2hash (uint64 (cell ))
247
303
return int (hashKey % d .vnodes )
0 commit comments