github.com/bartle-stripe/trillian@v1.2.1/storage/cache/subtree_cache.go (about) 1 // Copyright 2016 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 cache 16 17 import ( 18 "bytes" 19 "encoding/base64" 20 "fmt" 21 "sync" 22 23 "github.com/golang/glog" 24 "github.com/google/trillian/storage" 25 "github.com/google/trillian/storage/storagepb" 26 ) 27 28 // GetSubtreeFunc describes a function which can return a Subtree from storage. 29 type GetSubtreeFunc func(id storage.NodeID) (*storagepb.SubtreeProto, error) 30 31 // GetSubtreesFunc describes a function which can return a number of Subtrees from storage. 32 type GetSubtreesFunc func(ids []storage.NodeID) ([]*storagepb.SubtreeProto, error) 33 34 // SetSubtreesFunc describes a function which can store a collection of Subtrees into storage. 35 type SetSubtreesFunc func(s []*storagepb.SubtreeProto) error 36 37 // stratumInfo represents a single stratum across the tree. 38 // It it used inside the SubtreeCache to determine which Subtree prefix should 39 // be used for a given NodeID. 40 // Currently, the strata must have depths which are multiples of 8. 41 type stratumInfo struct { 42 // prefixBytes is the number of prefix bytes above this stratum. 43 prefixBytes int 44 // depth is the number of levels in this stratum. 45 depth int 46 } 47 48 const ( 49 // maxSupportedTreeDepth is the maximum depth a tree can reach. Note that log trees are 50 // further limited to a depth of 63 by the use of signed 64 bit leaf indices. Map trees 51 // do not have this restriction. 52 maxSupportedTreeDepth = 256 53 // depthQuantum defines the smallest supported subtree depth and all subtrees must be 54 // a multiple of this value in depth. 55 depthQuantum = 8 56 // logStrataDepth is the strata that must be used for all log subtrees. 57 logStrataDepth = 8 58 // maxLogDepth is the number of bits in a log path. 59 maxLogDepth = 64 60 ) 61 62 // SubtreeCache provides a caching access to Subtree storage. Currently there are assumptions 63 // in the code that all subtrees are multiple of 8 in depth and that log subtrees are always 64 // of depth 8. It is not possible to just change the constants above and have things still 65 // work. This is because of issues like byte packing of node IDs. 66 type SubtreeCache struct { 67 // prefixLengths contains the strata prefix sizes for each multiple-of-depthQuantum tree 68 // size. 69 stratumInfo []stratumInfo 70 // subtrees contains the Subtree data read from storage, and is updated by 71 // calls to SetNodeHash. 72 subtrees map[string]*storagepb.SubtreeProto 73 // dirtyPrefixes keeps track of all Subtrees which need to be written back 74 // to storage. 75 dirtyPrefixes map[string]bool 76 // mutex guards access to the maps above. 77 mutex *sync.RWMutex 78 // populate is used to rebuild internal nodes when subtrees are loaded from storage. 79 populate storage.PopulateSubtreeFunc 80 // prepare is used for preparation work when subtrees are about to be written to storage. 81 prepare storage.PrepareSubtreeWriteFunc 82 } 83 84 // NewSubtreeCache returns a newly intialised cache ready for use. 85 // populateSubtree is a function which knows how to populate a subtree's 86 // internal nodes given its leaves, and will be called for each subtree loaded 87 // from storage. 88 // TODO(al): consider supporting different sized subtrees - for now everything's subtrees of 8 levels. 89 func NewSubtreeCache(strataDepths []int, populateSubtree storage.PopulateSubtreeFunc, prepareSubtreeWrite storage.PrepareSubtreeWriteFunc) SubtreeCache { 90 // TODO(al): pass this in 91 maxTreeDepth := maxSupportedTreeDepth 92 // Precalculate strata information based on the passed in strata depths: 93 sInfo := make([]stratumInfo, 0, maxTreeDepth/depthQuantum) 94 t := 0 95 for _, sDepth := range strataDepths { 96 // Verify the stratum depth makes sense: 97 if sDepth <= 0 { 98 panic(fmt.Errorf("got invalid strata depth of %d: can't be <= 0", sDepth)) 99 } 100 if sDepth%depthQuantum != 0 { 101 panic(fmt.Errorf("got strata depth of %d, must be a multiple of %d", sDepth, depthQuantum)) 102 } 103 104 pb := t / depthQuantum 105 for i := 0; i < sDepth; i += depthQuantum { 106 sInfo = append(sInfo, stratumInfo{pb, sDepth}) 107 t += depthQuantum 108 } 109 } 110 // TODO(al): This needs to be passed in, particularly for Map use cases where 111 // we need to know it matches the number of bits in the chosen hash function. 112 if got, want := t, maxTreeDepth; got != want { 113 panic(fmt.Errorf("strata indicate tree of depth %d, but expected %d", got, want)) 114 } 115 116 return SubtreeCache{ 117 stratumInfo: sInfo, 118 subtrees: make(map[string]*storagepb.SubtreeProto), 119 dirtyPrefixes: make(map[string]bool), 120 mutex: new(sync.RWMutex), 121 populate: populateSubtree, 122 prepare: prepareSubtreeWrite, 123 } 124 } 125 126 func (s *SubtreeCache) stratumInfoForPrefixLength(numBits int) stratumInfo { 127 return s.stratumInfo[numBits/depthQuantum] 128 } 129 130 // splitNodeID breaks a NodeID out into its prefix and suffix parts. 131 // unless ID is 0 bits long, Suffix must always contain at least one bit. 132 func (s *SubtreeCache) splitNodeID(id storage.NodeID) ([]byte, storage.Suffix) { 133 sInfo := s.stratumInfoForPrefixLength(id.PrefixLenBits - 1) 134 return id.Split(sInfo.prefixBytes, sInfo.depth) 135 } 136 137 // preload calculates the set of subtrees required to know the hashes of the 138 // passed in node IDs, uses getSubtrees to retrieve them, and finally populates 139 // the cache structures with the data. 140 func (s *SubtreeCache) preload(ids []storage.NodeID, getSubtrees GetSubtreesFunc) error { 141 s.mutex.Lock() 142 defer s.mutex.Unlock() 143 144 // Figure out the set of subtrees we need: 145 want := make(map[string]*storage.NodeID) 146 for _, id := range ids { 147 id := id 148 px, _ := s.splitNodeID(id) 149 pxKey := string(px) 150 // TODO(al): fix for non-uniform strata 151 id.PrefixLenBits = len(px) * depthQuantum 152 if _, ok := s.subtrees[pxKey]; !ok { 153 want[pxKey] = &id 154 } 155 } 156 157 // There might be nothing to do so don't make a read request for zero subtrees if so 158 if len(want) == 0 { 159 return nil 160 } 161 162 list := make([]storage.NodeID, 0, len(want)) 163 for _, v := range want { 164 list = append(list, *v) 165 } 166 subtrees, err := getSubtrees(list) 167 if err != nil { 168 return err 169 } 170 for _, t := range subtrees { 171 s.populate(t) 172 s.subtrees[string(t.Prefix)] = t 173 delete(want, string(t.Prefix)) 174 } 175 176 // We might not have got all the subtrees we requested, if they don't already exist. 177 // Create empty subtrees for anything left over. As an additional sanity check we refuse 178 // to overwrite anything already in the cache as we determined above that these subtrees 179 // should not exist in the subtree cache map. 180 for _, id := range want { 181 prefixLen := id.PrefixLenBits / depthQuantum 182 px := id.Path[:prefixLen] 183 pxKey := string(px) 184 _, exists := s.subtrees[pxKey] 185 if exists { 186 return fmt.Errorf("preload tried to clobber existing subtree for: %v", *id) 187 } 188 s.subtrees[pxKey] = s.newEmptySubtree(*id, px) 189 } 190 191 return nil 192 } 193 194 // GetNodes returns the requested nodes, calling the getSubtrees function if 195 // they are not already cached. 196 func (s *SubtreeCache) GetNodes(ids []storage.NodeID, getSubtrees GetSubtreesFunc) ([]storage.Node, error) { 197 if glog.V(4) { 198 for _, n := range ids { 199 glog.Infof("cache: GetNodes(%x, %d", n.Path, n.PrefixLenBits) 200 } 201 } 202 if err := s.preload(ids, getSubtrees); err != nil { 203 return nil, err 204 } 205 206 ret := make([]storage.Node, 0, len(ids)) 207 for _, id := range ids { 208 h, err := s.GetNodeHash( 209 id, 210 func(n storage.NodeID) (*storagepb.SubtreeProto, error) { 211 // This should never happen - we should've already read all the data we 212 // need above, in Preload() 213 glog.Warningf("Unexpectedly reading from within GetNodeHash(): %s", n.String()) 214 ret, err := getSubtrees([]storage.NodeID{n}) 215 if err != nil || len(ret) == 0 { 216 return nil, err 217 } 218 if n := len(ret); n > 1 { 219 return nil, fmt.Errorf("got %d trees, want: 1", n) 220 } 221 return ret[0], nil 222 }) 223 if err != nil { 224 return nil, err 225 } 226 227 if h != nil { 228 ret = append(ret, storage.Node{ 229 NodeID: id, 230 Hash: h, 231 }) 232 } 233 } 234 return ret, nil 235 } 236 237 // GetNodeHash returns a single node hash from the cache. 238 func (s *SubtreeCache) GetNodeHash(id storage.NodeID, getSubtree GetSubtreeFunc) ([]byte, error) { 239 s.mutex.RLock() 240 defer s.mutex.RUnlock() 241 return s.getNodeHashUnderLock(id, getSubtree) 242 } 243 244 // getNodeHashUnderLock must be called with s.mutex locked. 245 func (s *SubtreeCache) getNodeHashUnderLock(id storage.NodeID, getSubtree GetSubtreeFunc) ([]byte, error) { 246 px, sx := s.splitNodeID(id) 247 prefixKey := string(px) 248 c := s.subtrees[prefixKey] 249 if c == nil { 250 glog.V(1).Infof("Cache miss for %x so we'll try to fetch from storage", prefixKey) 251 // Cache miss, so we'll try to fetch from storage. 252 subID := id 253 subID.PrefixLenBits = len(px) * depthQuantum // this won't work if depthQuantum changes 254 var err error 255 c, err = getSubtree(subID) 256 if err != nil { 257 return nil, err 258 } 259 if c == nil { 260 c = s.newEmptySubtree(subID, px) 261 } else { 262 if err := s.populate(c); err != nil { 263 return nil, err 264 } 265 } 266 if c.Prefix == nil { 267 panic(fmt.Errorf("GetNodeHash nil prefix on %v for id %v with px %#v", c, id.String(), px)) 268 } 269 270 s.subtrees[prefixKey] = c 271 } 272 273 // finally look for the particular node within the subtree so we can return 274 // the hash & revision. 275 var nh []byte 276 277 // Look up the hash in the appropriate map. 278 // The leaf hashes are stored in a separate map to the internal nodes so that 279 // we can easily dump (and later reconstruct) the internal nodes. As log subtrees 280 // have a fixed depth if the suffix has the same number of significant bits as the 281 // subtree depth then this is a leaf. For example if the subtree is depth 8 its leaves 282 // have 8 significant suffix bits. 283 sfxKey := sx.String() 284 if int32(sx.Bits) == c.Depth { 285 nh = c.Leaves[sfxKey] 286 } else { 287 nh = c.InternalNodes[sfxKey] 288 } 289 if glog.V(4) { 290 b, err := base64.StdEncoding.DecodeString(sfxKey) 291 if err != nil { 292 glog.Errorf("base64.DecodeString(%v): %v", sfxKey, err) 293 } 294 glog.Infof("getNodeHashUnderLock(%x | %x): %x", prefixKey, b, nh) 295 } 296 if nh == nil { 297 return nil, nil 298 } 299 return nh, nil 300 } 301 302 // SetNodeHash sets a node hash in the cache. 303 func (s *SubtreeCache) SetNodeHash(id storage.NodeID, h []byte, getSubtree GetSubtreeFunc) error { 304 s.mutex.Lock() 305 defer s.mutex.Unlock() 306 px, sx := s.splitNodeID(id) 307 prefixKey := string(px) 308 c := s.subtrees[prefixKey] 309 if c == nil { 310 // TODO(al): This is ok, IFF *all* leaves in the subtree are being set, 311 // verify that this is the case when it happens. 312 // For now, just read from storage if we don't already have it. 313 glog.V(1).Infof("attempting to write to unread subtree for %v, reading now", id.String()) 314 // We hold the lock so can call this directly: 315 _, err := s.getNodeHashUnderLock(id, getSubtree) 316 if err != nil { 317 return err 318 } 319 // There must be a subtree present in the cache now, even if storage didn't have anything for us. 320 c = s.subtrees[prefixKey] 321 if c == nil { 322 return fmt.Errorf("internal error, subtree cache for %v is nil after a read attempt", id.String()) 323 } 324 } 325 if c.Prefix == nil { 326 return fmt.Errorf("nil prefix for %v (key %v)", id.String(), prefixKey) 327 } 328 // Determine whether we're being asked to store a leaf node, or an internal 329 // node, and store it accordingly. 330 sfxKey := sx.String() 331 if int32(sx.Bits) == c.Depth { 332 // If the value being set is identical to the one we read from storage, then 333 // leave the cache state alone, and return. This will prevent a write (and 334 // subtree revision bump) for identical data. 335 if bytes.Equal(c.Leaves[sfxKey], h) { 336 return nil 337 } 338 c.Leaves[sfxKey] = h 339 } else { 340 // If the value being set is identical to the one we read from storage, then 341 // leave the cache state alone, and return. This will prevent a write (and 342 // subtree revision bump) for identical data. 343 if bytes.Equal(c.InternalNodes[sfxKey], h) { 344 return nil 345 } 346 c.InternalNodes[sfxKey] = h 347 } 348 s.dirtyPrefixes[prefixKey] = true 349 if glog.V(4) { 350 b, err := base64.StdEncoding.DecodeString(sfxKey) 351 if err != nil { 352 glog.Errorf("base64.DecodeString(%v): %v", sfxKey, err) 353 } 354 glog.Infof("SetNodeHash(pfx: %x, sfx: %x): %x", prefixKey, b, h) 355 } 356 return nil 357 } 358 359 // Flush causes the cache to write all dirty Subtrees back to storage. 360 func (s *SubtreeCache) Flush(setSubtrees SetSubtreesFunc) error { 361 s.mutex.RLock() 362 defer s.mutex.RUnlock() 363 364 treesToWrite := make([]*storagepb.SubtreeProto, 0, len(s.dirtyPrefixes)) 365 for k, v := range s.subtrees { 366 if s.dirtyPrefixes[k] { 367 bk := []byte(k) 368 if !bytes.Equal(bk, v.Prefix) { 369 return fmt.Errorf("inconsistent cache: prefix key is %v, but cached object claims %v", bk, v.Prefix) 370 } 371 // TODO(al): Do actually write this one once we're storing the updated 372 // subtree root value here during tree update calculations. 373 v.RootHash = nil 374 375 if len(v.Leaves) > 0 { 376 // prepare internal nodes ready for the write (tree type specific) 377 if err := s.prepare(v); err != nil { 378 return err 379 } 380 treesToWrite = append(treesToWrite, v) 381 } 382 } 383 } 384 if len(treesToWrite) == 0 { 385 return nil 386 } 387 return setSubtrees(treesToWrite) 388 } 389 390 func (s *SubtreeCache) newEmptySubtree(id storage.NodeID, px []byte) *storagepb.SubtreeProto { 391 sInfo := s.stratumInfoForPrefixLength(id.PrefixLenBits) 392 glog.V(1).Infof("Creating new empty subtree for %x, with depth %d", px, sInfo.depth) 393 // storage didn't have one for us, so we'll store an empty proto here 394 // incase we try to update it later on (we won't flush it back to 395 // storage unless it's been written to.) 396 return &storagepb.SubtreeProto{ 397 Prefix: px, 398 Depth: int32(sInfo.depth), 399 Leaves: make(map[string][]byte), 400 InternalNodes: make(map[string][]byte), 401 } 402 }