github.com/braveheart12/just@v0.8.7/ledger/artifactmanager/jettreeupdater.go (about) 1 /* 2 * Copyright 2019 Insolar Technologies 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package artifactmanager 18 19 import ( 20 "context" 21 "sync" 22 23 "github.com/insolar/insolar" 24 "github.com/insolar/insolar/ledger/storage/nodes" 25 "github.com/pkg/errors" 26 27 "github.com/insolar/insolar/core" 28 "github.com/insolar/insolar/core/message" 29 "github.com/insolar/insolar/core/reply" 30 "github.com/insolar/insolar/instrumentation/inslogger" 31 "github.com/insolar/insolar/instrumentation/instracer" 32 "github.com/insolar/insolar/ledger/storage" 33 "github.com/insolar/insolar/ledger/storage/jet" 34 ) 35 36 type seqEntry struct { 37 ch chan struct{} 38 once sync.Once 39 } 40 41 type seqKey struct { 42 pulse core.PulseNumber 43 jet core.RecordID 44 } 45 46 type fetchResult struct { 47 jet *core.RecordID 48 err error 49 } 50 51 type jetTreeUpdater struct { 52 Nodes nodes.Accessor 53 JetStorage storage.JetStorage 54 MessageBus core.MessageBus 55 JetCoordinator core.JetCoordinator 56 57 seqMutex sync.Mutex 58 sequencer map[seqKey]*seqEntry 59 } 60 61 func newJetTreeUpdater( 62 ans nodes.Accessor, 63 js storage.JetStorage, mb core.MessageBus, jc core.JetCoordinator, 64 ) *jetTreeUpdater { 65 return &jetTreeUpdater{ 66 Nodes: ans, 67 JetStorage: js, 68 MessageBus: mb, 69 JetCoordinator: jc, 70 sequencer: map[seqKey]*seqEntry{}, 71 } 72 } 73 74 func (jtu *jetTreeUpdater) fetchJet( 75 ctx context.Context, target core.RecordID, pulse core.PulseNumber, 76 ) (*core.RecordID, error) { 77 ctx, span := instracer.StartSpan(ctx, "jet_tree_updater.fetch_jet") 78 defer span.End() 79 80 // Look in the local tree. Return if the actual jet found. 81 jetID, actual := jtu.JetStorage.FindJet(ctx, pulse, target) 82 if actual { 83 return jetID, nil 84 } 85 86 // Not actual in our tree, asking neighbors for jet. 87 span.Annotate(nil, "tree in DB is not actual") 88 key := seqKey{pulse, *jetID} 89 90 executing := false 91 92 jtu.seqMutex.Lock() 93 if _, ok := jtu.sequencer[key]; !ok { 94 jtu.sequencer[key] = &seqEntry{ch: make(chan struct{})} 95 executing = true 96 } 97 entry := jtu.sequencer[key] 98 jtu.seqMutex.Unlock() 99 100 span.Annotate(nil, "got sequencer entry") 101 102 if !executing { 103 <-entry.ch 104 105 // Tree was updated in another thread, rechecking. 106 span.Annotate(nil, "somebody else updated actuality") 107 return jtu.fetchJet(ctx, target, pulse) 108 } 109 110 defer func() { 111 entry.once.Do(func() { 112 close(entry.ch) 113 }) 114 115 jtu.seqMutex.Lock() 116 delete(jtu.sequencer, key) 117 jtu.seqMutex.Unlock() 118 }() 119 120 resJet, err := jtu.fetchActualJetFromOtherNodes(ctx, target, pulse) 121 if err != nil { 122 return nil, err 123 } 124 125 jtu.JetStorage.UpdateJetTree(ctx, pulse, true, *resJet) 126 127 return resJet, nil 128 } 129 130 func (jtu *jetTreeUpdater) releaseJet(ctx context.Context, jetID core.RecordID, pulse core.PulseNumber) { 131 jtu.seqMutex.Lock() 132 defer jtu.seqMutex.Unlock() 133 134 depth, _ := jet.Jet(jetID) 135 for { 136 key := seqKey{pulse, jetID} 137 if v, ok := jtu.sequencer[key]; ok { 138 v.once.Do(func() { 139 close(v.ch) 140 }) 141 142 delete(jtu.sequencer, key) 143 } 144 145 if depth == 0 { 146 break 147 } 148 jetID = jet.Parent(jetID) 149 depth-- 150 } 151 } 152 153 func (jtu *jetTreeUpdater) fetchActualJetFromOtherNodes( 154 ctx context.Context, target core.RecordID, pulse core.PulseNumber, 155 ) (*core.RecordID, error) { 156 ctx, span := instracer.StartSpan(ctx, "jet_tree_updater.fetch_jet_from_other_nodes") 157 defer span.End() 158 159 ch := make(chan fetchResult, 1) 160 161 go func() { 162 nodes, err := jtu.otherNodesForPulse(ctx, pulse) 163 if err != nil { 164 ch <- fetchResult{nil, err} 165 return 166 } 167 168 num := len(nodes) 169 170 wg := sync.WaitGroup{} 171 wg.Add(num) 172 173 once := sync.Once{} 174 175 replies := make([]*reply.Jet, num) 176 for i, node := range nodes { 177 go func(i int, node insolar.Node) { 178 ctx, span := instracer.StartSpan(ctx, "jet_tree_updater.one_node_get_jet") 179 defer span.End() 180 181 defer wg.Done() 182 183 nodeID := node.ID 184 rep, err := jtu.MessageBus.Send( 185 ctx, 186 &message.GetJet{Object: target, Pulse: pulse}, 187 &core.MessageSendOptions{Receiver: &nodeID}, 188 ) 189 if err != nil { 190 inslogger.FromContext(ctx).Error( 191 errors.Wrap(err, "couldn't get jet"), 192 ) 193 return 194 } 195 196 r, ok := rep.(*reply.Jet) 197 if !ok { 198 inslogger.FromContext(ctx).Errorf("middleware.fetchActualJetFromOtherNodes: unexpected reply: %#v\n", rep) 199 return 200 } 201 202 if !r.Actual { 203 return 204 } 205 206 once.Do(func() { 207 jetID := r.ID 208 ch <- fetchResult{&jetID, nil} 209 close(ch) 210 }) 211 212 replies[i] = r 213 }(i, node) 214 } 215 wg.Wait() 216 217 seen := make(map[core.RecordID]struct{}) 218 res := make([]*core.RecordID, 0) 219 for _, r := range replies { 220 if r == nil { 221 continue 222 } 223 if _, ok := seen[r.ID]; ok { 224 continue 225 } 226 227 seen[r.ID] = struct{}{} 228 res = append(res, &r.ID) 229 } 230 231 if len(res) == 0 { 232 inslogger.FromContext(ctx).WithFields(map[string]interface{}{ 233 "pulse": pulse, 234 "object": target.DebugString(), 235 }).Error("all lights for pulse have no actual jet for object") 236 ch <- fetchResult{nil, errors.New("impossible situation")} 237 close(ch) 238 } else if len(res) > 1 { 239 inslogger.FromContext(ctx).WithFields(map[string]interface{}{ 240 "pulse": pulse, 241 "object": target.DebugString(), 242 }).Error("lights said different actual jet for object") 243 } 244 }() 245 246 res := <-ch 247 return res.jet, res.err 248 } 249 250 func (jtu *jetTreeUpdater) otherNodesForPulse( 251 ctx context.Context, pulse core.PulseNumber, 252 ) ([]insolar.Node, error) { 253 ctx, span := instracer.StartSpan(ctx, "jet_tree_updater.other_nodes_for_pulse") 254 defer span.End() 255 256 res, err := jtu.Nodes.InRole(pulse, core.StaticRoleLightMaterial) 257 if err != nil { 258 return nil, err 259 } 260 261 me := jtu.JetCoordinator.Me() 262 for i := range res { 263 if res[i].ID == me { 264 res = append(res[:i], res[i+1:]...) 265 break 266 } 267 } 268 269 num := len(res) 270 if num == 0 { 271 inslogger.FromContext(ctx).Error( 272 "This shouldn't happen. We're solo active light material", 273 ) 274 275 return nil, errors.New("impossible situation") 276 } 277 278 return res, nil 279 }