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 }