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  }