github.com/iotexproject/iotex-core@v1.14.1-rc1/db/trie/mptrie/twolayertrie.go (about)

     1  // Copyright (c) 2020 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package mptrie
     7  
     8  import (
     9  	"bytes"
    10  	"context"
    11  	"encoding/hex"
    12  	"sort"
    13  
    14  	"github.com/pkg/errors"
    15  
    16  	"github.com/iotexproject/iotex-core/db/trie"
    17  )
    18  
    19  type (
    20  	layerTwo struct {
    21  		tr         trie.Trie
    22  		dirty      bool
    23  		originHash []byte
    24  	}
    25  	twoLayerTrie struct {
    26  		layerOne    trie.Trie
    27  		layerTwoMap map[string]*layerTwo
    28  		kvStore     trie.KVStore
    29  		rootKey     string
    30  	}
    31  )
    32  
    33  // NewTwoLayerTrie creates a two layer trie
    34  func NewTwoLayerTrie(dbForTrie trie.KVStore, rootKey string) trie.TwoLayerTrie {
    35  	return &twoLayerTrie{
    36  		kvStore: dbForTrie,
    37  		rootKey: rootKey,
    38  	}
    39  }
    40  
    41  func (tlt *twoLayerTrie) layerTwoTrie(key []byte, layerTwoTrieKeyLen int) (*layerTwo, error) {
    42  	hk := hex.EncodeToString(key)
    43  	if lt, ok := tlt.layerTwoMap[hk]; ok {
    44  		return lt, nil
    45  	}
    46  	opts := []Option{KVStoreOption(tlt.kvStore), KeyLengthOption(layerTwoTrieKeyLen), AsyncOption()}
    47  	value, err := tlt.layerOne.Get(key)
    48  	switch errors.Cause(err) {
    49  	case trie.ErrNotExist:
    50  		// start an empty trie
    51  	case nil:
    52  		opts = append(opts, RootHashOption(value))
    53  	default:
    54  		return nil, err
    55  	}
    56  
    57  	lt, err := New(opts...)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	if err := lt.Start(context.Background()); err != nil {
    62  		return nil, err
    63  	}
    64  	h, err := lt.RootHash()
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	tlt.layerTwoMap[hk] = &layerTwo{
    70  		tr:         lt,
    71  		dirty:      false,
    72  		originHash: h,
    73  	}
    74  
    75  	return tlt.layerTwoMap[hk], nil
    76  }
    77  
    78  func (tlt *twoLayerTrie) Start(ctx context.Context) error {
    79  	rootHash, err := tlt.kvStore.Get([]byte(tlt.rootKey))
    80  	if errors.Cause(err) == trie.ErrNotExist {
    81  		rootHash = nil
    82  	}
    83  	layerOne, err := New(
    84  		KVStoreOption(tlt.kvStore),
    85  		RootHashOption(rootHash),
    86  		AsyncOption(),
    87  	)
    88  	if err != nil {
    89  		return errors.Wrapf(err, "failed to generate trie for %s", tlt.rootKey)
    90  	}
    91  	tlt.layerOne = layerOne
    92  	tlt.layerTwoMap = make(map[string]*layerTwo)
    93  
    94  	return tlt.layerOne.Start(ctx)
    95  }
    96  
    97  func (tlt *twoLayerTrie) Stop(ctx context.Context) error {
    98  	if err := tlt.flush(ctx); err != nil {
    99  		return err
   100  	}
   101  
   102  	return tlt.layerOne.Stop(ctx)
   103  }
   104  
   105  func (tlt *twoLayerTrie) stop(ctx context.Context, hkey string, lt *layerTwo) (err error) {
   106  	key, err := hex.DecodeString(hkey)
   107  	if err != nil {
   108  		return err
   109  	}
   110  	if lt.dirty {
   111  		rh, err := lt.tr.RootHash()
   112  		if err != nil {
   113  			return err
   114  		}
   115  		if !bytes.Equal(rh, lt.originHash) {
   116  			if lt.tr.IsEmpty() {
   117  				return tlt.layerOne.Delete(key)
   118  			}
   119  
   120  			return tlt.layerOne.Upsert(key, rh)
   121  		}
   122  	}
   123  
   124  	return lt.tr.Stop(ctx)
   125  }
   126  
   127  func (tlt *twoLayerTrie) layerTwoKeys() []string {
   128  	keys := make([]string, 0)
   129  	for k := range tlt.layerTwoMap {
   130  		keys = append(keys, k)
   131  	}
   132  	sort.Strings(keys)
   133  
   134  	return keys
   135  }
   136  
   137  func (tlt *twoLayerTrie) flush(ctx context.Context) error {
   138  	keys := tlt.layerTwoKeys()
   139  	for _, hkey := range keys {
   140  		if err := tlt.stop(ctx, hkey, tlt.layerTwoMap[hkey]); err != nil {
   141  			return err
   142  		}
   143  	}
   144  	tlt.layerTwoMap = make(map[string]*layerTwo)
   145  	_, err := tlt.layerOne.RootHash()
   146  	return err
   147  }
   148  
   149  func (tlt *twoLayerTrie) RootHash() ([]byte, error) {
   150  	if err := tlt.flush(context.Background()); err != nil {
   151  		return nil, err
   152  	}
   153  	return tlt.layerOne.RootHash()
   154  }
   155  
   156  func (tlt *twoLayerTrie) SetRootHash(rh []byte) error {
   157  	if err := tlt.layerOne.SetRootHash(rh); err != nil {
   158  		return err
   159  	}
   160  	keys := tlt.layerTwoKeys()
   161  	for _, k := range keys {
   162  		if err := tlt.layerTwoMap[k].tr.Stop(context.Background()); err != nil {
   163  			return err
   164  		}
   165  	}
   166  	tlt.layerTwoMap = make(map[string]*layerTwo)
   167  	return nil
   168  }
   169  
   170  func (tlt *twoLayerTrie) Get(layerOneKey []byte, layerTwoKey []byte) ([]byte, error) {
   171  	lt, err := tlt.layerTwoTrie(layerOneKey, len(layerTwoKey))
   172  	if err != nil {
   173  		return nil, err
   174  	}
   175  
   176  	return lt.tr.Get(layerTwoKey)
   177  }
   178  
   179  func (tlt *twoLayerTrie) Upsert(layerOneKey []byte, layerTwoKey []byte, value []byte) error {
   180  	lt, err := tlt.layerTwoTrie(layerOneKey, len(layerTwoKey))
   181  	if err != nil {
   182  		return err
   183  	}
   184  	if err := lt.tr.Upsert(layerTwoKey, value); err != nil {
   185  		return err
   186  	}
   187  	lt.dirty = true
   188  
   189  	return nil
   190  }
   191  
   192  func (tlt *twoLayerTrie) Delete(layerOneKey []byte, layerTwoKey []byte) error {
   193  	lt, err := tlt.layerTwoTrie(layerOneKey, len(layerTwoKey))
   194  	if err != nil {
   195  		return err
   196  	}
   197  	if err := lt.tr.Delete(layerTwoKey); err != nil {
   198  		return err
   199  	}
   200  	lt.dirty = true
   201  
   202  	return nil
   203  }