github.com/bartle-stripe/trillian@v1.2.1/storage/memory/tree_storage.go (about) 1 // Copyright 2017 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package memory 16 17 import ( 18 "container/list" 19 "context" 20 "fmt" 21 "strings" 22 "sync" 23 24 "github.com/golang/glog" 25 "github.com/golang/protobuf/proto" 26 "github.com/google/btree" 27 "github.com/google/trillian" 28 "github.com/google/trillian/storage" 29 "github.com/google/trillian/storage/cache" 30 "github.com/google/trillian/storage/storagepb" 31 ) 32 33 const degree = 8 34 35 // unseqKey formats a key for use in a tree's BTree store. 36 // The associated Item value will be the stubtreeProto with the given nodeID 37 // prefix. 38 func subtreeKey(treeID, rev int64, nodeID storage.NodeID) btree.Item { 39 return &kv{k: fmt.Sprintf("/%d/subtree/%s/%d", treeID, nodeID.String(), rev)} 40 } 41 42 // tree stores all data for a given treeID 43 type tree struct { 44 // mu protects access to all tree members. 45 mu sync.RWMutex 46 // store is a key-value representation of a Trillian tree storage. 47 // The keyspace is partitioned off into various prefixes for the different 48 // 'tables' of things stored in there. 49 // e.g. subtree protos are stored with a key returned by subtreeKey() above. 50 // 51 // Other prefixes are used by Log/Map Storage. 52 // 53 // See the various key formatting functions for details of what is stored 54 // under the formatted keys. 55 // 56 // store uses a BTree so that we can have a defined ordering over things 57 // (such as sequenced leaves), while still accessing by key. 58 store *btree.BTree 59 // currentSTH is the timestamp of the current STH. 60 currentSTH uint64 61 meta *trillian.Tree 62 } 63 64 func (t *tree) Lock() { 65 t.mu.Lock() 66 } 67 68 func (t *tree) Unlock() { 69 t.mu.Unlock() 70 } 71 72 func (t *tree) RLock() { 73 t.mu.RLock() 74 } 75 76 func (t *tree) RUnlock() { 77 t.mu.RUnlock() 78 } 79 80 // memoryTreeStorage is shared between the memoryLog and (forthcoming) memoryMap- 81 // Storage implementations, and contains functionality which is common to both, 82 type memoryTreeStorage struct { 83 // mu only protects access to the trees map. 84 mu sync.RWMutex 85 trees map[int64]*tree 86 } 87 88 func newTreeStorage() *memoryTreeStorage { 89 return &memoryTreeStorage{ 90 trees: make(map[int64]*tree), 91 } 92 } 93 94 // getTree returns the tree associated with id, or nil if no such tree exists. 95 func (m *memoryTreeStorage) getTree(id int64) *tree { 96 m.mu.RLock() 97 defer m.mu.RUnlock() 98 return m.trees[id] 99 } 100 101 // kv is a simple key->value type which implements btree's Item interface. 102 type kv struct { 103 k string 104 v interface{} 105 } 106 107 // Less than by k's string key 108 func (a kv) Less(b btree.Item) bool { 109 return strings.Compare(a.k, b.(*kv).k) < 0 110 } 111 112 // newTree creates and initializes a tree struct. 113 func newTree(t trillian.Tree) *tree { 114 ret := &tree{ 115 store: btree.New(degree), 116 meta: &t, 117 } 118 k := unseqKey(t.TreeId) 119 k.(*kv).v = list.New() 120 ret.store.ReplaceOrInsert(k) 121 122 k = hashToSeqKey(t.TreeId) 123 k.(*kv).v = make(map[string][]int64) 124 ret.store.ReplaceOrInsert(k) 125 126 return ret 127 } 128 129 func (m *memoryTreeStorage) beginTreeTX(ctx context.Context, treeID int64, hashSizeBytes int, cache cache.SubtreeCache, readonly bool) (treeTX, error) { 130 tree := m.getTree(treeID) 131 // Lock the tree for the duration of the TX. 132 // It will be unlocked by a call to Commit or Rollback. 133 var unlock func() 134 if readonly { 135 tree.RLock() 136 unlock = tree.RUnlock 137 } else { 138 tree.Lock() 139 unlock = tree.Unlock 140 } 141 return treeTX{ 142 ts: m, 143 tx: tree.store.Clone(), 144 tree: tree, 145 treeID: treeID, 146 hashSizeBytes: hashSizeBytes, 147 subtreeCache: cache, 148 writeRevision: -1, 149 unlock: unlock, 150 }, nil 151 } 152 153 type treeTX struct { 154 closed bool 155 tx *btree.BTree 156 ts *memoryTreeStorage 157 tree *tree 158 treeID int64 159 hashSizeBytes int 160 subtreeCache cache.SubtreeCache 161 writeRevision int64 162 unlock func() 163 } 164 165 func (t *treeTX) getSubtree(ctx context.Context, treeRevision int64, nodeID storage.NodeID) (*storagepb.SubtreeProto, error) { 166 s, err := t.getSubtrees(ctx, treeRevision, []storage.NodeID{nodeID}) 167 if err != nil { 168 return nil, err 169 } 170 switch len(s) { 171 case 0: 172 return nil, nil 173 case 1: 174 return s[0], nil 175 default: 176 return nil, fmt.Errorf("got %d subtrees, but expected 1", len(s)) 177 } 178 } 179 180 func (t *treeTX) getSubtrees(ctx context.Context, treeRevision int64, nodeIDs []storage.NodeID) ([]*storagepb.SubtreeProto, error) { 181 if len(nodeIDs) == 0 { 182 return nil, nil 183 } 184 185 ret := make([]*storagepb.SubtreeProto, 0, len(nodeIDs)) 186 187 for _, nodeID := range nodeIDs { 188 if nodeID.PrefixLenBits%8 != 0 { 189 return nil, fmt.Errorf("invalid subtree ID - not multiple of 8: %d", nodeID.PrefixLenBits) 190 } 191 192 // Look for a nodeID at or below treeRevision: 193 for r := treeRevision; r >= 0; r-- { 194 s := t.tx.Get(subtreeKey(t.treeID, r, nodeID)) 195 if s == nil { 196 continue 197 } 198 // Return a copy of the proto to protect against the caller modifying the stored one. 199 p := s.(*kv).v.(*storagepb.SubtreeProto) 200 v := proto.Clone(p).(*storagepb.SubtreeProto) 201 ret = append(ret, v) 202 break 203 } 204 } 205 206 // The InternalNodes cache is possibly nil here, but the SubtreeCache (which called 207 // this method) will re-populate it. 208 return ret, nil 209 } 210 211 func (t *treeTX) storeSubtrees(ctx context.Context, subtrees []*storagepb.SubtreeProto) error { 212 if len(subtrees) == 0 { 213 glog.Warning("attempted to store 0 subtrees...") 214 return nil 215 } 216 217 for _, s := range subtrees { 218 s := s 219 if s.Prefix == nil { 220 panic(fmt.Errorf("nil prefix on %v", s)) 221 } 222 k := subtreeKey(t.treeID, t.writeRevision, storage.NewNodeIDFromHash(s.Prefix)) 223 k.(*kv).v = s 224 t.tx.ReplaceOrInsert(k) 225 } 226 return nil 227 } 228 229 // getSubtreesAtRev returns a GetSubtreesFunc which reads at the passed in rev. 230 func (t *treeTX) getSubtreesAtRev(ctx context.Context, rev int64) cache.GetSubtreesFunc { 231 return func(ids []storage.NodeID) ([]*storagepb.SubtreeProto, error) { 232 return t.getSubtrees(ctx, rev, ids) 233 } 234 } 235 236 // GetMerkleNodes returns the requests nodes at (or below) the passed in treeRevision. 237 func (t *treeTX) GetMerkleNodes(ctx context.Context, treeRevision int64, nodeIDs []storage.NodeID) ([]storage.Node, error) { 238 return t.subtreeCache.GetNodes(nodeIDs, t.getSubtreesAtRev(ctx, treeRevision)) 239 } 240 241 func (t *treeTX) SetMerkleNodes(ctx context.Context, nodes []storage.Node) error { 242 for _, n := range nodes { 243 err := t.subtreeCache.SetNodeHash(n.NodeID, n.Hash, 244 func(nID storage.NodeID) (*storagepb.SubtreeProto, error) { 245 return t.getSubtree(ctx, t.writeRevision, nID) 246 }) 247 if err != nil { 248 return err 249 } 250 } 251 return nil 252 } 253 254 func (t *treeTX) Commit() error { 255 defer t.unlock() 256 257 if t.writeRevision > -1 { 258 if err := t.subtreeCache.Flush(func(st []*storagepb.SubtreeProto) error { 259 return t.storeSubtrees(context.TODO(), st) 260 }); err != nil { 261 glog.Warningf("TX commit flush error: %v", err) 262 return err 263 } 264 } 265 t.closed = true 266 // update the shared view of the tree post TX: 267 t.tree.store = t.tx 268 return nil 269 } 270 271 func (t *treeTX) Rollback() error { 272 defer t.unlock() 273 274 t.closed = true 275 return nil 276 } 277 278 func (t *treeTX) Close() error { 279 if !t.closed { 280 err := t.Rollback() 281 if err != nil { 282 glog.Warningf("Rollback error on Close(): %v", err) 283 } 284 return err 285 } 286 return nil 287 } 288 289 func (t *treeTX) IsOpen() bool { 290 return !t.closed 291 }