github.com/turingchain2020/turingchain@v1.1.21/system/store/mavl/db/prune.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 mavl
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"sync"
    11  
    12  	"runtime"
    13  	"sync/atomic"
    14  	"time"
    15  
    16  	"strconv"
    17  
    18  	"github.com/turingchain2020/turingchain/common"
    19  	dbm "github.com/turingchain2020/turingchain/common/db"
    20  	"github.com/turingchain2020/turingchain/types"
    21  	"github.com/golang/protobuf/proto"
    22  )
    23  
    24  const (
    25  	leafKeyCountPrefix     = "..mk.."
    26  	oldLeafKeyCountPrefix  = "..mok.."
    27  	secLvlPruningHeightKey = "_..mslphk.._"
    28  	blockHeightStrLen      = 10
    29  	hashLenStr             = 3
    30  	pruningStateStart      = 1
    31  	pruningStateEnd        = 0
    32  	//二级裁剪高度,达到此高度未裁剪则放入该处
    33  	secondLevelPruningHeight = 500000
    34  	//三级裁剪高度,达到此高度还没有裁剪,则不进行裁剪
    35  	threeLevelPruningHeight = 1500000
    36  	onceScanCount           = 10000 // 单次扫描数目
    37  	onceCount               = 1000  // 容器长度
    38  	batchDataSize           = 1024 * 1024 * 1
    39  	//DefaultPruneHeight ...
    40  	DefaultPruneHeight = 10000
    41  )
    42  
    43  var (
    44  	// 裁剪状态
    45  	pruningState   int32
    46  	wg             sync.WaitGroup
    47  	quit           bool
    48  	secLvlPruningH int64
    49  )
    50  
    51  type hashData struct {
    52  	height int64
    53  	hash   []byte
    54  }
    55  
    56  // ClosePrune 关闭裁剪
    57  func ClosePrune() {
    58  	quit = true
    59  	wg.Wait()
    60  	//防止BaseStore没有关闭再次进入
    61  	setPruning(pruningStateStart)
    62  }
    63  
    64  func genLeafCountKey(key, hash []byte, height int64, hashLen int) (hashkey []byte) {
    65  	hashkey = []byte(fmt.Sprintf("%s%s%010d%s%03d", leafKeyCountPrefix, string(key), height, string(hash), hashLen))
    66  	return hashkey
    67  }
    68  
    69  func getKeyHeightFromLeafCountKey(hashkey []byte) (key []byte, height int, hash []byte, err error) {
    70  	if len(hashkey) < len(leafKeyCountPrefix)+blockHeightStrLen+sha256Len+hashLenStr {
    71  		return nil, 0, nil, types.ErrSize
    72  	}
    73  	if !bytes.Contains(hashkey, []byte(leafKeyCountPrefix)) {
    74  		return nil, 0, nil, types.ErrSize
    75  	}
    76  	sLen := hashkey[len(hashkey)-hashLenStr:]
    77  	iLen, err := strconv.Atoi(string(sLen))
    78  	if err != nil {
    79  		return nil, 0, nil, types.ErrSize
    80  	}
    81  	k := bytes.TrimPrefix(hashkey, []byte(leafKeyCountPrefix))
    82  	key = k[:len(k)-iLen-blockHeightStrLen-hashLenStr]
    83  	//keyHeighthash
    84  	heightHash := k[len(key) : len(k)-hashLenStr]
    85  	sHeight := heightHash[:blockHeightStrLen]
    86  	height, err = strconv.Atoi(string(sHeight))
    87  	if err != nil {
    88  		return nil, 0, nil, types.ErrSize
    89  	}
    90  	hash = heightHash[blockHeightStrLen:]
    91  	return key, height, hash, nil
    92  }
    93  
    94  func genOldLeafCountKey(key, hash []byte, height int64, hashLen int) (hashkey []byte) {
    95  	hashkey = []byte(fmt.Sprintf("%s%s%010d%s%03d", oldLeafKeyCountPrefix, string(key), height, string(hash), hashLen))
    96  	return hashkey
    97  }
    98  
    99  func getKeyHeightFromOldLeafCountKey(hashkey []byte) (key []byte, height int, hash []byte, err error) {
   100  	if len(hashkey) < len(oldLeafKeyCountPrefix)+blockHeightStrLen+sha256Len+hashLenStr {
   101  		return nil, 0, nil, types.ErrSize
   102  	}
   103  	if !bytes.Contains(hashkey, []byte(oldLeafKeyCountPrefix)) {
   104  		return nil, 0, nil, types.ErrSize
   105  	}
   106  	sLen := hashkey[len(hashkey)-hashLenStr:]
   107  	iLen, err := strconv.Atoi(string(sLen))
   108  	if err != nil {
   109  		return nil, 0, nil, types.ErrSize
   110  	}
   111  	k := bytes.TrimPrefix(hashkey, []byte(oldLeafKeyCountPrefix))
   112  	key = k[:len(k)-iLen-blockHeightStrLen-hashLenStr]
   113  	//keyHeighthash
   114  	heightHash := k[len(key) : len(k)-hashLenStr]
   115  	sHeight := heightHash[:blockHeightStrLen]
   116  	height, err = strconv.Atoi(string(sHeight))
   117  	if err != nil {
   118  		return nil, 0, nil, types.ErrSize
   119  	}
   120  	hash = heightHash[blockHeightStrLen:]
   121  	return key, height, hash, nil
   122  }
   123  
   124  func genOldLeafCountKeyFromKey(hashk []byte) (oldhashk []byte) {
   125  	if len(hashk) < len(leafKeyCountPrefix) {
   126  		return hashk
   127  	}
   128  	oldhashk = []byte(fmt.Sprintf("%s%s", oldLeafKeyCountPrefix, string(hashk[len(leafKeyCountPrefix):])))
   129  	return oldhashk
   130  }
   131  
   132  func isPruning() bool {
   133  	return atomic.LoadInt32(&pruningState) == 1
   134  }
   135  
   136  func setPruning(state int32) {
   137  	atomic.StoreInt32(&pruningState, state)
   138  }
   139  
   140  func getSecLvlPruningHeight(db dbm.DB) int64 {
   141  	value, err := db.Get([]byte(secLvlPruningHeightKey))
   142  	if len(value) == 0 || err != nil {
   143  		return 0
   144  	}
   145  	h := &types.Int64{}
   146  	err = proto.Unmarshal(value, h)
   147  	if err != nil {
   148  		return 0
   149  	}
   150  	return h.Data
   151  }
   152  
   153  func setSecLvlPruningHeight(db dbm.DB, height int64) error {
   154  	h := &types.Int64{}
   155  	h.Data = height
   156  	value, err := proto.Marshal(h)
   157  	if err != nil {
   158  		return err
   159  	}
   160  	return db.Set([]byte(secLvlPruningHeightKey), value)
   161  }
   162  
   163  func pruning(db dbm.DB, curHeight int64, treeCfg *TreeConfig) {
   164  	defer wg.Done()
   165  	pruningTree(db, curHeight, treeCfg)
   166  }
   167  
   168  func pruningTree(db dbm.DB, curHeight int64, treeCfg *TreeConfig) {
   169  	setPruning(pruningStateStart)
   170  	// 一级遍历
   171  	pruningFirstLevel(db, curHeight, treeCfg)
   172  	// 二级遍历
   173  	pruningSecondLevel(db, curHeight, treeCfg)
   174  	setPruning(pruningStateEnd)
   175  }
   176  
   177  func pruningFirstLevel(db dbm.DB, curHeight int64, treeCfg *TreeConfig) {
   178  	treelog.Info("pruningTree pruningFirstLevel", "start curHeight:", curHeight)
   179  	start := time.Now()
   180  	pruningFirstLevelNode(db, curHeight, treeCfg)
   181  	end := time.Now()
   182  	treelog.Info("pruningTree pruningFirstLevel", "curHeight:", curHeight, "pruning leafNode cost time:", end.Sub(start))
   183  }
   184  
   185  func pruningFirstLevelNode(db dbm.DB, curHeight int64, treeCfg *TreeConfig) {
   186  	prefix := []byte(leafKeyCountPrefix)
   187  	it := db.Iterator(prefix, nil, true)
   188  	defer it.Close()
   189  
   190  	var mp map[string][]hashData
   191  	var kvs []*types.KeyValue
   192  	count := 0
   193  	batch := db.NewBatch(true)
   194  	for it.Rewind(); it.Valid(); it.Next() {
   195  		if quit {
   196  			//该处退出
   197  			return
   198  		}
   199  		if mp == nil {
   200  			mp = make(map[string][]hashData, onceCount)
   201  		}
   202  		//copy key
   203  		hashK := make([]byte, len(it.Key()))
   204  		copy(hashK, it.Key())
   205  
   206  		key, height, hash, err := getKeyHeightFromLeafCountKey(hashK)
   207  		if err != nil {
   208  			continue
   209  		}
   210  		if curHeight < int64(height)+secondLevelPruningHeight {
   211  			if curHeight >= int64(height)+int64(treeCfg.PruneHeight) {
   212  				data := hashData{
   213  					height: int64(height),
   214  					hash:   hash,
   215  				}
   216  				mp[string(key)] = append(mp[string(key)], data)
   217  				count++
   218  			}
   219  		} else {
   220  			value := make([]byte, len(it.Value()))
   221  			copy(value, it.Value())
   222  			kvs = append(kvs, &types.KeyValue{Key: hashK, Value: value})
   223  		}
   224  		if len(mp) >= onceCount-1 || count > onceScanCount {
   225  			deleteNode(db, mp, curHeight, batch, treeCfg)
   226  			mp = nil
   227  			count = 0
   228  		}
   229  		if len(kvs) >= onceCount {
   230  			addLeafCountKeyToSecondLevel(db, kvs, batch)
   231  			kvs = kvs[:0]
   232  		}
   233  	}
   234  	if len(mp) > 0 {
   235  		deleteNode(db, mp, curHeight, batch, treeCfg)
   236  		mp = nil
   237  		_ = mp
   238  	}
   239  	if len(kvs) > 0 {
   240  		addLeafCountKeyToSecondLevel(db, kvs, batch)
   241  	}
   242  }
   243  
   244  func addLeafCountKeyToSecondLevel(db dbm.DB, kvs []*types.KeyValue, batch dbm.Batch) {
   245  	batch.Reset()
   246  	for _, kv := range kvs {
   247  		batch.Delete(kv.Key)
   248  		batch.Set(genOldLeafCountKeyFromKey(kv.Key), kv.Value)
   249  		if batch.ValueSize() > batchDataSize {
   250  			dbm.MustWrite(batch)
   251  			batch.Reset()
   252  		}
   253  	}
   254  	dbm.MustWrite(batch)
   255  }
   256  
   257  func deleteNode(db dbm.DB, mp map[string][]hashData, curHeight int64, batch dbm.Batch, treeCfg *TreeConfig) {
   258  	if len(mp) == 0 {
   259  		return
   260  	}
   261  	batch.Reset()
   262  	for key, vals := range mp {
   263  		if len(vals) > 1 && vals[1].height != vals[0].height { //防止相同高度时候出现的误删除
   264  			for _, val := range vals[1:] { //从第二个开始判断
   265  				if curHeight >= val.height+int64(treeCfg.PruneHeight) {
   266  					leafCountKey := genLeafCountKey([]byte(key), val.hash, val.height, len(val.hash))
   267  					value, err := db.Get(leafCountKey)
   268  					if err == nil {
   269  						var pData types.PruneData
   270  						err := proto.Unmarshal(value, &pData)
   271  						if err == nil {
   272  							for _, hash := range pData.Hashs {
   273  								batch.Delete(hash)
   274  							}
   275  						}
   276  					}
   277  					batch.Delete(leafCountKey) // 叶子计数节点
   278  					batch.Delete(val.hash)     // 叶子节点hash值
   279  					if batch.ValueSize() > batchDataSize {
   280  						dbm.MustWrite(batch)
   281  						batch.Reset()
   282  					}
   283  				}
   284  			}
   285  		}
   286  		delete(mp, key)
   287  	}
   288  	dbm.MustWrite(batch)
   289  }
   290  
   291  func pruningSecondLevel(db dbm.DB, curHeight int64, treeCfg *TreeConfig) {
   292  	if secLvlPruningH == 0 {
   293  		secLvlPruningH = getSecLvlPruningHeight(db)
   294  	}
   295  	if curHeight/secondLevelPruningHeight > 1 &&
   296  		curHeight/secondLevelPruningHeight != secLvlPruningH/secondLevelPruningHeight {
   297  		treelog.Info("pruningTree pruningSecondLevel", "start curHeight:", curHeight)
   298  		start := time.Now()
   299  		pruningSecondLevelNode(db, curHeight, treeCfg)
   300  		end := time.Now()
   301  		treelog.Info("pruningTree pruningSecondLevel", "curHeight:", curHeight, "pruning leafNode cost time:", end.Sub(start))
   302  		err := setSecLvlPruningHeight(db, curHeight)
   303  		if err != nil {
   304  			return
   305  		}
   306  		secLvlPruningH = curHeight
   307  	}
   308  }
   309  
   310  func pruningSecondLevelNode(db dbm.DB, curHeight int64, treeCfg *TreeConfig) {
   311  	prefix := []byte(oldLeafKeyCountPrefix)
   312  	it := db.Iterator(prefix, nil, true)
   313  	defer it.Close()
   314  
   315  	var mp map[string][]hashData
   316  	count := 0
   317  	batch := db.NewBatch(true)
   318  	for it.Rewind(); it.Valid(); it.Next() {
   319  		if quit {
   320  			//该处退出
   321  			return
   322  		}
   323  		if mp == nil {
   324  			mp = make(map[string][]hashData, onceCount)
   325  		}
   326  		//copy key
   327  		hashK := make([]byte, len(it.Key()))
   328  		copy(hashK, it.Key())
   329  		key, height, hash, err := getKeyHeightFromOldLeafCountKey(hashK)
   330  		if err == nil {
   331  			data := hashData{
   332  				height: int64(height),
   333  				hash:   hash,
   334  			}
   335  			mp[string(key)] = append(mp[string(key)], data)
   336  			count++
   337  			if len(mp) >= onceCount-1 || count > onceScanCount {
   338  				deleteOldNode(db, mp, curHeight, batch, treeCfg)
   339  				mp = nil
   340  				count = 0
   341  			}
   342  		}
   343  	}
   344  	if len(mp) > 0 {
   345  		deleteOldNode(db, mp, curHeight, batch, treeCfg)
   346  		mp = nil
   347  		_ = mp
   348  	}
   349  }
   350  
   351  func deleteOldNode(db dbm.DB, mp map[string][]hashData, curHeight int64, batch dbm.Batch, treeCfg *TreeConfig) {
   352  	if len(mp) == 0 {
   353  		return
   354  	}
   355  	batch.Reset()
   356  	for key, vals := range mp {
   357  		if len(vals) > 1 {
   358  			if vals[1].height != vals[0].height { //防止相同高度时候出现的误删除
   359  				for _, val := range vals[1:] { //从第二个开始判断
   360  					if curHeight >= val.height+int64(treeCfg.PruneHeight) {
   361  						leafCountKey := genOldLeafCountKey([]byte(key), val.hash, val.height, len(val.hash))
   362  						value, err := db.Get(leafCountKey)
   363  						if err == nil {
   364  							var pData types.PruneData
   365  							err := proto.Unmarshal(value, &pData)
   366  							if err == nil {
   367  								for _, hash := range pData.Hashs {
   368  									batch.Delete(hash)
   369  								}
   370  							}
   371  						}
   372  						batch.Delete(leafCountKey)
   373  						batch.Delete(val.hash) // 叶子节点hash值
   374  					}
   375  				}
   376  			} else {
   377  				// 删除第三层存储索引key
   378  				for _, val := range vals {
   379  					if curHeight >= val.height+threeLevelPruningHeight {
   380  						batch.Delete(genOldLeafCountKey([]byte(key), val.hash, val.height, len(val.hash)))
   381  					}
   382  				}
   383  			}
   384  		} else if len(vals) == 1 && curHeight >= vals[0].height+threeLevelPruningHeight { // 删除第三层存储索引key
   385  			batch.Delete(genOldLeafCountKey([]byte(key), vals[0].hash, vals[0].height, len(vals[0].hash)))
   386  		}
   387  		delete(mp, key)
   388  		if batch.ValueSize() > batchDataSize {
   389  			dbm.MustWrite(batch)
   390  			batch.Reset()
   391  		}
   392  	}
   393  	dbm.MustWrite(batch)
   394  }
   395  
   396  // PruningTreePrintDB pruning tree print db
   397  func PruningTreePrintDB(db dbm.DB, prefix []byte) {
   398  	it := db.Iterator(prefix, nil, true)
   399  	defer it.Close()
   400  	count := 0
   401  	for it.Rewind(); it.Valid(); it.Next() {
   402  		if bytes.Equal(prefix, []byte(leafKeyCountPrefix)) {
   403  			hashK := it.Key()
   404  			value := it.Value()
   405  			var pData types.PruneData
   406  			err := proto.Unmarshal(value, &pData)
   407  			if err == nil {
   408  				key, height, _, err := getKeyHeightFromLeafCountKey(hashK)
   409  				if err == nil {
   410  					treelog.Debug("pruningTree:", "key:", string(key), "height", height)
   411  				}
   412  			}
   413  		} else if bytes.Equal(prefix, []byte(hashNodePrefix)) {
   414  			treelog.Debug("pruningTree:", "key:", string(it.Key()))
   415  		} else if bytes.Equal(prefix, []byte(leafNodePrefix)) {
   416  			treelog.Debug("pruningTree:", "key:", string(it.Key()))
   417  		}
   418  		count++
   419  	}
   420  	fmt.Printf("prefix %s All count:%d \n", string(prefix), count)
   421  	treelog.Info("pruningTree:", "prefix:", string(prefix), "All count", count)
   422  }
   423  
   424  // PrintSameLeafKey 查询相同的叶子节点
   425  func PrintSameLeafKey(db dbm.DB, key string) {
   426  	printSameLeafKeyDB(db, key, false)
   427  	printSameLeafKeyDB(db, key, true)
   428  }
   429  
   430  func printSameLeafKeyDB(db dbm.DB, key string, isold bool) {
   431  	var prifex string
   432  	if isold {
   433  		prifex = oldLeafKeyCountPrefix
   434  	} else {
   435  		prifex = leafKeyCountPrefix
   436  	}
   437  	priKey := []byte(fmt.Sprintf("%s%s", prifex, key))
   438  
   439  	it := db.Iterator(priKey, nil, true)
   440  	defer it.Close()
   441  
   442  	for it.Rewind(); it.Valid(); it.Next() {
   443  		hashK := make([]byte, len(it.Key()))
   444  		copy(hashK, it.Key())
   445  
   446  		key, height, hash, err := getKeyHeightFromLeafCountKey(hashK)
   447  		if err == nil {
   448  			pri := ""
   449  			if len(hash) > 32 {
   450  				pri = string(hash[:16])
   451  			}
   452  			treelog.Info("leaf node", "height", height, "pri", pri, "hash", common.ToHex(hash), "key", string(key))
   453  		}
   454  	}
   455  }
   456  
   457  // PrintLeafNodeParent 查询叶子节点的父节点
   458  func PrintLeafNodeParent(db dbm.DB, key, hash []byte, height int64) {
   459  	var isHave bool
   460  	leafCountKey := genLeafCountKey(key, hash, height, len(hash))
   461  	value, err := db.Get(leafCountKey)
   462  	if err == nil {
   463  		var pData types.PruneData
   464  		err := proto.Unmarshal(value, &pData)
   465  		if err == nil {
   466  			for _, hash := range pData.Hashs {
   467  				var pri string
   468  				if len(hash) > 32 {
   469  					pri = string(hash[:16])
   470  				}
   471  				treelog.Info("hash node", "hash pri", pri, "hash", common.ToHex(hash))
   472  			}
   473  		}
   474  		isHave = true
   475  	}
   476  
   477  	if !isHave {
   478  		oldLeafCountKey := genOldLeafCountKey(key, hash, height, len(hash))
   479  		value, err = db.Get(oldLeafCountKey)
   480  		if err == nil {
   481  			var pData types.PruneData
   482  			err := proto.Unmarshal(value, &pData)
   483  			if err == nil {
   484  				for _, hash := range pData.Hashs {
   485  					var pri string
   486  					if len(hash) > 32 {
   487  						pri = string(hash[:16])
   488  					}
   489  					treelog.Info("hash node", "hash pri", pri, "hash", common.ToHex(hash))
   490  				}
   491  			}
   492  			isHave = true
   493  		}
   494  	}
   495  
   496  	if !isHave {
   497  		treelog.Info("err", "get db", "not exist in db")
   498  	}
   499  }
   500  
   501  // PrintNodeDb 查询hash节点以及其子节点
   502  func PrintNodeDb(db dbm.DB, hash []byte) {
   503  	nDb := newNodeDB(db, true)
   504  	node, err := nDb.GetNode(nil, hash)
   505  	if err != nil {
   506  		fmt.Println("err", err)
   507  		return
   508  	}
   509  	pri := ""
   510  	if len(node.hash) > 32 {
   511  		pri = string(node.hash[:16])
   512  	}
   513  	treelog.Info("hash node", "hash pri", pri, "hash", common.ToHex(node.hash), "height", node.height)
   514  	node.printNodeInfo(nDb)
   515  }
   516  
   517  func (node *Node) printNodeInfo(db *nodeDB) {
   518  	if node.height == 0 {
   519  		pri := ""
   520  		if len(node.hash) > 32 {
   521  			pri = string(node.hash[:16])
   522  		}
   523  		treelog.Info("leaf node", "hash pri", pri, "hash", common.ToHex(node.hash), "key", string(node.key))
   524  		return
   525  	}
   526  	if node.leftHash != nil {
   527  		left, err := db.GetNode(nil, node.leftHash)
   528  		if err != nil {
   529  			return
   530  		}
   531  		pri := ""
   532  		if len(left.hash) > 32 {
   533  			pri = string(left.hash[:16])
   534  		}
   535  		treelog.Debug("hash node", "hash pri", pri, "hash", common.ToHex(left.hash), "height", left.height)
   536  		left.printNodeInfo(db)
   537  	}
   538  
   539  	if node.rightHash != nil {
   540  		right, err := db.GetNode(nil, node.rightHash)
   541  		if err != nil {
   542  			return
   543  		}
   544  		pri := ""
   545  		if len(right.hash) > 32 {
   546  			pri = string(right.hash[:16])
   547  		}
   548  		treelog.Debug("hash node", "hash pri", pri, "hash", common.ToHex(right.hash), "height", right.height)
   549  		right.printNodeInfo(db)
   550  	}
   551  }
   552  
   553  // PruningTree 裁剪树
   554  func PruningTree(db dbm.DB, curHeight int64, treeCfg *TreeConfig) {
   555  	pruningTree(db, curHeight, treeCfg)
   556  }
   557  
   558  // PrintMemStats 打印内存使用情况
   559  func PrintMemStats(height int64) {
   560  	var m runtime.MemStats
   561  	runtime.ReadMemStats(&m)
   562  	treelog.Info("printMemStats:", "程序向系统申请", m.HeapSys/(1024*1024), "堆上目前分配Alloc:", m.HeapAlloc/(1024*1024), "堆上没有使用", m.HeapIdle/(1024*1024), "HeapReleased", m.HeapReleased/(1024*1024), "height", height)
   563  }