github.com/turingchain2020/turingchain@v1.1.21/common/db/localdb.go (about)

     1  package db
     2  
     3  import (
     4  	"sync"
     5  )
     6  
     7  // LocalDB local db for store key value in local
     8  type LocalDB struct {
     9  	txcache  DB
    10  	cache    DB
    11  	maindb   DB
    12  	intx     bool
    13  	mu       sync.RWMutex
    14  	readOnly bool
    15  }
    16  
    17  func newMemDB() DB {
    18  	memdb, err := NewGoMemDB("", "", 0)
    19  	if err != nil {
    20  		panic(err)
    21  	}
    22  	return memdb
    23  }
    24  
    25  // NewLocalDB new local db
    26  func NewLocalDB(maindb DB, readOnly bool) KVDB {
    27  	if readOnly {
    28  		//只读模式不需要memdb,比如交易检查,可以使用该localdb,减少memdb内存开销
    29  		return &LocalDB{
    30  			maindb:   maindb,
    31  			readOnly: true,
    32  		}
    33  	}
    34  	return &LocalDB{
    35  		cache:   newMemDB(),
    36  		txcache: newMemDB(),
    37  		maindb:  maindb,
    38  	}
    39  }
    40  
    41  // Get get value from local db
    42  func (l *LocalDB) Get(key []byte) ([]byte, error) {
    43  	l.mu.RLock()
    44  	defer l.mu.RUnlock()
    45  	value, err := l.get(key)
    46  	if isdeleted(value) {
    47  		//表示已经删除了(空值要用内部定义的 emptyvalue)
    48  		return nil, ErrNotFoundInDb
    49  	}
    50  	return value, err
    51  }
    52  
    53  func (l *LocalDB) get(key []byte) ([]byte, error) {
    54  	if l.intx && l.txcache != nil {
    55  		if value, err := l.txcache.Get(key); err == nil {
    56  			return value, nil
    57  		}
    58  	}
    59  	if l.cache != nil {
    60  		if value, err := l.cache.Get(key); err == nil {
    61  			return value, nil
    62  		}
    63  	}
    64  	value, err := l.maindb.Get(key)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  	if l.cache != nil {
    69  		err = l.cache.Set(key, value)
    70  		if err != nil {
    71  			panic(err)
    72  		}
    73  	}
    74  	return value, nil
    75  }
    76  
    77  // Set set key value to local db
    78  func (l *LocalDB) Set(key []byte, value []byte) error {
    79  	l.mu.Lock()
    80  	defer l.mu.Unlock()
    81  	if l.readOnly {
    82  		panic("set local db in read only mode")
    83  	}
    84  	if l.intx {
    85  		if l.txcache == nil {
    86  			l.txcache = newMemDB()
    87  		}
    88  		setdb2(l.txcache, key, value)
    89  	} else if l.cache != nil {
    90  		setdb2(l.cache, key, value)
    91  	}
    92  	return nil
    93  }
    94  
    95  // List 从数据库中查询数据列表,set 中的cache 更新不会影响这个list
    96  func (l *LocalDB) List(prefix, key []byte, count, direction int32) ([][]byte, error) {
    97  	l.mu.RLock()
    98  	defer l.mu.RUnlock()
    99  	dblist := make([]IteratorDB, 0)
   100  	if l.txcache != nil {
   101  		dblist = append(dblist, l.txcache)
   102  	}
   103  	if l.cache != nil {
   104  		dblist = append(dblist, l.cache)
   105  	}
   106  	if l.maindb != nil {
   107  		dblist = append(dblist, l.maindb)
   108  	}
   109  	mergedb := NewMergedIteratorDB(dblist)
   110  	it := NewListHelper(mergedb)
   111  	return it.List(prefix, key, count, direction), nil
   112  }
   113  
   114  // PrefixCount 从数据库中查询指定前缀的key的数量
   115  func (l *LocalDB) PrefixCount(prefix []byte) (count int64) {
   116  	l.mu.RLock()
   117  	defer l.mu.RUnlock()
   118  	dblist := make([]IteratorDB, 0)
   119  	if l.txcache != nil {
   120  		dblist = append(dblist, l.txcache)
   121  	}
   122  	if l.cache != nil {
   123  		dblist = append(dblist, l.cache)
   124  	}
   125  	if l.maindb != nil {
   126  		dblist = append(dblist, l.maindb)
   127  	}
   128  	mergedb := NewMergedIteratorDB(dblist)
   129  	it := NewListHelper(mergedb)
   130  	return it.PrefixCount(prefix)
   131  }
   132  
   133  //Begin 开启内存事务处理
   134  func (l *LocalDB) Begin() {
   135  	l.mu.Lock()
   136  	defer l.mu.Unlock()
   137  	l.intx = true
   138  	l.txcache = nil
   139  }
   140  
   141  // Rollback reset tx
   142  func (l *LocalDB) Rollback() {
   143  	l.mu.Lock()
   144  	defer l.mu.Unlock()
   145  	l.resetTx()
   146  }
   147  
   148  // Commit canche tx
   149  func (l *LocalDB) Commit() error {
   150  	l.mu.Lock()
   151  	defer l.mu.Unlock()
   152  	if l.txcache == nil {
   153  		l.resetTx()
   154  		return nil
   155  	}
   156  	it := l.txcache.Iterator(nil, nil, false)
   157  	for it.Next() {
   158  		err := l.cache.Set(it.Key(), it.Value())
   159  		if err != nil {
   160  			panic(err)
   161  		}
   162  	}
   163  	l.resetTx()
   164  	return nil
   165  }
   166  
   167  func (l *LocalDB) resetTx() {
   168  	l.intx = false
   169  	l.txcache = nil
   170  }
   171  
   172  func setdb2(d DB, key []byte, value []byte) {
   173  	//value == nil 特殊标记key,代表key已经删除了
   174  	err := d.Set(key, value)
   175  	if err != nil {
   176  		panic(err)
   177  	}
   178  }