github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/libnetwork/networkdb/networkdb.go (about) 1 package networkdb 2 3 //go:generate protoc -I=. -I=../../vendor/ --gogofaster_out=import_path=github.com/Prakhar-Agarwal-byte/moby/libnetwork/networkdb:. networkdb.proto 4 5 import ( 6 "context" 7 "fmt" 8 "os" 9 "strings" 10 "sync" 11 "sync/atomic" 12 "time" 13 14 "github.com/containerd/log" 15 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/types" 16 "github.com/Prakhar-Agarwal-byte/moby/pkg/stringid" 17 "github.com/docker/go-events" 18 iradix "github.com/hashicorp/go-immutable-radix" 19 "github.com/hashicorp/memberlist" 20 "github.com/hashicorp/serf/serf" 21 ) 22 23 const ( 24 byTable int = 1 + iota 25 byNetwork 26 ) 27 28 // NetworkDB instance drives the networkdb cluster and acts the broker 29 // for cluster-scoped and network-scoped gossip and watches. 30 type NetworkDB struct { 31 // The clocks MUST be the first things 32 // in this struct due to Golang issue #599. 33 34 // Global lamport clock for node network attach events. 35 networkClock serf.LamportClock 36 37 // Global lamport clock for table events. 38 tableClock serf.LamportClock 39 40 sync.RWMutex 41 42 // NetworkDB configuration. 43 config *Config 44 45 // All the tree index (byTable, byNetwork) that we maintain 46 // the db. 47 indexes map[int]*iradix.Tree 48 49 // Memberlist we use to drive the cluster. 50 memberlist *memberlist.Memberlist 51 52 // List of all peer nodes in the cluster not-limited to any 53 // network. 54 nodes map[string]*node 55 56 // List of all peer nodes which have failed 57 failedNodes map[string]*node 58 59 // List of all peer nodes which have left 60 leftNodes map[string]*node 61 62 // A multi-dimensional map of network/node attachments. The 63 // first key is a node name and the second key is a network ID 64 // for the network that node is participating in. 65 networks map[string]map[string]*network 66 67 // A map of nodes which are participating in a given 68 // network. The key is a network ID. 69 networkNodes map[string][]string 70 71 // A table of ack channels for every node from which we are 72 // waiting for an ack. 73 bulkSyncAckTbl map[string]chan struct{} 74 75 // Broadcast queue for network event gossip. 76 networkBroadcasts *memberlist.TransmitLimitedQueue 77 78 // Broadcast queue for node event gossip. 79 nodeBroadcasts *memberlist.TransmitLimitedQueue 80 81 // A central context to stop all go routines running on 82 // behalf of the NetworkDB instance. 83 ctx context.Context 84 cancelCtx context.CancelFunc 85 86 // A central broadcaster for all local watchers watching table 87 // events. 88 broadcaster *events.Broadcaster 89 90 // List of all tickers which needed to be stopped when 91 // cleaning up. 92 tickers []*time.Ticker 93 94 // Reference to the memberlist's keyring to add & remove keys 95 keyring *memberlist.Keyring 96 97 // bootStrapIP is the list of IPs that can be used to bootstrap 98 // the gossip. 99 bootStrapIP []string 100 101 // lastStatsTimestamp is the last timestamp when the stats got printed 102 lastStatsTimestamp time.Time 103 104 // lastHealthTimestamp is the last timestamp when the health score got printed 105 lastHealthTimestamp time.Time 106 } 107 108 // PeerInfo represents the peer (gossip cluster) nodes of a network 109 type PeerInfo struct { 110 Name string 111 IP string 112 } 113 114 // PeerClusterInfo represents the peer (gossip cluster) nodes 115 type PeerClusterInfo struct { 116 PeerInfo 117 } 118 119 type node struct { 120 memberlist.Node 121 ltime serf.LamportTime 122 // Number of hours left before the reaper removes the node 123 reapTime time.Duration 124 } 125 126 // network describes the node/network attachment. 127 type network struct { 128 // Network ID 129 id string 130 131 // Lamport time for the latest state of the entry. 132 ltime serf.LamportTime 133 134 // Gets set to true after the first bulk sync happens 135 inSync bool 136 137 // Node leave is in progress. 138 leaving bool 139 140 // Number of seconds still left before a deleted network entry gets 141 // removed from networkDB 142 reapTime time.Duration 143 144 // The broadcast queue for table event gossip. This is only 145 // initialized for this node's network attachment entries. 146 tableBroadcasts *memberlist.TransmitLimitedQueue 147 148 // Number of gossip messages sent related to this network during the last stats collection period 149 qMessagesSent atomic.Int64 150 151 // Number of entries on the network. This value is the sum of all the entries of all the tables of a specific network. 152 // Its use is for statistics purposes. It keep tracks of database size and is printed per network every StatsPrintPeriod 153 // interval 154 entriesNumber atomic.Int64 155 } 156 157 // Config represents the configuration of the networkdb instance and 158 // can be passed by the caller. 159 type Config struct { 160 // NodeID is the node unique identifier of the node when is part of the cluster 161 NodeID string 162 163 // Hostname is the node hostname. 164 Hostname string 165 166 // BindAddr is the IP on which networkdb listens. It can be 167 // 0.0.0.0 to listen on all addresses on the host. 168 BindAddr string 169 170 // AdvertiseAddr is the node's IP address that we advertise for 171 // cluster communication. 172 AdvertiseAddr string 173 174 // BindPort is the local node's port to which we bind to for 175 // cluster communication. 176 BindPort int 177 178 // Keys to be added to the Keyring of the memberlist. Key at index 179 // 0 is the primary key 180 Keys [][]byte 181 182 // PacketBufferSize is the maximum number of bytes that memberlist will 183 // put in a packet (this will be for UDP packets by default with a NetTransport). 184 // A safe value for this is typically 1400 bytes (which is the default). However, 185 // depending on your network's MTU (Maximum Transmission Unit) you may 186 // be able to increase this to get more content into each gossip packet. 187 PacketBufferSize int 188 189 // reapEntryInterval duration of a deleted entry before being garbage collected 190 reapEntryInterval time.Duration 191 192 // reapNetworkInterval duration of a delted network before being garbage collected 193 // NOTE this MUST always be higher than reapEntryInterval 194 reapNetworkInterval time.Duration 195 196 // rejoinClusterDuration represents retryJoin timeout used by rejoinClusterBootStrap. 197 // Default is 10sec. 198 rejoinClusterDuration time.Duration 199 200 // rejoinClusterInterval represents interval on which rejoinClusterBootStrap runs. 201 // Default is 60sec. 202 rejoinClusterInterval time.Duration 203 204 // StatsPrintPeriod the period to use to print queue stats 205 // Default is 5min 206 StatsPrintPeriod time.Duration 207 208 // HealthPrintPeriod the period to use to print the health score 209 // Default is 1min 210 HealthPrintPeriod time.Duration 211 } 212 213 // entry defines a table entry 214 type entry struct { 215 // node from which this entry was learned. 216 node string 217 218 // Lamport time for the most recent update to the entry 219 ltime serf.LamportTime 220 221 // Opaque value store in the entry 222 value []byte 223 224 // Deleting the entry is in progress. All entries linger in 225 // the cluster for certain amount of time after deletion. 226 deleting bool 227 228 // Number of seconds still left before a deleted table entry gets 229 // removed from networkDB 230 reapTime time.Duration 231 } 232 233 // DefaultConfig returns a NetworkDB config with default values 234 func DefaultConfig() *Config { 235 hostname, _ := os.Hostname() 236 return &Config{ 237 NodeID: stringid.TruncateID(stringid.GenerateRandomID()), 238 Hostname: hostname, 239 BindAddr: "0.0.0.0", 240 PacketBufferSize: 1400, 241 StatsPrintPeriod: 5 * time.Minute, 242 HealthPrintPeriod: 1 * time.Minute, 243 reapEntryInterval: 30 * time.Minute, 244 rejoinClusterDuration: 10 * time.Second, 245 rejoinClusterInterval: 60 * time.Second, 246 } 247 } 248 249 // New creates a new instance of NetworkDB using the Config passed by 250 // the caller. 251 func New(c *Config) (*NetworkDB, error) { 252 // The garbage collection logic for entries leverage the presence of the network. 253 // For this reason the expiration time of the network is put slightly higher than the entry expiration so that 254 // there is at least 5 extra cycle to make sure that all the entries are properly deleted before deleting the network. 255 c.reapNetworkInterval = c.reapEntryInterval + 5*reapPeriod 256 257 nDB := &NetworkDB{ 258 config: c, 259 indexes: make(map[int]*iradix.Tree), 260 networks: make(map[string]map[string]*network), 261 nodes: make(map[string]*node), 262 failedNodes: make(map[string]*node), 263 leftNodes: make(map[string]*node), 264 networkNodes: make(map[string][]string), 265 bulkSyncAckTbl: make(map[string]chan struct{}), 266 broadcaster: events.NewBroadcaster(), 267 } 268 269 nDB.indexes[byTable] = iradix.New() 270 nDB.indexes[byNetwork] = iradix.New() 271 272 log.G(context.TODO()).Infof("New memberlist node - Node:%v will use memberlist nodeID:%v with config:%+v", c.Hostname, c.NodeID, c) 273 if err := nDB.clusterInit(); err != nil { 274 return nil, err 275 } 276 277 return nDB, nil 278 } 279 280 // Join joins this NetworkDB instance with a list of peer NetworkDB 281 // instances passed by the caller in the form of addr:port 282 func (nDB *NetworkDB) Join(members []string) error { 283 nDB.Lock() 284 nDB.bootStrapIP = append([]string(nil), members...) 285 log.G(context.TODO()).Infof("The new bootstrap node list is:%v", nDB.bootStrapIP) 286 nDB.Unlock() 287 return nDB.clusterJoin(members) 288 } 289 290 // Close destroys this NetworkDB instance by leave the cluster, 291 // stopping timers, canceling goroutines etc. 292 func (nDB *NetworkDB) Close() { 293 if err := nDB.clusterLeave(); err != nil { 294 log.G(context.TODO()).Errorf("%v(%v) Could not close DB: %v", nDB.config.Hostname, nDB.config.NodeID, err) 295 } 296 297 // Avoid (*Broadcaster).run goroutine leak 298 nDB.broadcaster.Close() 299 } 300 301 // ClusterPeers returns all the gossip cluster peers. 302 func (nDB *NetworkDB) ClusterPeers() []PeerInfo { 303 nDB.RLock() 304 defer nDB.RUnlock() 305 peers := make([]PeerInfo, 0, len(nDB.nodes)) 306 for _, node := range nDB.nodes { 307 peers = append(peers, PeerInfo{ 308 Name: node.Name, 309 IP: node.Node.Addr.String(), 310 }) 311 } 312 return peers 313 } 314 315 // Peers returns the gossip peers for a given network. 316 func (nDB *NetworkDB) Peers(nid string) []PeerInfo { 317 nDB.RLock() 318 defer nDB.RUnlock() 319 peers := make([]PeerInfo, 0, len(nDB.networkNodes[nid])) 320 for _, nodeName := range nDB.networkNodes[nid] { 321 if node, ok := nDB.nodes[nodeName]; ok { 322 peers = append(peers, PeerInfo{ 323 Name: node.Name, 324 IP: node.Addr.String(), 325 }) 326 } else { 327 // Added for testing purposes, this condition should never happen else mean that the network list 328 // is out of sync with the node list 329 peers = append(peers, PeerInfo{Name: nodeName, IP: "unknown"}) 330 } 331 } 332 return peers 333 } 334 335 // GetEntry retrieves the value of a table entry in a given (network, 336 // table, key) tuple 337 func (nDB *NetworkDB) GetEntry(tname, nid, key string) ([]byte, error) { 338 nDB.RLock() 339 defer nDB.RUnlock() 340 entry, err := nDB.getEntry(tname, nid, key) 341 if err != nil { 342 return nil, err 343 } 344 if entry != nil && entry.deleting { 345 return nil, types.NotFoundErrorf("entry in table %s network id %s and key %s deleted and pending garbage collection", tname, nid, key) 346 } 347 348 return entry.value, nil 349 } 350 351 func (nDB *NetworkDB) getEntry(tname, nid, key string) (*entry, error) { 352 e, ok := nDB.indexes[byTable].Get([]byte(fmt.Sprintf("/%s/%s/%s", tname, nid, key))) 353 if !ok { 354 return nil, types.NotFoundErrorf("could not get entry in table %s with network id %s and key %s", tname, nid, key) 355 } 356 357 return e.(*entry), nil 358 } 359 360 // CreateEntry creates a table entry in NetworkDB for given (network, 361 // table, key) tuple and if the NetworkDB is part of the cluster 362 // propagates this event to the cluster. It is an error to create an 363 // entry for the same tuple for which there is already an existing 364 // entry unless the current entry is deleting state. 365 func (nDB *NetworkDB) CreateEntry(tname, nid, key string, value []byte) error { 366 nDB.Lock() 367 oldEntry, err := nDB.getEntry(tname, nid, key) 368 if err == nil || (oldEntry != nil && !oldEntry.deleting) { 369 nDB.Unlock() 370 return fmt.Errorf("cannot create entry in table %s with network id %s and key %s, already exists", tname, nid, key) 371 } 372 373 entry := &entry{ 374 ltime: nDB.tableClock.Increment(), 375 node: nDB.config.NodeID, 376 value: value, 377 } 378 379 nDB.createOrUpdateEntry(nid, tname, key, entry) 380 nDB.Unlock() 381 382 if err := nDB.sendTableEvent(TableEventTypeCreate, nid, tname, key, entry); err != nil { 383 return fmt.Errorf("cannot send create event for table %s, %v", tname, err) 384 } 385 386 return nil 387 } 388 389 // UpdateEntry updates a table entry in NetworkDB for given (network, 390 // table, key) tuple and if the NetworkDB is part of the cluster 391 // propagates this event to the cluster. It is an error to update a 392 // non-existent entry. 393 func (nDB *NetworkDB) UpdateEntry(tname, nid, key string, value []byte) error { 394 nDB.Lock() 395 if _, err := nDB.getEntry(tname, nid, key); err != nil { 396 nDB.Unlock() 397 return fmt.Errorf("cannot update entry as the entry in table %s with network id %s and key %s does not exist", tname, nid, key) 398 } 399 400 entry := &entry{ 401 ltime: nDB.tableClock.Increment(), 402 node: nDB.config.NodeID, 403 value: value, 404 } 405 406 nDB.createOrUpdateEntry(nid, tname, key, entry) 407 nDB.Unlock() 408 409 if err := nDB.sendTableEvent(TableEventTypeUpdate, nid, tname, key, entry); err != nil { 410 return fmt.Errorf("cannot send table update event: %v", err) 411 } 412 413 return nil 414 } 415 416 // TableElem elem 417 type TableElem struct { 418 Value []byte 419 owner string 420 } 421 422 // GetTableByNetwork walks the networkdb by the give table and network id and 423 // returns a map of keys and values 424 func (nDB *NetworkDB) GetTableByNetwork(tname, nid string) map[string]*TableElem { 425 entries := make(map[string]*TableElem) 426 nDB.indexes[byTable].Root().WalkPrefix([]byte(fmt.Sprintf("/%s/%s", tname, nid)), func(k []byte, v interface{}) bool { 427 entry := v.(*entry) 428 if entry.deleting { 429 return false 430 } 431 key := string(k) 432 key = key[strings.LastIndex(key, "/")+1:] 433 entries[key] = &TableElem{Value: entry.value, owner: entry.node} 434 return false 435 }) 436 return entries 437 } 438 439 // DeleteEntry deletes a table entry in NetworkDB for given (network, 440 // table, key) tuple and if the NetworkDB is part of the cluster 441 // propagates this event to the cluster. 442 func (nDB *NetworkDB) DeleteEntry(tname, nid, key string) error { 443 nDB.Lock() 444 oldEntry, err := nDB.getEntry(tname, nid, key) 445 if err != nil || oldEntry == nil || oldEntry.deleting { 446 nDB.Unlock() 447 return fmt.Errorf("cannot delete entry %s with network id %s and key %s "+ 448 "does not exist or is already being deleted", tname, nid, key) 449 } 450 451 entry := &entry{ 452 ltime: nDB.tableClock.Increment(), 453 node: nDB.config.NodeID, 454 value: oldEntry.value, 455 deleting: true, 456 reapTime: nDB.config.reapEntryInterval, 457 } 458 459 nDB.createOrUpdateEntry(nid, tname, key, entry) 460 nDB.Unlock() 461 462 if err := nDB.sendTableEvent(TableEventTypeDelete, nid, tname, key, entry); err != nil { 463 return fmt.Errorf("cannot send table delete event: %v", err) 464 } 465 466 return nil 467 } 468 469 func (nDB *NetworkDB) deleteNodeFromNetworks(deletedNode string) { 470 for nid, nodes := range nDB.networkNodes { 471 updatedNodes := make([]string, 0, len(nodes)) 472 for _, node := range nodes { 473 if node == deletedNode { 474 continue 475 } 476 477 updatedNodes = append(updatedNodes, node) 478 } 479 480 nDB.networkNodes[nid] = updatedNodes 481 } 482 483 delete(nDB.networks, deletedNode) 484 } 485 486 // deleteNodeNetworkEntries is called in 2 conditions with 2 different outcomes: 487 // 1) when a notification is coming of a node leaving the network 488 // - Walk all the network entries and mark the leaving node's entries for deletion 489 // These will be garbage collected when the reap timer will expire 490 // 491 // 2) when the local node is leaving the network 492 // - Walk all the network entries: 493 // A) if the entry is owned by the local node 494 // then we will mark it for deletion. This will ensure that if a node did not 495 // yet received the notification that the local node is leaving, will be aware 496 // of the entries to be deleted. 497 // B) if the entry is owned by a remote node, then we can safely delete it. This 498 // ensures that if we join back this network as we receive the CREATE event for 499 // entries owned by remote nodes, we will accept them and we notify the application 500 func (nDB *NetworkDB) deleteNodeNetworkEntries(nid, node string) { 501 // Indicates if the delete is triggered for the local node 502 isNodeLocal := node == nDB.config.NodeID 503 504 nDB.indexes[byNetwork].Root().WalkPrefix([]byte("/"+nid), 505 func(path []byte, v interface{}) bool { 506 oldEntry := v.(*entry) 507 params := strings.Split(string(path[1:]), "/") 508 nid := params[0] 509 tname := params[1] 510 key := params[2] 511 512 // If the entry is owned by a remote node and this node is not leaving the network 513 if oldEntry.node != node && !isNodeLocal { 514 // Don't do anything because the event is triggered for a node that does not own this entry 515 return false 516 } 517 518 // If this entry is already marked for deletion and this node is not leaving the network 519 if oldEntry.deleting && !isNodeLocal { 520 // Don't do anything this entry will be already garbage collected using the old reapTime 521 return false 522 } 523 524 entry := &entry{ 525 ltime: oldEntry.ltime, 526 node: oldEntry.node, 527 value: oldEntry.value, 528 deleting: true, 529 reapTime: nDB.config.reapEntryInterval, 530 } 531 532 // we arrived at this point in 2 cases: 533 // 1) this entry is owned by the node that is leaving the network 534 // 2) the local node is leaving the network 535 if oldEntry.node == node { 536 if isNodeLocal { 537 // TODO fcrisciani: this can be removed if there is no way to leave the network 538 // without doing a delete of all the objects 539 entry.ltime++ 540 } 541 542 if !oldEntry.deleting { 543 nDB.createOrUpdateEntry(nid, tname, key, entry) 544 } 545 } else { 546 // the local node is leaving the network, all the entries of remote nodes can be safely removed 547 nDB.deleteEntry(nid, tname, key) 548 } 549 550 // Notify to the upper layer only entries not already marked for deletion 551 if !oldEntry.deleting { 552 nDB.broadcaster.Write(makeEvent(opDelete, tname, nid, key, entry.value)) 553 } 554 return false 555 }) 556 } 557 558 func (nDB *NetworkDB) deleteNodeTableEntries(node string) { 559 nDB.indexes[byTable].Root().Walk(func(path []byte, v interface{}) bool { 560 oldEntry := v.(*entry) 561 if oldEntry.node != node { 562 return false 563 } 564 565 params := strings.Split(string(path[1:]), "/") 566 tname := params[0] 567 nid := params[1] 568 key := params[2] 569 570 nDB.deleteEntry(nid, tname, key) 571 572 if !oldEntry.deleting { 573 nDB.broadcaster.Write(makeEvent(opDelete, tname, nid, key, oldEntry.value)) 574 } 575 return false 576 }) 577 } 578 579 // WalkTable walks a single table in NetworkDB and invokes the passed 580 // function for each entry in the table passing the network, key, 581 // value. The walk stops if the passed function returns a true. 582 func (nDB *NetworkDB) WalkTable(tname string, fn func(string, string, []byte, bool) bool) error { 583 nDB.RLock() 584 values := make(map[string]interface{}) 585 nDB.indexes[byTable].Root().WalkPrefix([]byte("/"+tname), func(path []byte, v interface{}) bool { 586 values[string(path)] = v 587 return false 588 }) 589 nDB.RUnlock() 590 591 for k, v := range values { 592 params := strings.Split(k[1:], "/") 593 nid := params[1] 594 key := params[2] 595 if fn(nid, key, v.(*entry).value, v.(*entry).deleting) { 596 return nil 597 } 598 } 599 600 return nil 601 } 602 603 // JoinNetwork joins this node to a given network and propagates this 604 // event across the cluster. This triggers this node joining the 605 // sub-cluster of this network and participates in the network-scoped 606 // gossip and bulk sync for this network. 607 func (nDB *NetworkDB) JoinNetwork(nid string) error { 608 ltime := nDB.networkClock.Increment() 609 610 nDB.Lock() 611 nodeNetworks, ok := nDB.networks[nDB.config.NodeID] 612 if !ok { 613 nodeNetworks = make(map[string]*network) 614 nDB.networks[nDB.config.NodeID] = nodeNetworks 615 } 616 n, ok := nodeNetworks[nid] 617 var entries int64 618 if ok { 619 entries = n.entriesNumber.Load() 620 } 621 nodeNetworks[nid] = &network{id: nid, ltime: ltime} 622 nodeNetworks[nid].entriesNumber.Store(entries) 623 nodeNetworks[nid].tableBroadcasts = &memberlist.TransmitLimitedQueue{ 624 NumNodes: func() int { 625 // TODO fcrisciani this can be optimized maybe avoiding the lock? 626 // this call is done each GetBroadcasts call to evaluate the number of 627 // replicas for the message 628 nDB.RLock() 629 defer nDB.RUnlock() 630 return len(nDB.networkNodes[nid]) 631 }, 632 RetransmitMult: 4, 633 } 634 nDB.addNetworkNode(nid, nDB.config.NodeID) 635 networkNodes := nDB.networkNodes[nid] 636 n = nodeNetworks[nid] 637 nDB.Unlock() 638 639 if err := nDB.sendNetworkEvent(nid, NetworkEventTypeJoin, ltime); err != nil { 640 return fmt.Errorf("failed to send leave network event for %s: %v", nid, err) 641 } 642 643 log.G(context.TODO()).Debugf("%v(%v): joined network %s", nDB.config.Hostname, nDB.config.NodeID, nid) 644 if _, err := nDB.bulkSync(networkNodes, true); err != nil { 645 log.G(context.TODO()).Errorf("Error bulk syncing while joining network %s: %v", nid, err) 646 } 647 648 // Mark the network as being synced 649 // note this is a best effort, we are not checking the result of the bulk sync 650 nDB.Lock() 651 n.inSync = true 652 nDB.Unlock() 653 654 return nil 655 } 656 657 // LeaveNetwork leaves this node from a given network and propagates 658 // this event across the cluster. This triggers this node leaving the 659 // sub-cluster of this network and as a result will no longer 660 // participate in the network-scoped gossip and bulk sync for this 661 // network. Also remove all the table entries for this network from 662 // networkdb 663 func (nDB *NetworkDB) LeaveNetwork(nid string) error { 664 ltime := nDB.networkClock.Increment() 665 if err := nDB.sendNetworkEvent(nid, NetworkEventTypeLeave, ltime); err != nil { 666 return fmt.Errorf("failed to send leave network event for %s: %v", nid, err) 667 } 668 669 nDB.Lock() 670 defer nDB.Unlock() 671 672 // Remove myself from the list of the nodes participating to the network 673 nDB.deleteNetworkNode(nid, nDB.config.NodeID) 674 675 // Update all the local entries marking them for deletion and delete all the remote entries 676 nDB.deleteNodeNetworkEntries(nid, nDB.config.NodeID) 677 678 nodeNetworks, ok := nDB.networks[nDB.config.NodeID] 679 if !ok { 680 return fmt.Errorf("could not find self node for network %s while trying to leave", nid) 681 } 682 683 n, ok := nodeNetworks[nid] 684 if !ok { 685 return fmt.Errorf("could not find network %s while trying to leave", nid) 686 } 687 688 log.G(context.TODO()).Debugf("%v(%v): leaving network %s", nDB.config.Hostname, nDB.config.NodeID, nid) 689 n.ltime = ltime 690 n.reapTime = nDB.config.reapNetworkInterval 691 n.leaving = true 692 return nil 693 } 694 695 // addNetworkNode adds the node to the list of nodes which participate 696 // in the passed network only if it is not already present. Caller 697 // should hold the NetworkDB lock while calling this 698 func (nDB *NetworkDB) addNetworkNode(nid string, nodeName string) { 699 nodes := nDB.networkNodes[nid] 700 for _, node := range nodes { 701 if node == nodeName { 702 return 703 } 704 } 705 706 nDB.networkNodes[nid] = append(nDB.networkNodes[nid], nodeName) 707 } 708 709 // Deletes the node from the list of nodes which participate in the 710 // passed network. Caller should hold the NetworkDB lock while calling 711 // this 712 func (nDB *NetworkDB) deleteNetworkNode(nid string, nodeName string) { 713 nodes, ok := nDB.networkNodes[nid] 714 if !ok || len(nodes) == 0 { 715 return 716 } 717 newNodes := make([]string, 0, len(nodes)-1) 718 for _, name := range nodes { 719 if name == nodeName { 720 continue 721 } 722 newNodes = append(newNodes, name) 723 } 724 nDB.networkNodes[nid] = newNodes 725 } 726 727 // findCommonnetworks find the networks that both this node and the 728 // passed node have joined. 729 func (nDB *NetworkDB) findCommonNetworks(nodeName string) []string { 730 nDB.RLock() 731 defer nDB.RUnlock() 732 733 var networks []string 734 for nid := range nDB.networks[nDB.config.NodeID] { 735 if n, ok := nDB.networks[nodeName][nid]; ok { 736 if !n.leaving { 737 networks = append(networks, nid) 738 } 739 } 740 } 741 742 return networks 743 } 744 745 func (nDB *NetworkDB) updateLocalNetworkTime() { 746 nDB.Lock() 747 defer nDB.Unlock() 748 749 ltime := nDB.networkClock.Increment() 750 for _, n := range nDB.networks[nDB.config.NodeID] { 751 n.ltime = ltime 752 } 753 } 754 755 // createOrUpdateEntry this function handles the creation or update of entries into the local 756 // tree store. It is also used to keep in sync the entries number of the network (all tables are aggregated) 757 func (nDB *NetworkDB) createOrUpdateEntry(nid, tname, key string, entry interface{}) (okTable bool, okNetwork bool) { 758 nDB.indexes[byTable], _, okTable = nDB.indexes[byTable].Insert([]byte(fmt.Sprintf("/%s/%s/%s", tname, nid, key)), entry) 759 nDB.indexes[byNetwork], _, okNetwork = nDB.indexes[byNetwork].Insert([]byte(fmt.Sprintf("/%s/%s/%s", nid, tname, key)), entry) 760 if !okNetwork { 761 // Add only if it is an insert not an update 762 n, ok := nDB.networks[nDB.config.NodeID][nid] 763 if ok { 764 n.entriesNumber.Add(1) 765 } 766 } 767 return okTable, okNetwork 768 } 769 770 // deleteEntry this function handles the deletion of entries into the local tree store. 771 // It is also used to keep in sync the entries number of the network (all tables are aggregated) 772 func (nDB *NetworkDB) deleteEntry(nid, tname, key string) (okTable bool, okNetwork bool) { 773 nDB.indexes[byTable], _, okTable = nDB.indexes[byTable].Delete([]byte(fmt.Sprintf("/%s/%s/%s", tname, nid, key))) 774 nDB.indexes[byNetwork], _, okNetwork = nDB.indexes[byNetwork].Delete([]byte(fmt.Sprintf("/%s/%s/%s", nid, tname, key))) 775 if okNetwork { 776 // Remove only if the delete is successful 777 n, ok := nDB.networks[nDB.config.NodeID][nid] 778 if ok { 779 n.entriesNumber.Add(-1) 780 } 781 } 782 return okTable, okNetwork 783 }