github.com/turingchain2020/turingchain@v1.1.21/executor/statedb.go (about) 1 // Copyright Turing Corp. 2018 All Rights Reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package executor 6 7 import ( 8 "encoding/hex" 9 10 "github.com/turingchain2020/turingchain/common/db" 11 "github.com/turingchain2020/turingchain/queue" 12 "github.com/turingchain2020/turingchain/types" 13 ) 14 15 // StateDB state db for store mavl 16 type StateDB struct { 17 cache map[string][]byte 18 txcache map[string][]byte 19 keys []string 20 intx bool 21 client queue.Client 22 stateHash []byte 23 version int64 24 height int64 25 local *db.SimpleMVCC 26 opt *StateDBOption 27 } 28 29 // StateDBOption state db option enable mvcc 30 type StateDBOption struct { 31 EnableMVCC bool 32 Height int64 33 } 34 35 // NewStateDB new state db 36 func NewStateDB(client queue.Client, stateHash []byte, localdb db.KVDB, opt *StateDBOption) db.KV { 37 if opt == nil { 38 opt = &StateDBOption{} 39 } 40 db := &StateDB{ 41 //预分配一个单位 42 cache: make(map[string][]byte, 1), 43 txcache: make(map[string][]byte), 44 intx: false, 45 client: client, 46 stateHash: stateHash, 47 height: opt.Height, 48 version: -1, 49 local: db.NewSimpleMVCC(localdb), 50 opt: opt, 51 } 52 return db 53 } 54 55 func (s *StateDB) enableMVCC(hash []byte) { 56 opt := s.opt 57 if opt.EnableMVCC { 58 if hash == nil { 59 hash = s.stateHash 60 } 61 v, err := s.local.GetVersion(hash) 62 if err == nil && v >= 0 { 63 s.version = v 64 } else if s.height > 0 { 65 println("init state db", "height", s.height, "err", err.Error(), "v", v, "stateHash", hex.EncodeToString(s.stateHash)) 66 panic("mvcc get version error,config set enableMVCC=true, it must be synchronized from 0 height") 67 } 68 } 69 } 70 71 // Begin 开启内存事务处理 72 func (s *StateDB) Begin() { 73 s.intx = true 74 s.keys = nil 75 types.AssertConfig(s.client) 76 cfg := s.client.GetConfig() 77 if cfg.IsFork(s.height, "ForkExecRollback") { 78 s.txcache = nil 79 } 80 } 81 82 // Rollback reset tx 83 func (s *StateDB) Rollback() { 84 s.resetTx() 85 } 86 87 // Commit canche tx 88 func (s *StateDB) Commit() error { 89 for k, v := range s.txcache { 90 s.cache[k] = v 91 } 92 s.intx = false 93 s.keys = nil 94 types.AssertConfig(s.client) 95 cfg := s.client.GetConfig() 96 if cfg.IsFork(s.height, "ForkExecRollback") { 97 s.resetTx() 98 } 99 return nil 100 } 101 102 func (s *StateDB) resetTx() { 103 s.intx = false 104 s.txcache = nil 105 s.keys = nil 106 } 107 108 // Get get value from state db 109 func (s *StateDB) Get(key []byte) ([]byte, error) { 110 v, err := s.get(key) 111 debugAccount("==get==", key, v) 112 return v, err 113 } 114 115 func (s *StateDB) get(key []byte) ([]byte, error) { 116 skey := types.Bytes2Str(key) 117 if s.intx && s.txcache != nil { 118 if value, ok := s.txcache[skey]; ok { 119 return value, nil 120 } 121 } 122 if value, ok := s.cache[skey]; ok { 123 return value, nil 124 } 125 //mvcc 是有效的情况下,直接从mvcc中获取 126 if s.version >= 0 { 127 data, err := s.local.GetV(key, s.version) 128 //TODO 这里需要一个标志,数据是否是从0开始同步的 129 return data, err 130 } 131 if s.client == nil { 132 return nil, types.ErrNotFound 133 } 134 query := &types.StoreGet{StateHash: s.stateHash, Keys: [][]byte{key}} 135 msg := s.client.NewMessage("store", types.EventStoreGet, query) 136 err := s.client.Send(msg, true) 137 if err != nil { 138 return nil, err 139 } 140 resp, err := s.client.Wait(msg) 141 if err != nil { 142 panic(err) //no happen for ever 143 } 144 defer s.client.FreeMessage(msg, resp) 145 if nil == resp.GetData().(*types.StoreReplyValue).Values { 146 return nil, types.ErrNotFound 147 } 148 value := resp.GetData().(*types.StoreReplyValue).Values[0] 149 if value == nil { 150 //panic(string(key)) 151 return nil, types.ErrNotFound 152 } 153 //get 的值可以写入cache,因为没有对系统的值做修改 154 s.cache[string(key)] = value 155 return value, nil 156 } 157 158 func debugAccount(prefix string, key []byte, value []byte) { 159 //println(prefix, string(key), string(value)) 160 /* 161 if !types.Debug { 162 return 163 } 164 var msg types.Account 165 err := types.Decode(value, &msg) 166 if err == nil { 167 elog.Info(prefix, "key", string(key), "value", msg) 168 } 169 */ 170 } 171 172 // StartTx reset state db keys 173 func (s *StateDB) StartTx() { 174 s.keys = nil 175 } 176 177 // GetSetKeys get state db set keys 178 func (s *StateDB) GetSetKeys() (keys []string) { 179 return s.keys 180 } 181 182 // Set set key value to state db 183 func (s *StateDB) Set(key []byte, value []byte) error { 184 debugAccount("==set==", key, value) 185 skey := string(key) 186 if s.intx { 187 if s.txcache == nil { 188 s.txcache = make(map[string][]byte) 189 } 190 s.keys = append(s.keys, skey) 191 setmap(s.txcache, skey, value) 192 } else { 193 setmap(s.cache, skey, value) 194 } 195 return nil 196 } 197 198 func setmap(data map[string][]byte, key string, value []byte) { 199 if value == nil { 200 delete(data, key) 201 return 202 } 203 data[key] = value 204 } 205 206 // BatchGet batch get keys from state db 207 func (s *StateDB) BatchGet(keys [][]byte) (values [][]byte, err error) { 208 for _, key := range keys { 209 v, err := s.Get(key) 210 if err != nil && err != types.ErrNotFound { 211 return nil, err 212 } 213 values = append(values, v) 214 } 215 return values, nil 216 }