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