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  }