go.dedis.ch/onet/v3@v3.2.11-0.20210930124529-e36530bca7ef/treestorage.go (about) 1 package onet 2 3 import ( 4 "sync" 5 "time" 6 ) 7 8 type treeStorage struct { 9 sync.Mutex 10 timeout time.Duration 11 wg sync.WaitGroup 12 trees map[TreeID]*Tree 13 cancellations map[TreeID]chan struct{} 14 closed bool 15 } 16 17 func newTreeStorage(t time.Duration) *treeStorage { 18 return &treeStorage{ 19 timeout: t, 20 trees: make(map[TreeID]*Tree), 21 cancellations: make(map[TreeID]chan struct{}), 22 closed: false, 23 } 24 } 25 26 // Register creates the key for tree so it is known 27 func (ts *treeStorage) Register(id TreeID) { 28 ts.Lock() 29 ts.trees[id] = nil 30 ts.Unlock() 31 } 32 33 // Unregister makes sure the tree is either set or the key is removed 34 func (ts *treeStorage) Unregister(id TreeID) { 35 ts.Lock() 36 defer ts.Unlock() 37 38 if tree := ts.trees[id]; tree == nil { 39 // if another goroutine set the tree inbetween, we keep the tree 40 // but if it is nil, we need to remove the key 41 delete(ts.trees, id) 42 } 43 } 44 45 // IsRegistered returns true when the tree has previously been registered 46 func (ts *treeStorage) IsRegistered(id TreeID) bool { 47 ts.Lock() 48 defer ts.Unlock() 49 50 _, ok := ts.trees[id] 51 return ok 52 } 53 54 // Get returns the tree if it exists or nil 55 func (ts *treeStorage) Get(id TreeID) *Tree { 56 ts.Lock() 57 defer ts.Unlock() 58 59 return ts.trees[id] 60 } 61 62 // getAndRefresh cancels any pending remove and return the 63 // tree if it exists. 64 func (ts *treeStorage) getAndRefresh(id TreeID) *Tree { 65 ts.Lock() 66 defer ts.Unlock() 67 68 ts.cancelDeletion(id) 69 70 return ts.trees[id] 71 } 72 73 // Set sets the given tree and cancel potential removal 74 func (ts *treeStorage) Set(tree *Tree) { 75 ts.Lock() 76 defer ts.Unlock() 77 78 ts.cancelDeletion(tree.ID) 79 80 ts.trees[tree.ID] = tree 81 } 82 83 // Remove starts a timeout to remove the tree from the storage 84 func (ts *treeStorage) Remove(id TreeID) { 85 ts.Lock() 86 defer ts.Unlock() 87 88 if ts.closed { 89 // server is closing so we avoid creating new goroutines 90 return 91 } 92 93 _, ok := ts.cancellations[id] 94 if ok { 95 // already planned to be removed 96 return 97 } 98 99 ts.wg.Add(1) 100 c := make(chan struct{}) 101 ts.cancellations[id] = c 102 103 go func() { 104 defer ts.wg.Done() 105 106 timer := time.NewTimer(ts.timeout) 107 108 select { 109 // other distant node instances of the protocol could ask for the tree even 110 // after we're done locally and then it needs to be kept around for some time 111 case <-timer.C: 112 ts.Lock() 113 delete(ts.trees, id) 114 delete(ts.cancellations, id) 115 ts.Unlock() 116 case <-c: 117 timer.Stop() 118 return 119 } 120 }() 121 } 122 123 // GetRoster looks for the roster in the list of trees or returns nil 124 func (ts *treeStorage) GetRoster(id RosterID) *Roster { 125 ts.Lock() 126 defer ts.Unlock() 127 128 for _, tree := range ts.trees { 129 if tree.Roster.ID.Equal(id) { 130 return tree.Roster 131 } 132 } 133 134 return nil 135 } 136 137 // Close forces cleaning goroutines to be shutdown 138 func (ts *treeStorage) Close() { 139 ts.Lock() 140 defer ts.Unlock() 141 142 // prevent further call to remove because the server is closing anyway 143 ts.closed = true 144 145 for k, c := range ts.cancellations { 146 close(c) 147 delete(ts.cancellations, k) 148 } 149 150 ts.wg.Wait() 151 } 152 153 // cancelDeletion prevents any pending remove request 154 // to be triggered for the tree. 155 // Caution: caller is reponsible for holding the lock. 156 func (ts *treeStorage) cancelDeletion(id TreeID) { 157 c := ts.cancellations[id] 158 if c != nil { 159 close(c) 160 delete(ts.cancellations, id) 161 } 162 }