github.com/core-coin/go-core/v2@v2.1.9/p2p/nodestate/nodestate.go (about) 1 // Copyright 2020 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-core library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package nodestate 18 19 import ( 20 "errors" 21 "reflect" 22 "sync" 23 "time" 24 "unsafe" 25 26 "github.com/core-coin/go-core/v2/xcbdb" 27 28 "github.com/core-coin/go-core/v2/common/mclock" 29 "github.com/core-coin/go-core/v2/log" 30 "github.com/core-coin/go-core/v2/metrics" 31 "github.com/core-coin/go-core/v2/p2p/enode" 32 "github.com/core-coin/go-core/v2/p2p/enr" 33 "github.com/core-coin/go-core/v2/rlp" 34 ) 35 36 var ( 37 ErrInvalidField = errors.New("invalid field type") 38 ErrClosed = errors.New("already closed") 39 ) 40 41 type ( 42 // NodeStateMachine implements a network node-related event subscription system. 43 // It can assign binary state flags and fields of arbitrary type to each node and allows 44 // subscriptions to flag/field changes which can also modify further flags and fields, 45 // potentially triggering further subscriptions. An operation includes an initial change 46 // and all resulting subsequent changes and always ends in a consistent global state. 47 // It is initiated by a "top level" SetState/SetField call that blocks (also blocking other 48 // top-level functions) until the operation is finished. Callbacks making further changes 49 // should use the non-blocking SetStateSub/SetFieldSub functions. The tree of events 50 // resulting from the initial changes is traversed in a breadth-first order, ensuring for 51 // each subscription callback that all other callbacks caused by the same change triggering 52 // the current callback are processed before anything is triggered by the changes made in the 53 // current callback. In practice this logic ensures that all subscriptions "see" events in 54 // the logical order, callbacks are never called concurrently and "back and forth" effects 55 // are also possible. The state machine design should ensure that infinite event cycles 56 // cannot happen. 57 // The caller can also add timeouts assigned to a certain node and a subset of state flags. 58 // If the timeout elapses, the flags are reset. If all relevant flags are reset then the timer 59 // is dropped. State flags with no timeout are persisted in the database if the flag 60 // descriptor enables saving. If a node has no state flags set at any moment then it is discarded. 61 // Note: in order to avoid mutex deadlocks the callbacks should never lock a mutex that 62 // might be locked when the top level SetState/SetField functions are called. If a function 63 // potentially performs state/field changes then it is recommended to mention this fact in the 64 // function description, along with whether it should run inside an operation callback. 65 NodeStateMachine struct { 66 started, closed bool 67 lock sync.Mutex 68 clock mclock.Clock 69 db xcbdb.KeyValueStore 70 dbNodeKey []byte 71 nodes map[enode.ID]*nodeInfo 72 offlineCallbackList []offlineCallback 73 opFlag bool // an operation has started 74 opWait *sync.Cond // signaled when the operation ends 75 opPending []func() // pending callback list of the current operation 76 77 // Registered state flags or fields. Modifications are allowed 78 // only when the node state machine has not been started. 79 setup *Setup 80 fields []*fieldInfo 81 saveFlags bitMask 82 83 // Installed callbacks. Modifications are allowed only when the 84 // node state machine has not been started. 85 stateSubs []stateSub 86 87 // Testing hooks, only for testing purposes. 88 saveNodeHook func(*nodeInfo) 89 } 90 91 // Flags represents a set of flags from a certain setup 92 Flags struct { 93 mask bitMask 94 setup *Setup 95 } 96 97 // Field represents a field from a certain setup 98 Field struct { 99 index int 100 setup *Setup 101 } 102 103 // flagDefinition describes a node state flag. Each registered instance is automatically 104 // mapped to a bit of the 64 bit node states. 105 // If persistent is true then the node is saved when state machine is shutdown. 106 flagDefinition struct { 107 name string 108 persistent bool 109 } 110 111 // fieldDefinition describes an optional node field of the given type. The contents 112 // of the field are only retained for each node as long as at least one of the 113 // state flags is set. 114 fieldDefinition struct { 115 name string 116 ftype reflect.Type 117 encode func(interface{}) ([]byte, error) 118 decode func([]byte) (interface{}, error) 119 } 120 121 // stateSetup contains the list of flags and fields used by the application 122 Setup struct { 123 Version uint 124 flags []flagDefinition 125 fields []fieldDefinition 126 } 127 128 // bitMask describes a node state or state mask. It represents a subset 129 // of node flags with each bit assigned to a flag index (LSB represents flag 0). 130 bitMask uint64 131 132 // StateCallback is a subscription callback which is called when one of the 133 // state flags that is included in the subscription state mask is changed. 134 // Note: oldState and newState are also masked with the subscription mask so only 135 // the relevant bits are included. 136 StateCallback func(n *enode.Node, oldState, newState Flags) 137 138 // FieldCallback is a subscription callback which is called when the value of 139 // a specific field is changed. 140 FieldCallback func(n *enode.Node, state Flags, oldValue, newValue interface{}) 141 142 // nodeInfo contains node state, fields and state timeouts 143 nodeInfo struct { 144 node *enode.Node 145 state bitMask 146 timeouts []*nodeStateTimeout 147 fields []interface{} 148 fieldCount int 149 db, dirty bool 150 } 151 152 nodeInfoEnc struct { 153 Enr enr.Record 154 Version uint 155 State bitMask 156 Fields [][]byte 157 } 158 159 stateSub struct { 160 mask bitMask 161 callback StateCallback 162 } 163 164 nodeStateTimeout struct { 165 mask bitMask 166 timer mclock.Timer 167 } 168 169 fieldInfo struct { 170 fieldDefinition 171 subs []FieldCallback 172 } 173 174 offlineCallback struct { 175 node *nodeInfo 176 state bitMask 177 fields []interface{} 178 } 179 ) 180 181 // offlineState is a special state that is assumed to be set before a node is loaded from 182 // the database and after it is shut down. 183 const offlineState = bitMask(1) 184 185 // NewFlag creates a new node state flag 186 func (s *Setup) NewFlag(name string) Flags { 187 if s.flags == nil { 188 s.flags = []flagDefinition{{name: "offline"}} 189 } 190 f := Flags{mask: bitMask(1) << uint(len(s.flags)), setup: s} 191 s.flags = append(s.flags, flagDefinition{name: name}) 192 return f 193 } 194 195 // NewPersistentFlag creates a new persistent node state flag 196 func (s *Setup) NewPersistentFlag(name string) Flags { 197 if s.flags == nil { 198 s.flags = []flagDefinition{{name: "offline"}} 199 } 200 f := Flags{mask: bitMask(1) << uint(len(s.flags)), setup: s} 201 s.flags = append(s.flags, flagDefinition{name: name, persistent: true}) 202 return f 203 } 204 205 // OfflineFlag returns the system-defined offline flag belonging to the given setup 206 func (s *Setup) OfflineFlag() Flags { 207 return Flags{mask: offlineState, setup: s} 208 } 209 210 // NewField creates a new node state field 211 func (s *Setup) NewField(name string, ftype reflect.Type) Field { 212 f := Field{index: len(s.fields), setup: s} 213 s.fields = append(s.fields, fieldDefinition{ 214 name: name, 215 ftype: ftype, 216 }) 217 return f 218 } 219 220 // NewPersistentField creates a new persistent node field 221 func (s *Setup) NewPersistentField(name string, ftype reflect.Type, encode func(interface{}) ([]byte, error), decode func([]byte) (interface{}, error)) Field { 222 f := Field{index: len(s.fields), setup: s} 223 s.fields = append(s.fields, fieldDefinition{ 224 name: name, 225 ftype: ftype, 226 encode: encode, 227 decode: decode, 228 }) 229 return f 230 } 231 232 // flagOp implements binary flag operations and also checks whether the operands belong to the same setup 233 func flagOp(a, b Flags, trueIfA, trueIfB, trueIfBoth bool) Flags { 234 if a.setup == nil { 235 if a.mask != 0 { 236 panic("Node state flags have no setup reference") 237 } 238 a.setup = b.setup 239 } 240 if b.setup == nil { 241 if b.mask != 0 { 242 panic("Node state flags have no setup reference") 243 } 244 b.setup = a.setup 245 } 246 if a.setup != b.setup { 247 panic("Node state flags belong to a different setup") 248 } 249 res := Flags{setup: a.setup} 250 if trueIfA { 251 res.mask |= a.mask & ^b.mask 252 } 253 if trueIfB { 254 res.mask |= b.mask & ^a.mask 255 } 256 if trueIfBoth { 257 res.mask |= a.mask & b.mask 258 } 259 return res 260 } 261 262 // And returns the set of flags present in both a and b 263 func (a Flags) And(b Flags) Flags { return flagOp(a, b, false, false, true) } 264 265 // AndNot returns the set of flags present in a but not in b 266 func (a Flags) AndNot(b Flags) Flags { return flagOp(a, b, true, false, false) } 267 268 // Or returns the set of flags present in either a or b 269 func (a Flags) Or(b Flags) Flags { return flagOp(a, b, true, true, true) } 270 271 // Xor returns the set of flags present in either a or b but not both 272 func (a Flags) Xor(b Flags) Flags { return flagOp(a, b, true, true, false) } 273 274 // HasAll returns true if b is a subset of a 275 func (a Flags) HasAll(b Flags) bool { return flagOp(a, b, false, true, false).mask == 0 } 276 277 // HasNone returns true if a and b have no shared flags 278 func (a Flags) HasNone(b Flags) bool { return flagOp(a, b, false, false, true).mask == 0 } 279 280 // Equals returns true if a and b have the same flags set 281 func (a Flags) Equals(b Flags) bool { return flagOp(a, b, true, true, false).mask == 0 } 282 283 // IsEmpty returns true if a has no flags set 284 func (a Flags) IsEmpty() bool { return a.mask == 0 } 285 286 // MergeFlags merges multiple sets of state flags 287 func MergeFlags(list ...Flags) Flags { 288 if len(list) == 0 { 289 return Flags{} 290 } 291 res := list[0] 292 for i := 1; i < len(list); i++ { 293 res = res.Or(list[i]) 294 } 295 return res 296 } 297 298 // String returns a list of the names of the flags specified in the bit mask 299 func (f Flags) String() string { 300 if f.mask == 0 { 301 return "[]" 302 } 303 s := "[" 304 comma := false 305 for index, flag := range f.setup.flags { 306 if f.mask&(bitMask(1)<<uint(index)) != 0 { 307 if comma { 308 s = s + ", " 309 } 310 s = s + flag.name 311 comma = true 312 } 313 } 314 s = s + "]" 315 return s 316 } 317 318 // NewNodeStateMachine creates a new node state machine. 319 // If db is not nil then the node states, fields and active timeouts are persisted. 320 // Persistence can be enabled or disabled for each state flag and field. 321 func NewNodeStateMachine(db xcbdb.KeyValueStore, dbKey []byte, clock mclock.Clock, setup *Setup) *NodeStateMachine { 322 if setup.flags == nil { 323 panic("No state flags defined") 324 } 325 if len(setup.flags) > 8*int(unsafe.Sizeof(bitMask(0))) { 326 panic("Too many node state flags") 327 } 328 ns := &NodeStateMachine{ 329 db: db, 330 dbNodeKey: dbKey, 331 clock: clock, 332 setup: setup, 333 nodes: make(map[enode.ID]*nodeInfo), 334 fields: make([]*fieldInfo, len(setup.fields)), 335 } 336 ns.opWait = sync.NewCond(&ns.lock) 337 stateNameMap := make(map[string]int) 338 for index, flag := range setup.flags { 339 if _, ok := stateNameMap[flag.name]; ok { 340 panic("Node state flag name collision: " + flag.name) 341 } 342 stateNameMap[flag.name] = index 343 if flag.persistent { 344 ns.saveFlags |= bitMask(1) << uint(index) 345 } 346 } 347 fieldNameMap := make(map[string]int) 348 for index, field := range setup.fields { 349 if _, ok := fieldNameMap[field.name]; ok { 350 panic("Node field name collision: " + field.name) 351 } 352 ns.fields[index] = &fieldInfo{fieldDefinition: field} 353 fieldNameMap[field.name] = index 354 } 355 return ns 356 } 357 358 // stateMask checks whether the set of flags belongs to the same setup and returns its internal bit mask 359 func (ns *NodeStateMachine) stateMask(flags Flags) bitMask { 360 if flags.setup != ns.setup && flags.mask != 0 { 361 panic("Node state flags belong to a different setup") 362 } 363 return flags.mask 364 } 365 366 // fieldIndex checks whether the field belongs to the same setup and returns its internal index 367 func (ns *NodeStateMachine) fieldIndex(field Field) int { 368 if field.setup != ns.setup { 369 panic("Node field belongs to a different setup") 370 } 371 return field.index 372 } 373 374 // SubscribeState adds a node state subscription. The callback is called while the state 375 // machine mutex is not held and it is allowed to make further state updates using the 376 // non-blocking SetStateSub/SetFieldSub functions. All callbacks of an operation are running 377 // from the thread/goroutine of the initial caller and parallel operations are not permitted. 378 // Therefore the callback is never called concurrently. It is the responsibility of the 379 // implemented state logic to avoid deadlocks and to reach a stable state in a finite amount 380 // of steps. 381 // State subscriptions should be installed before loading the node database or making the 382 // first state update. 383 func (ns *NodeStateMachine) SubscribeState(flags Flags, callback StateCallback) { 384 ns.lock.Lock() 385 defer ns.lock.Unlock() 386 387 if ns.started { 388 panic("state machine already started") 389 } 390 ns.stateSubs = append(ns.stateSubs, stateSub{ns.stateMask(flags), callback}) 391 } 392 393 // SubscribeField adds a node field subscription. Same rules apply as for SubscribeState. 394 func (ns *NodeStateMachine) SubscribeField(field Field, callback FieldCallback) { 395 ns.lock.Lock() 396 defer ns.lock.Unlock() 397 398 if ns.started { 399 panic("state machine already started") 400 } 401 f := ns.fields[ns.fieldIndex(field)] 402 f.subs = append(f.subs, callback) 403 } 404 405 // newNode creates a new nodeInfo 406 func (ns *NodeStateMachine) newNode(n *enode.Node) *nodeInfo { 407 return &nodeInfo{node: n, fields: make([]interface{}, len(ns.fields))} 408 } 409 410 // checkStarted checks whether the state machine has already been started and panics otherwise. 411 func (ns *NodeStateMachine) checkStarted() { 412 if !ns.started { 413 panic("state machine not started yet") 414 } 415 } 416 417 // Start starts the state machine, enabling state and field operations and disabling 418 // further subscriptions. 419 func (ns *NodeStateMachine) Start() { 420 ns.lock.Lock() 421 if ns.started { 422 panic("state machine already started") 423 } 424 ns.started = true 425 if ns.db != nil { 426 ns.loadFromDb() 427 } 428 429 ns.opStart() 430 ns.offlineCallbacks(true) 431 ns.opFinish() 432 ns.lock.Unlock() 433 } 434 435 // Stop stops the state machine and saves its state if a database was supplied 436 func (ns *NodeStateMachine) Stop() { 437 ns.lock.Lock() 438 defer ns.lock.Unlock() 439 440 ns.checkStarted() 441 if !ns.opStart() { 442 panic("already closed") 443 } 444 for _, node := range ns.nodes { 445 fields := make([]interface{}, len(node.fields)) 446 copy(fields, node.fields) 447 ns.offlineCallbackList = append(ns.offlineCallbackList, offlineCallback{node, node.state, fields}) 448 } 449 if ns.db != nil { 450 ns.saveToDb() 451 } 452 ns.offlineCallbacks(false) 453 ns.closed = true 454 ns.opFinish() 455 } 456 457 // loadFromDb loads persisted node states from the database 458 func (ns *NodeStateMachine) loadFromDb() { 459 it := ns.db.NewIterator(ns.dbNodeKey, nil) 460 for it.Next() { 461 var id enode.ID 462 if len(it.Key()) != len(ns.dbNodeKey)+len(id) { 463 log.Error("Node state db entry with invalid length", "found", len(it.Key()), "expected", len(ns.dbNodeKey)+len(id)) 464 continue 465 } 466 copy(id[:], it.Key()[len(ns.dbNodeKey):]) 467 ns.decodeNode(id, it.Value()) 468 } 469 } 470 471 type dummyIdentity enode.ID 472 473 func (id dummyIdentity) Verify(r *enr.Record, sig []byte) error { return nil } 474 func (id dummyIdentity) NodeAddr(r *enr.Record) []byte { return id[:] } 475 476 // decodeNode decodes a node database entry and adds it to the node set if successful 477 func (ns *NodeStateMachine) decodeNode(id enode.ID, data []byte) { 478 var enc nodeInfoEnc 479 if err := rlp.DecodeBytes(data, &enc); err != nil { 480 log.Error("Failed to decode node info", "id", id, "error", err) 481 return 482 } 483 n, _ := enode.New(dummyIdentity(id), &enc.Enr) 484 node := ns.newNode(n) 485 node.db = true 486 487 if enc.Version != ns.setup.Version { 488 log.Debug("Removing stored node with unknown version", "current", ns.setup.Version, "stored", enc.Version) 489 ns.deleteNode(id) 490 return 491 } 492 if len(enc.Fields) > len(ns.setup.fields) { 493 log.Error("Invalid node field count", "id", id, "stored", len(enc.Fields)) 494 return 495 } 496 // Resolve persisted node fields 497 for i, encField := range enc.Fields { 498 if len(encField) == 0 { 499 continue 500 } 501 if decode := ns.fields[i].decode; decode != nil { 502 if field, err := decode(encField); err == nil { 503 node.fields[i] = field 504 node.fieldCount++ 505 } else { 506 log.Error("Failed to decode node field", "id", id, "field name", ns.fields[i].name, "error", err) 507 return 508 } 509 } else { 510 log.Error("Cannot decode node field", "id", id, "field name", ns.fields[i].name) 511 return 512 } 513 } 514 // It's a compatible node record, add it to set. 515 ns.nodes[id] = node 516 node.state = enc.State 517 fields := make([]interface{}, len(node.fields)) 518 copy(fields, node.fields) 519 ns.offlineCallbackList = append(ns.offlineCallbackList, offlineCallback{node, node.state, fields}) 520 log.Debug("Loaded node state", "id", id, "state", Flags{mask: enc.State, setup: ns.setup}) 521 } 522 523 // saveNode saves the given node info to the database 524 func (ns *NodeStateMachine) saveNode(id enode.ID, node *nodeInfo) error { 525 if ns.db == nil { 526 return nil 527 } 528 529 storedState := node.state & ns.saveFlags 530 for _, t := range node.timeouts { 531 storedState &= ^t.mask 532 } 533 enc := nodeInfoEnc{ 534 Enr: *node.node.Record(), 535 Version: ns.setup.Version, 536 State: storedState, 537 Fields: make([][]byte, len(ns.fields)), 538 } 539 log.Debug("Saved node state", "id", id, "state", Flags{mask: enc.State, setup: ns.setup}) 540 lastIndex := -1 541 for i, f := range node.fields { 542 if f == nil { 543 continue 544 } 545 encode := ns.fields[i].encode 546 if encode == nil { 547 continue 548 } 549 blob, err := encode(f) 550 if err != nil { 551 return err 552 } 553 enc.Fields[i] = blob 554 lastIndex = i 555 } 556 if storedState == 0 && lastIndex == -1 { 557 if node.db { 558 node.db = false 559 ns.deleteNode(id) 560 } 561 node.dirty = false 562 return nil 563 } 564 enc.Fields = enc.Fields[:lastIndex+1] 565 data, err := rlp.EncodeToBytes(&enc) 566 if err != nil { 567 return err 568 } 569 if err := ns.db.Put(append(ns.dbNodeKey, id[:]...), data); err != nil { 570 return err 571 } 572 node.dirty, node.db = false, true 573 574 if ns.saveNodeHook != nil { 575 ns.saveNodeHook(node) 576 } 577 return nil 578 } 579 580 // deleteNode removes a node info from the database 581 func (ns *NodeStateMachine) deleteNode(id enode.ID) { 582 ns.db.Delete(append(ns.dbNodeKey, id[:]...)) 583 } 584 585 // saveToDb saves the persistent flags and fields of all nodes that have been changed 586 func (ns *NodeStateMachine) saveToDb() { 587 for id, node := range ns.nodes { 588 if node.dirty { 589 err := ns.saveNode(id, node) 590 if err != nil { 591 log.Error("Failed to save node", "id", id, "error", err) 592 } 593 } 594 } 595 } 596 597 // updateEnode updates the enode entry belonging to the given node if it already exists 598 func (ns *NodeStateMachine) updateEnode(n *enode.Node) (enode.ID, *nodeInfo) { 599 id := n.ID() 600 node := ns.nodes[id] 601 if node != nil && n.Seq() > node.node.Seq() { 602 node.node = n 603 } 604 return id, node 605 } 606 607 // Persist saves the persistent state and fields of the given node immediately 608 func (ns *NodeStateMachine) Persist(n *enode.Node) error { 609 ns.lock.Lock() 610 defer ns.lock.Unlock() 611 612 ns.checkStarted() 613 if id, node := ns.updateEnode(n); node != nil && node.dirty { 614 err := ns.saveNode(id, node) 615 if err != nil { 616 log.Error("Failed to save node", "id", id, "error", err) 617 } 618 return err 619 } 620 return nil 621 } 622 623 // SetState updates the given node state flags and blocks until the operation is finished. 624 // If a flag with a timeout is set again, the operation removes or replaces the existing timeout. 625 func (ns *NodeStateMachine) SetState(n *enode.Node, setFlags, resetFlags Flags, timeout time.Duration) error { 626 ns.lock.Lock() 627 defer ns.lock.Unlock() 628 629 if !ns.opStart() { 630 return ErrClosed 631 } 632 ns.setState(n, setFlags, resetFlags, timeout) 633 ns.opFinish() 634 return nil 635 } 636 637 // SetStateSub updates the given node state flags without blocking (should be called 638 // from a subscription/operation callback). 639 func (ns *NodeStateMachine) SetStateSub(n *enode.Node, setFlags, resetFlags Flags, timeout time.Duration) { 640 ns.lock.Lock() 641 defer ns.lock.Unlock() 642 643 ns.opCheck() 644 ns.setState(n, setFlags, resetFlags, timeout) 645 } 646 647 func (ns *NodeStateMachine) setState(n *enode.Node, setFlags, resetFlags Flags, timeout time.Duration) { 648 ns.checkStarted() 649 set, reset := ns.stateMask(setFlags), ns.stateMask(resetFlags) 650 id, node := ns.updateEnode(n) 651 if node == nil { 652 if set == 0 { 653 return 654 } 655 node = ns.newNode(n) 656 ns.nodes[id] = node 657 } 658 oldState := node.state 659 newState := (node.state & (^reset)) | set 660 changed := oldState ^ newState 661 node.state = newState 662 663 // Remove the timeout callbacks for all reset and set flags, 664 // even they are not existent(it's noop). 665 ns.removeTimeouts(node, set|reset) 666 667 // Register the timeout callback if required 668 if timeout != 0 && set != 0 { 669 ns.addTimeout(n, set, timeout) 670 } 671 if newState == oldState { 672 return 673 } 674 if newState == 0 && node.fieldCount == 0 { 675 delete(ns.nodes, id) 676 if node.db { 677 ns.deleteNode(id) 678 } 679 } else { 680 if changed&ns.saveFlags != 0 { 681 node.dirty = true 682 } 683 } 684 callback := func() { 685 for _, sub := range ns.stateSubs { 686 if changed&sub.mask != 0 { 687 sub.callback(n, Flags{mask: oldState & sub.mask, setup: ns.setup}, Flags{mask: newState & sub.mask, setup: ns.setup}) 688 } 689 } 690 } 691 ns.opPending = append(ns.opPending, callback) 692 } 693 694 // opCheck checks whether an operation is active 695 func (ns *NodeStateMachine) opCheck() { 696 if !ns.opFlag { 697 panic("Operation has not started") 698 } 699 } 700 701 // opStart waits until other operations are finished and starts a new one 702 func (ns *NodeStateMachine) opStart() bool { 703 for ns.opFlag { 704 ns.opWait.Wait() 705 } 706 if ns.closed { 707 return false 708 } 709 ns.opFlag = true 710 return true 711 } 712 713 // opFinish finishes the current operation by running all pending callbacks. 714 // Callbacks resulting from a state/field change performed in a previous callback are always 715 // put at the end of the pending list and therefore processed after all callbacks resulting 716 // from the previous state/field change. 717 func (ns *NodeStateMachine) opFinish() { 718 for len(ns.opPending) != 0 { 719 list := ns.opPending 720 ns.lock.Unlock() 721 for _, cb := range list { 722 cb() 723 } 724 ns.lock.Lock() 725 ns.opPending = ns.opPending[len(list):] 726 } 727 ns.opPending = nil 728 ns.opFlag = false 729 ns.opWait.Broadcast() 730 } 731 732 // Operation calls the given function as an operation callback. This allows the caller 733 // to start an operation with multiple initial changes. The same rules apply as for 734 // subscription callbacks. 735 func (ns *NodeStateMachine) Operation(fn func()) error { 736 ns.lock.Lock() 737 started := ns.opStart() 738 ns.lock.Unlock() 739 if !started { 740 return ErrClosed 741 } 742 fn() 743 ns.lock.Lock() 744 ns.opFinish() 745 ns.lock.Unlock() 746 return nil 747 } 748 749 // offlineCallbacks calls state update callbacks at startup or shutdown 750 func (ns *NodeStateMachine) offlineCallbacks(start bool) { 751 for _, cb := range ns.offlineCallbackList { 752 cb := cb 753 callback := func() { 754 for _, sub := range ns.stateSubs { 755 offState := offlineState & sub.mask 756 onState := cb.state & sub.mask 757 if offState == onState { 758 continue 759 } 760 if start { 761 sub.callback(cb.node.node, Flags{mask: offState, setup: ns.setup}, Flags{mask: onState, setup: ns.setup}) 762 } else { 763 sub.callback(cb.node.node, Flags{mask: onState, setup: ns.setup}, Flags{mask: offState, setup: ns.setup}) 764 } 765 } 766 for i, f := range cb.fields { 767 if f == nil || ns.fields[i].subs == nil { 768 continue 769 } 770 for _, fsub := range ns.fields[i].subs { 771 if start { 772 fsub(cb.node.node, Flags{mask: offlineState, setup: ns.setup}, nil, f) 773 } else { 774 fsub(cb.node.node, Flags{mask: offlineState, setup: ns.setup}, f, nil) 775 } 776 } 777 } 778 } 779 ns.opPending = append(ns.opPending, callback) 780 } 781 ns.offlineCallbackList = nil 782 } 783 784 // AddTimeout adds a node state timeout associated to the given state flag(s). 785 // After the specified time interval, the relevant states will be reset. 786 func (ns *NodeStateMachine) AddTimeout(n *enode.Node, flags Flags, timeout time.Duration) error { 787 ns.lock.Lock() 788 defer ns.lock.Unlock() 789 790 ns.checkStarted() 791 if ns.closed { 792 return ErrClosed 793 } 794 ns.addTimeout(n, ns.stateMask(flags), timeout) 795 return nil 796 } 797 798 // addTimeout adds a node state timeout associated to the given state flag(s). 799 func (ns *NodeStateMachine) addTimeout(n *enode.Node, mask bitMask, timeout time.Duration) { 800 _, node := ns.updateEnode(n) 801 if node == nil { 802 return 803 } 804 mask &= node.state 805 if mask == 0 { 806 return 807 } 808 ns.removeTimeouts(node, mask) 809 t := &nodeStateTimeout{mask: mask} 810 t.timer = ns.clock.AfterFunc(timeout, func() { 811 ns.SetState(n, Flags{}, Flags{mask: t.mask, setup: ns.setup}, 0) 812 }) 813 node.timeouts = append(node.timeouts, t) 814 if mask&ns.saveFlags != 0 { 815 node.dirty = true 816 } 817 } 818 819 // removeTimeout removes node state timeouts associated to the given state flag(s). 820 // If a timeout was associated to multiple flags which are not all included in the 821 // specified remove mask then only the included flags are de-associated and the timer 822 // stays active. 823 func (ns *NodeStateMachine) removeTimeouts(node *nodeInfo, mask bitMask) { 824 for i := 0; i < len(node.timeouts); i++ { 825 t := node.timeouts[i] 826 match := t.mask & mask 827 if match == 0 { 828 continue 829 } 830 t.mask -= match 831 if t.mask != 0 { 832 continue 833 } 834 t.timer.Stop() 835 node.timeouts[i] = node.timeouts[len(node.timeouts)-1] 836 node.timeouts = node.timeouts[:len(node.timeouts)-1] 837 i-- 838 if match&ns.saveFlags != 0 { 839 node.dirty = true 840 } 841 } 842 } 843 844 // GetField retrieves the given field of the given node. Note that when used in a 845 // subscription callback the result can be out of sync with the state change represented 846 // by the callback parameters so extra safety checks might be necessary. 847 func (ns *NodeStateMachine) GetField(n *enode.Node, field Field) interface{} { 848 ns.lock.Lock() 849 defer ns.lock.Unlock() 850 851 ns.checkStarted() 852 if ns.closed { 853 return nil 854 } 855 if _, node := ns.updateEnode(n); node != nil { 856 return node.fields[ns.fieldIndex(field)] 857 } 858 return nil 859 } 860 861 // SetField sets the given field of the given node and blocks until the operation is finished 862 func (ns *NodeStateMachine) SetField(n *enode.Node, field Field, value interface{}) error { 863 ns.lock.Lock() 864 defer ns.lock.Unlock() 865 866 if !ns.opStart() { 867 return ErrClosed 868 } 869 err := ns.setField(n, field, value) 870 ns.opFinish() 871 return err 872 } 873 874 // SetFieldSub sets the given field of the given node without blocking (should be called 875 // from a subscription/operation callback). 876 func (ns *NodeStateMachine) SetFieldSub(n *enode.Node, field Field, value interface{}) error { 877 ns.lock.Lock() 878 defer ns.lock.Unlock() 879 880 ns.opCheck() 881 return ns.setField(n, field, value) 882 } 883 884 func (ns *NodeStateMachine) setField(n *enode.Node, field Field, value interface{}) error { 885 ns.checkStarted() 886 id, node := ns.updateEnode(n) 887 if node == nil { 888 if value == nil { 889 return nil 890 } 891 node = ns.newNode(n) 892 ns.nodes[id] = node 893 } 894 fieldIndex := ns.fieldIndex(field) 895 f := ns.fields[fieldIndex] 896 if value != nil && reflect.TypeOf(value) != f.ftype { 897 log.Error("Invalid field type", "type", reflect.TypeOf(value), "required", f.ftype) 898 return ErrInvalidField 899 } 900 oldValue := node.fields[fieldIndex] 901 if value == oldValue { 902 return nil 903 } 904 if oldValue != nil { 905 node.fieldCount-- 906 } 907 if value != nil { 908 node.fieldCount++ 909 } 910 node.fields[fieldIndex] = value 911 if node.state == 0 && node.fieldCount == 0 { 912 delete(ns.nodes, id) 913 if node.db { 914 ns.deleteNode(id) 915 } 916 } else { 917 if f.encode != nil { 918 node.dirty = true 919 } 920 } 921 state := node.state 922 callback := func() { 923 for _, cb := range f.subs { 924 cb(n, Flags{mask: state, setup: ns.setup}, oldValue, value) 925 } 926 } 927 ns.opPending = append(ns.opPending, callback) 928 return nil 929 } 930 931 // ForEach calls the callback for each node having all of the required and none of the 932 // disabled flags set. 933 // Note that this callback is not an operation callback but ForEach can be called from an 934 // Operation callback or Operation can also be called from a ForEach callback if necessary. 935 func (ns *NodeStateMachine) ForEach(requireFlags, disableFlags Flags, cb func(n *enode.Node, state Flags)) { 936 ns.lock.Lock() 937 ns.checkStarted() 938 type callback struct { 939 node *enode.Node 940 state bitMask 941 } 942 require, disable := ns.stateMask(requireFlags), ns.stateMask(disableFlags) 943 var callbacks []callback 944 for _, node := range ns.nodes { 945 if node.state&require == require && node.state&disable == 0 { 946 callbacks = append(callbacks, callback{node.node, node.state & (require | disable)}) 947 } 948 } 949 ns.lock.Unlock() 950 for _, c := range callbacks { 951 cb(c.node, Flags{mask: c.state, setup: ns.setup}) 952 } 953 } 954 955 // GetNode returns the enode currently associated with the given ID 956 func (ns *NodeStateMachine) GetNode(id enode.ID) *enode.Node { 957 ns.lock.Lock() 958 defer ns.lock.Unlock() 959 960 ns.checkStarted() 961 if node := ns.nodes[id]; node != nil { 962 return node.node 963 } 964 return nil 965 } 966 967 // AddLogMetrics adds logging and/or metrics for nodes entering, exiting and currently 968 // being in a given set specified by required and disabled state flags 969 func (ns *NodeStateMachine) AddLogMetrics(requireFlags, disableFlags Flags, name string, inMeter, outMeter metrics.Meter, gauge metrics.Gauge) { 970 var count int64 971 ns.SubscribeState(requireFlags.Or(disableFlags), func(n *enode.Node, oldState, newState Flags) { 972 oldMatch := oldState.HasAll(requireFlags) && oldState.HasNone(disableFlags) 973 newMatch := newState.HasAll(requireFlags) && newState.HasNone(disableFlags) 974 if newMatch == oldMatch { 975 return 976 } 977 978 if newMatch { 979 count++ 980 if name != "" { 981 log.Debug("Node entered", "set", name, "id", n.ID(), "count", count) 982 } 983 if inMeter != nil { 984 inMeter.Mark(1) 985 } 986 } else { 987 count-- 988 if name != "" { 989 log.Debug("Node left", "set", name, "id", n.ID(), "count", count) 990 } 991 if outMeter != nil { 992 outMeter.Mark(1) 993 } 994 } 995 if gauge != nil { 996 gauge.Update(count) 997 } 998 }) 999 }