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  }