github.com/beyonderyue/gochain@v2.2.26+incompatible/eth/db_upgrade.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package eth implements the GoChain protocol. 18 package eth 19 20 /* 21 import ( 22 "bytes" 23 "time" 24 25 "github.com/gochain-io/gochain/common" 26 "github.com/gochain-io/gochain/core" 27 "github.com/gochain-io/gochain/ethdb" 28 "github.com/gochain-io/gochain/log" 29 "github.com/gochain-io/gochain/rlp" 30 ) 31 32 var deduplicateData = []byte("dbUpgrade_20170714deduplicateData") 33 34 // upgradeDeduplicateData checks the chain database version and 35 // starts a background process to make upgrades if necessary. 36 // Returns a stop function that blocks until the process has 37 // been safely stopped. 38 func upgradeDeduplicateData(db common.Database) func() error { 39 // If the database is already converted or empty, bail out 40 data, _ := db.Get(deduplicateData) 41 if len(data) > 0 && data[0] == 42 { 42 return nil 43 } 44 if data, _ := db.Get([]byte("LastHeader")); len(data) == 0 { 45 if err := db.Put(deduplicateData, []byte{42}); err != nil { 46 log.Error("Cannot update deduplicate data key", "err", err) 47 } 48 return nil 49 } 50 // Start the deduplication upgrade on a new goroutine 51 log.Warn("Upgrading database to use lookup entries") 52 stop := make(chan chan error) 53 54 go func() { 55 // Create an iterator to read the entire database and covert old lookup entires 56 it := db.(*ethdb.LDBDatabase).NewIterator(nil, nil) 57 defer func() { 58 if it != nil { 59 it.Release() 60 } 61 }() 62 63 var ( 64 converted uint64 65 failed error 66 ) 67 for failed == nil && it.Next() { 68 // Skip any entries that don't look like old transaction meta entires (<hash>0x01) 69 key := it.Key() 70 if len(key) != common.HashLength+1 || key[common.HashLength] != 0x01 { 71 continue 72 } 73 // Skip any entries that don't contain metadata (name clash between <hash>0x01 and <some-prefix><hash>) 74 var meta struct { 75 BlockHash common.Hash 76 BlockIndex uint64 77 Index uint64 78 } 79 if err := rlp.DecodeBytes(it.Value(), &meta); err != nil { 80 continue 81 } 82 // Skip any already upgraded entries (clash due to <hash> ending with 0x01 (old suffix)) 83 hash := key[:common.HashLength] 84 85 if hash[0] == byte('l') { 86 // Potential clash, the "old" `hash` must point to a live transaction. 87 if tx, _, _, _ := rawdb.ReadTransaction(db, common.BytesToHash(hash)); tx == nil || !bytes.Equal(tx.Hash().Bytes(), hash) { 88 continue 89 } 90 } 91 // Convert the old metadata to a new lookup entry, delete duplicate data 92 if failed = db.Put(append([]byte("l"), hash...), it.Value()); failed == nil { // Write the new looku entry 93 if failed = db.Delete(hash); failed == nil { // Delete the duplicate transaction data 94 if failed = db.Delete(append([]byte("receipts-"), hash...)); failed == nil { // Delete the duplicate receipt data 95 if failed = db.Delete(key); failed != nil { // Delete the old transaction metadata 96 break 97 } 98 } 99 } 100 } 101 // Bump the conversion counter, and recreate the iterator occasionally to 102 // avoid too high memory consumption. 103 converted++ 104 if converted%100000 == 0 { 105 it.Release() 106 it = db.(*ethdb.LDBDatabase).NewIterator(nil, nil) 107 it.Seek(key) 108 109 log.Info("Deduplicating database entries", "deduped", converted) 110 } 111 // Check for termination, or continue after a bit of a timeout 112 select { 113 case errc := <-stop: 114 errc <- nil 115 return 116 case <-time.After(time.Microsecond * 100): 117 } 118 } 119 // Upgrade finished, mark a such and terminate 120 if failed == nil { 121 log.Info("Database deduplication successful", "deduped", converted) 122 if err := db.Put(deduplicateData, []byte{42}); err != nil { 123 log.Error("Cannot update deduplicate data key on success", "err", err) 124 } 125 } else { 126 log.Error("Database deduplication failed", "deduped", converted, "err", failed) 127 } 128 it.Release() 129 it = nil 130 131 errc := <-stop 132 errc <- failed 133 }() 134 // Assembly the cancellation callback 135 return func() error { 136 errc := make(chan error) 137 stop <- errc 138 return <-errc 139 } 140 } 141 */