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 }