github.com/turingchain2020/turingchain@v1.1.21/blockchain/reindex.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 blockchain
     6  
     7  import (
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/turingchain2020/turingchain/common/version"
    12  	"github.com/turingchain2020/turingchain/types"
    13  )
    14  
    15  //UpgradeChain 升级localdb
    16  func (chain *BlockChain) UpgradeChain() {
    17  	meta, err := chain.blockStore.GetUpgradeMeta()
    18  	if err != nil {
    19  		panic(err)
    20  	}
    21  	curheight := chain.GetBlockHeight()
    22  	if curheight == -1 {
    23  		meta = &types.UpgradeMeta{
    24  			Version: version.GetLocalDBVersion(),
    25  		}
    26  		err = chain.blockStore.SetUpgradeMeta(meta)
    27  		if err != nil {
    28  			panic(err)
    29  		}
    30  		return
    31  	}
    32  	start := meta.Height
    33  	v1, _, _ := getLocalDBVersion()
    34  	if chain.needReIndex(meta) {
    35  		//如果没有开始重建index,那么先del all keys
    36  		//reindex 的过程中,会每个高度都去更新meta
    37  		if v1 == 1 {
    38  			if !meta.Starting {
    39  				chainlog.Info("begin del all keys")
    40  				chain.blockStore.delAllKeys()
    41  				chainlog.Info("end del all keys")
    42  			}
    43  			chain.reIndex(start, curheight)
    44  		} else if v1 == 2 {
    45  			//如果节点开启isRecordBlockSequence功能,需要按照seq来升级区块信息
    46  			var isSeq bool
    47  			lastSequence, err := chain.blockStore.LoadBlockLastSequence()
    48  			if err != nil || lastSequence < 0 {
    49  				isSeq = false
    50  			} else {
    51  				curheight = lastSequence
    52  				isSeq = true
    53  			}
    54  			chain.reIndexForTable(start, curheight, isSeq)
    55  		}
    56  		meta := &types.UpgradeMeta{
    57  			Starting: false,
    58  			Version:  version.GetLocalDBVersion(),
    59  			Height:   0,
    60  		}
    61  		err = chain.blockStore.SetUpgradeMeta(meta)
    62  		if err != nil {
    63  			panic(err)
    64  		}
    65  	}
    66  }
    67  
    68  func (chain *BlockChain) reIndex(start, end int64) {
    69  	for i := start; i <= end; i++ {
    70  		err := chain.reIndexOne(i)
    71  		if err != nil {
    72  			panic(err)
    73  		}
    74  	}
    75  }
    76  
    77  func (chain *BlockChain) needReIndex(meta *types.UpgradeMeta) bool {
    78  	if meta.Starting { //正在index
    79  		return true
    80  	}
    81  	v1 := meta.Version
    82  	v2 := version.GetLocalDBVersion()
    83  	v1arr := strings.Split(v1, ".")
    84  	v2arr := strings.Split(v2, ".")
    85  	if len(v1arr) != 3 || len(v2arr) != 3 {
    86  		panic("upgrade meta version error")
    87  	}
    88  	//只支持从低版本升级到高版本
    89  	v1Value, err := strconv.Atoi(v1arr[0])
    90  	if err != nil {
    91  		panic("upgrade meta strconv.Atoi error")
    92  	}
    93  	v2Value, err := strconv.Atoi(v2arr[0])
    94  	if err != nil {
    95  		panic("upgrade meta strconv.Atoi error")
    96  	}
    97  	if v1arr[0] != v2arr[0] && v2Value > v1Value {
    98  		return true
    99  	}
   100  	return false
   101  }
   102  
   103  func (chain *BlockChain) reIndexOne(height int64) error {
   104  	newbatch := chain.blockStore.NewBatch(false)
   105  	blockdetail, err := chain.GetBlock(height)
   106  	if err != nil {
   107  		chainlog.Error("reindexone.GetBlock", "err", err)
   108  		panic(err)
   109  	}
   110  	if height%1000 == 0 {
   111  		chainlog.Info("reindex -> ", "height", height, "lastheight", chain.GetBlockHeight())
   112  	}
   113  	//保存tx信息到db中(newbatch, blockdetail)
   114  	err = chain.blockStore.AddTxs(newbatch, blockdetail)
   115  	if err != nil {
   116  		chainlog.Error("reIndexOne indexTxs:", "height", blockdetail.Block.Height, "err", err)
   117  		panic(err)
   118  	}
   119  	meta := &types.UpgradeMeta{
   120  		Starting: true,
   121  		Version:  version.GetLocalDBVersion(),
   122  		Height:   height + 1,
   123  	}
   124  	newbatch.Set(version.LocalDBMeta, types.Encode(meta))
   125  	return newbatch.Write()
   126  }
   127  
   128  func (chain *BlockChain) reIndexForTable(start, end int64, isSeq bool) {
   129  	for i := start; i <= end; i++ {
   130  		err := chain.reIndexForTableOne(i, end, isSeq)
   131  		if err != nil {
   132  			panic(err)
   133  		}
   134  	}
   135  	chainlog.Info("reindex:reIndexForTable:complete")
   136  }
   137  
   138  //使用table的方式保存block的header和body以及paratx信息,
   139  //然后删除对应的bodyPrefix, headerPrefix, heightToHeaderPrefix,key值
   140  //需要区分是按照seq还是height来升级block
   141  func (chain *BlockChain) reIndexForTableOne(index int64, lastindex int64, isSeq bool) error {
   142  	newbatch := chain.blockStore.NewBatch(false)
   143  	var blockdetail *types.BlockDetail
   144  	var err error
   145  	blockOptType := types.AddBlock
   146  
   147  	if isSeq {
   148  		blockdetail, blockOptType, err = chain.blockStore.loadBlockBySequenceOld(index)
   149  	} else {
   150  		blockdetail, err = chain.blockStore.loadBlockByHeightOld(index)
   151  	}
   152  	if err != nil {
   153  		chainlog.Error("reindex:reIndexForTable:load Block Err", "index", index, "isSeq", isSeq, "err", err)
   154  		panic(err)
   155  	}
   156  	height := blockdetail.Block.GetHeight()
   157  	hash := blockdetail.Block.Hash(chain.client.GetConfig())
   158  	curHeight := chain.GetBlockHeight()
   159  
   160  	//只重构add时区块的存储方式,del时只需要删除对应区块上的平行链标记即可
   161  	if blockOptType == types.AddBlock {
   162  		if index%1000 == 0 {
   163  			chainlog.Info("reindex -> ", "index", index, "lastindex", lastindex, "isSeq", isSeq)
   164  		}
   165  
   166  		saveReceipt := true
   167  		// 精简localdb,情况下直接不对 blockReceipt做保存
   168  		if chain.client.GetConfig().IsEnable("reduceLocaldb") && curHeight-SafetyReduceHeight > height {
   169  			saveReceipt = false
   170  		}
   171  		//使用table格式保存header和body以及paratx标识
   172  		err = chain.blockStore.saveBlockForTable(newbatch, blockdetail, true, saveReceipt)
   173  		if err != nil {
   174  			chainlog.Error("reindex:reIndexForTable", "height", height, "isSeq", isSeq, "err", err)
   175  			panic(err)
   176  		}
   177  
   178  		//删除旧的用于存储header和body的key值
   179  		newbatch.Delete(calcHashToBlockHeaderKey(hash))
   180  		newbatch.Delete(calcHashToBlockBodyKey(hash))
   181  		newbatch.Delete(calcHeightToBlockHeaderKey(height))
   182  
   183  		// 精简localdb
   184  		if chain.client.GetConfig().IsEnable("reduceLocaldb") && curHeight-SafetyReduceHeight > height {
   185  			chain.reduceIndexTx(newbatch, blockdetail.GetBlock())
   186  			newbatch.Set(types.ReduceLocaldbHeight, types.Encode(&types.Int64{Data: height}))
   187  		}
   188  	} else {
   189  		parakvs, _ := delParaTxTable(chain.blockStore.db, height)
   190  		for _, kv := range parakvs {
   191  			if len(kv.GetKey()) != 0 && kv.GetValue() == nil {
   192  				newbatch.Delete(kv.GetKey())
   193  			}
   194  		}
   195  		// 精简localdb,为了提升效率,所有索引tx均生成,而不从数据库中读取,因此需要删除侧链生成的tx
   196  		if chain.client.GetConfig().IsEnable("reduceLocaldb") && curHeight-SafetyReduceHeight > height {
   197  			chain.deleteTx(newbatch, blockdetail.GetBlock())
   198  		}
   199  	}
   200  
   201  	meta := &types.UpgradeMeta{
   202  		Starting: true,
   203  		Version:  version.GetLocalDBVersion(),
   204  		Height:   index + 1,
   205  	}
   206  	newbatch.Set(version.LocalDBMeta, types.Encode(meta))
   207  
   208  	return newbatch.Write()
   209  }
   210  
   211  //返回当前版本的V1,V2,V3的值
   212  func getLocalDBVersion() (int, int, int) {
   213  
   214  	version := version.GetLocalDBVersion()
   215  	vArr := strings.Split(version, ".")
   216  	if len(vArr) != 3 {
   217  		panic("getLocalDBVersion version error")
   218  	}
   219  	v1, _ := strconv.Atoi(vArr[0])
   220  	v2, _ := strconv.Atoi(vArr[1])
   221  	v3, _ := strconv.Atoi(vArr[2])
   222  
   223  	return v1, v2, v3
   224  }