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 }