github.com/braveheart12/just@v0.8.7/ledger/storage/jetstorage.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 storage 18 19 import ( 20 "bytes" 21 "context" 22 "sync" 23 24 "github.com/ugorji/go/codec" 25 26 "github.com/insolar/insolar/core" 27 "github.com/insolar/insolar/ledger/storage/jet" 28 ) 29 30 // JetStorage provides methods for working with jets 31 //go:generate minimock -i github.com/insolar/insolar/ledger/storage.JetStorage -o ./ -s _mock.go 32 type JetStorage interface { 33 UpdateJetTree(ctx context.Context, pulse core.PulseNumber, setActual bool, ids ...core.RecordID) 34 FindJet(ctx context.Context, pulse core.PulseNumber, id core.RecordID) (*core.RecordID, bool) 35 SplitJetTree(ctx context.Context, pulse core.PulseNumber, jetID core.RecordID) (*core.RecordID, *core.RecordID, error) 36 CloneJetTree(ctx context.Context, from, to core.PulseNumber) *jet.Tree 37 DeleteJetTree(ctx context.Context, pulse core.PulseNumber) 38 39 AddJets(ctx context.Context, jetIDs ...core.RecordID) error 40 GetJets(ctx context.Context) (jet.IDSet, error) 41 } 42 43 type jetStorage struct { 44 DB DBContext `inject:""` 45 46 trees map[core.PulseNumber]*jet.Tree 47 treesLock sync.RWMutex 48 49 addJetLock sync.RWMutex 50 } 51 52 func NewJetStorage() JetStorage { 53 return &jetStorage{ 54 trees: map[core.PulseNumber]*jet.Tree{}, 55 } 56 } 57 58 // FindJet finds jet for specified pulse and object. 59 func (js *jetStorage) FindJet(ctx context.Context, pulse core.PulseNumber, id core.RecordID) (*core.RecordID, bool) { 60 js.treesLock.RLock() 61 62 if t, ok := js.trees[pulse]; ok { 63 defer js.treesLock.RUnlock() 64 return t.Find(id) 65 } 66 js.treesLock.RUnlock() 67 68 js.treesLock.Lock() 69 defer js.treesLock.Unlock() 70 return js.getJetTree(ctx, pulse).Find(id) 71 } 72 73 // UpdateJetTree updates jet tree for specified pulse. 74 func (js *jetStorage) UpdateJetTree(ctx context.Context, pulse core.PulseNumber, setActual bool, ids ...core.RecordID) { 75 js.treesLock.Lock() 76 defer js.treesLock.Unlock() 77 78 tree := js.getJetTree(ctx, pulse) 79 for _, id := range ids { 80 tree.Update(id, setActual) 81 } 82 } 83 84 // SplitJetTree performs jet split and returns resulting jet ids. 85 func (js *jetStorage) SplitJetTree( 86 ctx context.Context, pulse core.PulseNumber, jetID core.RecordID, 87 ) (*core.RecordID, *core.RecordID, error) { 88 js.treesLock.Lock() 89 defer js.treesLock.Unlock() 90 91 tree := js.getJetTree(ctx, pulse) 92 93 left, right, err := tree.Split(jetID) 94 if err != nil { 95 return nil, nil, err 96 } 97 98 return left, right, nil 99 } 100 101 // CloneJetTree copies tree from one pulse to another. Use it to copy past tree into new pulse. 102 func (js *jetStorage) CloneJetTree( 103 ctx context.Context, from, to core.PulseNumber, 104 ) *jet.Tree { 105 js.treesLock.Lock() 106 defer js.treesLock.Unlock() 107 108 tree := js.getJetTree(ctx, from) 109 110 res := tree.Clone(false) 111 js.trees[to] = res 112 return res 113 } 114 115 func (js *jetStorage) DeleteJetTree( 116 ctx context.Context, pulse core.PulseNumber, 117 ) { 118 js.treesLock.Lock() 119 defer js.treesLock.Unlock() 120 121 delete(js.trees, pulse) 122 } 123 124 func (js *jetStorage) getJetTree(ctx context.Context, pulse core.PulseNumber) *jet.Tree { 125 if t, ok := js.trees[pulse]; ok { 126 return t 127 } 128 129 tree := jet.NewTree(pulse == core.GenesisPulse.PulseNumber) 130 js.trees[pulse] = tree 131 return tree 132 } 133 134 // AddJets stores a list of jets of the current node. 135 func (js *jetStorage) AddJets(ctx context.Context, jetIDs ...core.RecordID) error { 136 js.addJetLock.Lock() 137 defer js.addJetLock.Unlock() 138 139 k := prefixkey(scopeIDSystem, []byte{sysJetList}) 140 141 var jets jet.IDSet 142 buff, err := js.DB.get(ctx, k) 143 if err == nil { 144 dec := codec.NewDecoder(bytes.NewReader(buff), &codec.CborHandle{}) 145 err = dec.Decode(&jets) 146 if err != nil { 147 return err 148 } 149 } else if err == core.ErrNotFound { 150 jets = jet.IDSet{} 151 } else { 152 return err 153 } 154 155 for _, id := range jetIDs { 156 jets[id] = struct{}{} 157 } 158 return js.DB.set(ctx, k, jets.Bytes()) 159 } 160 161 // GetJets returns jets of the current node 162 func (js *jetStorage) GetJets(ctx context.Context) (jet.IDSet, error) { 163 js.addJetLock.RLock() 164 defer js.addJetLock.RUnlock() 165 166 k := prefixkey(scopeIDSystem, []byte{sysJetList}) 167 buff, err := js.DB.get(ctx, k) 168 if err != nil { 169 return nil, err 170 } 171 172 dec := codec.NewDecoder(bytes.NewReader(buff), &codec.CborHandle{}) 173 var jets jet.IDSet 174 err = dec.Decode(&jets) 175 if err != nil { 176 return nil, err 177 } 178 179 return jets, nil 180 }