github.com/turingchain2020/turingchain@v1.1.21/common/db/go_ssdb.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 db
     6  
     7  import (
     8  	"bytes"
     9  
    10  	log "github.com/turingchain2020/turingchain/common/log/log15"
    11  	"github.com/syndtr/goleveldb/leveldb/util"
    12  
    13  	"fmt"
    14  	"strconv"
    15  	"strings"
    16  	"time"
    17  
    18  	"github.com/turingchain2020/turingchain/types"
    19  )
    20  
    21  var dlog = log.New("module", "db.ssdb")
    22  var sdbBench = &SsdbBench{}
    23  
    24  func init() {
    25  	dbCreator := func(name string, dir string, cache int) (DB, error) {
    26  		return NewGoSSDB(name, dir, cache)
    27  	}
    28  	registerDBCreator(ssDBBackendStr, dbCreator, false)
    29  }
    30  
    31  //SsdbBench ...
    32  type SsdbBench struct {
    33  	// 写次数
    34  	writeCount int
    35  	// 写条数
    36  	writeNum int
    37  	// 写耗费时间
    38  	writeTime time.Duration
    39  	readCount int
    40  	readNum   int
    41  	readTime  time.Duration
    42  }
    43  
    44  //SsdbNode 节点
    45  type SsdbNode struct {
    46  	ip   string
    47  	port int
    48  }
    49  
    50  //GoSSDB db
    51  type GoSSDB struct {
    52  	BaseDB
    53  	pool  *SDBPool
    54  	nodes []*SsdbNode
    55  }
    56  
    57  func (bench *SsdbBench) write(num int, cost time.Duration) {
    58  	bench.writeCount++
    59  	bench.writeNum += num
    60  	bench.writeTime += cost
    61  }
    62  
    63  func (bench *SsdbBench) read(num int, cost time.Duration) {
    64  	bench.readCount++
    65  	bench.readNum += num
    66  	bench.readTime += cost
    67  }
    68  
    69  func (bench *SsdbBench) String() string {
    70  	return fmt.Sprintf("SSDBBenchmark[(ReadTimes=%v, ReadRecordNum=%v, ReadCostTime=%v;) (WriteTimes=%v, WriteRecordNum=%v, WriteCostTime=%v)",
    71  		bench.readCount, bench.readNum, bench.readTime, bench.writeCount, bench.writeNum, bench.writeTime)
    72  }
    73  
    74  func printSsdbBenchmark() {
    75  	tick := time.Tick(time.Minute * 5)
    76  	for {
    77  		<-tick
    78  		dlog.Info(sdbBench.String())
    79  	}
    80  }
    81  
    82  // url pattern: ip:port,ip:port
    83  func parseSsdbNode(url string) (nodes []*SsdbNode) {
    84  	hosts := strings.Split(url, ",")
    85  	if hosts == nil {
    86  		dlog.Error("invalid ssdb url")
    87  		return nil
    88  	}
    89  	for _, host := range hosts {
    90  		parts := strings.Split(host, ":")
    91  		if parts == nil || len(parts) != 2 {
    92  			dlog.Error("invalid ssd url", "part", host)
    93  			continue
    94  		}
    95  		ip := parts[0]
    96  		port, err := strconv.Atoi(parts[1])
    97  		if err != nil {
    98  			dlog.Error("invalid ssd url host port", "port", parts[1])
    99  			continue
   100  		}
   101  		nodes = append(nodes, &SsdbNode{ip, port})
   102  	}
   103  	return nodes
   104  }
   105  
   106  //NewGoSSDB new
   107  func NewGoSSDB(name string, dir string, cache int) (*GoSSDB, error) {
   108  	database := &GoSSDB{}
   109  	database.nodes = parseSsdbNode(dir)
   110  
   111  	if database.nodes == nil {
   112  		dlog.Error("no valid ssdb instance exists, exit!")
   113  		return nil, types.ErrDataBaseDamage
   114  	}
   115  	var err error
   116  	database.pool, err = NewSDBPool(database.nodes)
   117  	if err != nil {
   118  		dlog.Error("connect to ssdb error!", "ssdb", database.nodes[0])
   119  		return nil, types.ErrDataBaseDamage
   120  	}
   121  
   122  	go printSsdbBenchmark()
   123  
   124  	return database, nil
   125  }
   126  
   127  //Get get
   128  func (db *GoSSDB) Get(key []byte) ([]byte, error) {
   129  	start := time.Now()
   130  
   131  	value, err := db.pool.get().Get(string(key))
   132  	if err != nil {
   133  		//dlog.Error("Get value error", "error", err, "key", key, "keyhex", hex.EncodeToString(key), "keystr", string(key))
   134  		return nil, err
   135  	}
   136  	if value == nil {
   137  		return nil, ErrNotFoundInDb
   138  	}
   139  
   140  	sdbBench.read(1, time.Since(start))
   141  	return value.Bytes(), nil
   142  }
   143  
   144  //Set 设置
   145  func (db *GoSSDB) Set(key []byte, value []byte) error {
   146  	start := time.Now()
   147  
   148  	err := db.pool.get().Set(string(key), value)
   149  	if err != nil {
   150  		dlog.Error("Set", "error", err)
   151  		return err
   152  	}
   153  	sdbBench.write(1, time.Since(start))
   154  	return nil
   155  }
   156  
   157  //SetSync 同步
   158  func (db *GoSSDB) SetSync(key []byte, value []byte) error {
   159  	return db.Set(key, value)
   160  }
   161  
   162  //Delete 删除
   163  func (db *GoSSDB) Delete(key []byte) error {
   164  	start := time.Now()
   165  
   166  	err := db.pool.get().Del(string(key))
   167  	if err != nil {
   168  		dlog.Error("Delete", "error", err)
   169  		return err
   170  	}
   171  	sdbBench.write(1, time.Since(start))
   172  	return nil
   173  }
   174  
   175  //DeleteSync 删除同步
   176  func (db *GoSSDB) DeleteSync(key []byte) error {
   177  	return db.Delete(key)
   178  }
   179  
   180  //Close 关闭
   181  func (db *GoSSDB) Close() {
   182  	db.pool.close()
   183  }
   184  
   185  //Print 打印
   186  func (db *GoSSDB) Print() {
   187  }
   188  
   189  //Stats ...
   190  func (db *GoSSDB) Stats() map[string]string {
   191  	return make(map[string]string)
   192  }
   193  
   194  //Iterator 迭代器
   195  func (db *GoSSDB) Iterator(itbeg []byte, itend []byte, reverse bool) Iterator {
   196  	start := time.Now()
   197  
   198  	var (
   199  		keys  []string
   200  		err   error
   201  		begin string
   202  		end   string
   203  	)
   204  	if itend == nil {
   205  		itend = bytesPrefix(itbeg)
   206  	}
   207  	if bytes.Equal(itend, types.EmptyValue) {
   208  		itend = nil
   209  	}
   210  	limit := util.Range{Start: itbeg, Limit: itend}
   211  	if reverse {
   212  		begin = string(limit.Limit)
   213  		end = string(itbeg)
   214  		keys, err = db.pool.get().Rkeys(begin, end, IteratorPageSize)
   215  	} else {
   216  		begin = string(itbeg)
   217  		end = string(limit.Limit)
   218  		keys, err = db.pool.get().Keys(begin, end, IteratorPageSize)
   219  	}
   220  
   221  	it := newSSDBIt(begin, end, itbeg, itend, []string{}, reverse, db)
   222  	if err != nil {
   223  		dlog.Error("get iterator error", "error", err, "keys", keys)
   224  		return it
   225  	}
   226  	if len(keys) > 0 {
   227  		it.keys = keys
   228  
   229  		// 如果返回的数据大小刚好满足分页,则假设下一页还有数据
   230  		if len(it.keys) == IteratorPageSize {
   231  			it.nextPage = true
   232  			it.tmpEnd = it.keys[IteratorPageSize-1]
   233  		}
   234  	}
   235  
   236  	sdbBench.read(len(keys), time.Since(start))
   237  	return it
   238  }
   239  
   240  // 因为ssdb不支持原生的迭代器模式,需要一次获取KEY;
   241  // 为了防止匹配的KEY范围过大,这里需要进行分页,每次只取1024条KEY;
   242  // Next方法自动进行跨页取数据
   243  type ssDBIt struct {
   244  	itBase
   245  	db      *GoSSDB
   246  	keys    []string
   247  	index   int
   248  	reverse bool
   249  	// 迭代开始位置
   250  	begin string
   251  	// 迭代结束位置
   252  	end string
   253  
   254  	// 需要分页的情况下,下一页的开始位置
   255  	//  是否有下一页数据
   256  	tmpEnd   string
   257  	nextPage bool
   258  
   259  	// 当前所属的页数(从0开始)
   260  	pageNo int
   261  }
   262  
   263  func newSSDBIt(begin, end string, prefix, itend []byte, keys []string, reverse bool, db *GoSSDB) *ssDBIt {
   264  	return &ssDBIt{
   265  		itBase:  itBase{prefix, itend, reverse},
   266  		index:   -1,
   267  		keys:    keys,
   268  		reverse: reverse,
   269  		db:      db,
   270  	}
   271  }
   272  
   273  func (dbit *ssDBIt) Close() {
   274  	dbit.keys = []string{}
   275  }
   276  
   277  // 获取下一页的数据
   278  func (dbit *ssDBIt) cacheNextPage(begin string) bool {
   279  	if dbit.initKeys(begin, dbit.end) {
   280  		dbit.index = 0
   281  		dbit.pageNo++
   282  		return true
   283  	}
   284  	return false
   285  
   286  }
   287  
   288  func (dbit *ssDBIt) initKeys(begin, end string) bool {
   289  	var (
   290  		keys []string
   291  		err  error
   292  	)
   293  	if dbit.reverse {
   294  		keys, err = dbit.db.pool.get().Rkeys(begin, end, IteratorPageSize)
   295  	} else {
   296  		keys, err = dbit.db.pool.get().Keys(begin, end, IteratorPageSize)
   297  	}
   298  	if err != nil {
   299  		dlog.Error("get iterator next page error", "error", err, "begin", begin, "end", dbit.end, "reverse", dbit.reverse)
   300  		return false
   301  	}
   302  
   303  	if len(keys) > 0 {
   304  		// 这里只改变keys,不改变index
   305  		dbit.keys = keys
   306  
   307  		// 如果返回的数据大小刚好满足分页,则假设下一页还有数据
   308  		if len(keys) == IteratorPageSize {
   309  			dbit.nextPage = true
   310  			dbit.tmpEnd = dbit.keys[IteratorPageSize-1]
   311  		} else {
   312  			dbit.nextPage = false
   313  		}
   314  		return true
   315  	}
   316  	return false
   317  
   318  }
   319  
   320  func (dbit *ssDBIt) Next() bool {
   321  	if len(dbit.keys) > dbit.index+1 {
   322  		dbit.index++
   323  		return true
   324  	}
   325  	// 如果有下一页数据,则自动抓取
   326  	if dbit.nextPage {
   327  		return dbit.cacheNextPage(dbit.tmpEnd)
   328  	}
   329  	return false
   330  
   331  }
   332  
   333  func (dbit *ssDBIt) checkKeyCmp(key1, key2 string, reverse bool) bool {
   334  	if reverse {
   335  		return strings.Compare(key1, key2) < 0
   336  	}
   337  	return strings.Compare(key1, key2) > 0
   338  }
   339  
   340  func (dbit *ssDBIt) findInPage(key string) int {
   341  	pos := -1
   342  	for i, v := range dbit.keys {
   343  		if i < dbit.index {
   344  			continue
   345  		}
   346  		if dbit.checkKeyCmp(key, v, dbit.reverse) {
   347  			continue
   348  		} else {
   349  			pos = i
   350  			break
   351  		}
   352  	}
   353  	return pos
   354  }
   355  
   356  func (dbit *ssDBIt) Seek(key []byte) bool {
   357  	keyStr := string(key)
   358  	pos := dbit.findInPage(keyStr)
   359  
   360  	// 如果第一页已经找到,不会走入此逻辑
   361  	for pos == -1 && dbit.nextPage {
   362  		if dbit.cacheNextPage(dbit.tmpEnd) {
   363  			pos = dbit.findInPage(keyStr)
   364  		} else {
   365  			break
   366  		}
   367  	}
   368  
   369  	dbit.index = pos
   370  	return dbit.Valid()
   371  }
   372  
   373  func (dbit *ssDBIt) Rewind() bool {
   374  	// 目前代码的Rewind调用都是在第一页,正常情况下走不到else分支;
   375  	// 但为了代码健壮性考虑,这里增加对else分支的处理
   376  	if dbit.pageNo == 0 {
   377  		dbit.index = 0
   378  		return true
   379  	}
   380  
   381  	// 当数据取到第N页的情况时,Rewind需要返回到第一页第一条
   382  	if dbit.initKeys(dbit.begin, dbit.end) {
   383  		dbit.index = 0
   384  		dbit.pageNo = 0
   385  		return true
   386  	}
   387  	return false
   388  
   389  }
   390  
   391  func (dbit *ssDBIt) Key() []byte {
   392  	if dbit.index >= 0 && dbit.index < len(dbit.keys) {
   393  		return []byte(dbit.keys[dbit.index])
   394  	}
   395  	return nil
   396  
   397  }
   398  func (dbit *ssDBIt) Value() []byte {
   399  	key := dbit.keys[dbit.index]
   400  	value, err := dbit.db.Get([]byte(key))
   401  
   402  	if err != nil {
   403  		dlog.Error("get iterator value error", "key", key, "error", err)
   404  		return nil
   405  	}
   406  	return value
   407  }
   408  
   409  func (dbit *ssDBIt) Error() error {
   410  	return nil
   411  }
   412  
   413  func (dbit *ssDBIt) ValueCopy() []byte {
   414  	v := dbit.Value()
   415  	value := make([]byte, len(v))
   416  	copy(value, v)
   417  	return value
   418  }
   419  
   420  func (dbit *ssDBIt) Valid() bool {
   421  	start := time.Now()
   422  	if dbit.index < 0 {
   423  		return false
   424  	}
   425  	if len(dbit.keys) <= dbit.index {
   426  		return false
   427  	}
   428  	key := dbit.keys[dbit.index]
   429  	sdbBench.read(1, time.Since(start))
   430  	return dbit.checkKey([]byte(key))
   431  }
   432  
   433  type ssDBBatch struct {
   434  	db       *GoSSDB
   435  	batchset map[string][]byte
   436  	batchdel map[string]bool
   437  	size     int
   438  }
   439  
   440  //NewBatch new
   441  func (db *GoSSDB) NewBatch(sync bool) Batch {
   442  	return &ssDBBatch{db: db, batchset: make(map[string][]byte), batchdel: make(map[string]bool)}
   443  }
   444  
   445  func (db *ssDBBatch) Set(key, value []byte) {
   446  	db.batchset[string(key)] = value
   447  	delete(db.batchdel, string(key))
   448  	db.size += len(value)
   449  	db.size += len(key)
   450  }
   451  
   452  func (db *ssDBBatch) Delete(key []byte) {
   453  	db.batchset[string(key)] = []byte{}
   454  	delete(db.batchset, string(key))
   455  	db.batchdel[string(key)] = true
   456  	db.size += len(key)
   457  }
   458  
   459  // 注意本方法的实现逻辑,因为ssdb没有提供删除和更新同时进行的批量操作;
   460  // 所以这里先执行更新操作(删除的KEY在这里会将VALUE设置为空);
   461  // 然后再执行删除操作;
   462  // 这样即使中间执行出错,也不会导致删除结果未写入的情况(值已经被置空);
   463  func (db *ssDBBatch) Write() error {
   464  	start := time.Now()
   465  
   466  	if len(db.batchset) > 0 {
   467  		err := db.db.pool.get().MultiSet(db.batchset)
   468  		if err != nil {
   469  			dlog.Error("Write (multi_set)", "error", err)
   470  			return err
   471  		}
   472  	}
   473  
   474  	if len(db.batchdel) > 0 {
   475  		var dkeys []string
   476  		for k := range db.batchdel {
   477  			dkeys = append(dkeys, k)
   478  		}
   479  		err := db.db.pool.get().MultiDel(dkeys...)
   480  		if err != nil {
   481  			dlog.Error("Write (multi_del)", "error", err)
   482  			return err
   483  		}
   484  	}
   485  
   486  	sdbBench.write(len(db.batchset)+len(db.batchdel), time.Since(start))
   487  	return nil
   488  }
   489  
   490  func (db *ssDBBatch) ValueSize() int {
   491  	return db.size
   492  }
   493  
   494  //ValueLen  batch数量
   495  func (db *ssDBBatch) ValueLen() int {
   496  	return len(db.batchset)
   497  }
   498  
   499  func (db *ssDBBatch) Reset() {
   500  	db.batchset = make(map[string][]byte)
   501  	db.batchdel = make(map[string]bool)
   502  	db.size = 0
   503  }
   504  
   505  func (db *ssDBBatch) UpdateWriteSync(sync bool) {
   506  }