2
2
// Distributed under the MIT software license, see the accompanying
3
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
4
5
- #include < index/disktxpos.h>
6
5
#include < index/txindex.h>
6
+
7
+ #include < index/disktxpos.h>
7
8
#include < node/blockstorage.h>
8
- #include < node/ui_interface.h>
9
- #include < shutdown.h>
10
9
#include < util/system.h>
11
- #include < util/translation.h>
12
10
#include < validation.h>
13
11
14
- constexpr uint8_t DB_BEST_BLOCK{' B' };
15
12
constexpr uint8_t DB_TXINDEX{' t' };
16
- constexpr uint8_t DB_TXINDEX_BLOCK{' T' };
17
13
18
14
std::unique_ptr<TxIndex> g_txindex;
19
15
@@ -30,10 +26,6 @@ class TxIndex::DB : public BaseIndex::DB
30
26
31
27
// / Write a batch of transaction positions to the DB.
32
28
bool WriteTxs (const std::vector<std::pair<uint256, CDiskTxPos>>& v_pos);
33
-
34
- // / Migrate txindex data from the block tree DB, where it may be for older nodes that have not
35
- // / been upgraded yet to the new database.
36
- bool MigrateData (CBlockTreeDB& block_tree_db, const CBlockLocator& best_locator);
37
29
};
38
30
39
31
TxIndex::DB::DB (size_t n_cache_size, bool f_memory, bool f_wipe) :
@@ -54,163 +46,12 @@ bool TxIndex::DB::WriteTxs(const std::vector<std::pair<uint256, CDiskTxPos>>& v_
54
46
return WriteBatch (batch);
55
47
}
56
48
57
- /*
58
- * Safely persist a transfer of data from the old txindex database to the new one, and compact the
59
- * range of keys updated. This is used internally by MigrateData.
60
- */
61
- static void WriteTxIndexMigrationBatches (CDBWrapper& newdb, CDBWrapper& olddb,
62
- CDBBatch& batch_newdb, CDBBatch& batch_olddb,
63
- const std::pair<uint8_t , uint256>& begin_key,
64
- const std::pair<uint8_t , uint256>& end_key)
65
- {
66
- // Sync new DB changes to disk before deleting from old DB.
67
- newdb.WriteBatch (batch_newdb, /* fSync=*/ true );
68
- olddb.WriteBatch (batch_olddb);
69
- olddb.CompactRange (begin_key, end_key);
70
-
71
- batch_newdb.Clear ();
72
- batch_olddb.Clear ();
73
- }
74
-
75
- bool TxIndex::DB::MigrateData (CBlockTreeDB& block_tree_db, const CBlockLocator& best_locator)
76
- {
77
- // The prior implementation of txindex was always in sync with block index
78
- // and presence was indicated with a boolean DB flag. If the flag is set,
79
- // this means the txindex from a previous version is valid and in sync with
80
- // the chain tip. The first step of the migration is to unset the flag and
81
- // write the chain hash to a separate key, DB_TXINDEX_BLOCK. After that, the
82
- // index entries are copied over in batches to the new database. Finally,
83
- // DB_TXINDEX_BLOCK is erased from the old database and the block hash is
84
- // written to the new database.
85
- //
86
- // Unsetting the boolean flag ensures that if the node is downgraded to a
87
- // previous version, it will not see a corrupted, partially migrated index
88
- // -- it will see that the txindex is disabled. When the node is upgraded
89
- // again, the migration will pick up where it left off and sync to the block
90
- // with hash DB_TXINDEX_BLOCK.
91
- bool f_legacy_flag = false ;
92
- block_tree_db.ReadFlag (" txindex" , f_legacy_flag);
93
- if (f_legacy_flag) {
94
- if (!block_tree_db.Write (DB_TXINDEX_BLOCK, best_locator)) {
95
- return error (" %s: cannot write block indicator" , __func__);
96
- }
97
- if (!block_tree_db.WriteFlag (" txindex" , false )) {
98
- return error (" %s: cannot write block index db flag" , __func__);
99
- }
100
- }
101
-
102
- CBlockLocator locator;
103
- if (!block_tree_db.Read (DB_TXINDEX_BLOCK, locator)) {
104
- return true ;
105
- }
106
-
107
- int64_t count = 0 ;
108
- LogPrintf (" Upgrading txindex database... [0%%]\n " );
109
- uiInterface.ShowProgress (_ (" Upgrading txindex database" ).translated , 0 , true );
110
- int report_done = 0 ;
111
- const size_t batch_size = 1 << 24 ; // 16 MiB
112
-
113
- CDBBatch batch_newdb (*this );
114
- CDBBatch batch_olddb (block_tree_db);
115
-
116
- std::pair<uint8_t , uint256> key;
117
- std::pair<uint8_t , uint256> begin_key{DB_TXINDEX, uint256 ()};
118
- std::pair<uint8_t , uint256> prev_key = begin_key;
119
-
120
- bool interrupted = false ;
121
- std::unique_ptr<CDBIterator> cursor (block_tree_db.NewIterator ());
122
- for (cursor->Seek (begin_key); cursor->Valid (); cursor->Next ()) {
123
- if (ShutdownRequested ()) {
124
- interrupted = true ;
125
- break ;
126
- }
127
-
128
- if (!cursor->GetKey (key)) {
129
- return error (" %s: cannot get key from valid cursor" , __func__);
130
- }
131
- if (key.first != DB_TXINDEX) {
132
- break ;
133
- }
134
-
135
- // Log progress every 10%.
136
- if (++count % 256 == 0 ) {
137
- // Since txids are uniformly random and traversed in increasing order, the high 16 bits
138
- // of the hash can be used to estimate the current progress.
139
- const uint256& txid = key.second ;
140
- uint32_t high_nibble =
141
- (static_cast <uint32_t >(*(txid.begin () + 0 )) << 8 ) +
142
- (static_cast <uint32_t >(*(txid.begin () + 1 )) << 0 );
143
- int percentage_done = (int )(high_nibble * 100.0 / 65536.0 + 0.5 );
144
-
145
- uiInterface.ShowProgress (_ (" Upgrading txindex database" ).translated , percentage_done, true );
146
- if (report_done < percentage_done/10 ) {
147
- LogPrintf (" Upgrading txindex database... [%d%%]\n " , percentage_done);
148
- report_done = percentage_done/10 ;
149
- }
150
- }
151
-
152
- CDiskTxPos value;
153
- if (!cursor->GetValue (value)) {
154
- return error (" %s: cannot parse txindex record" , __func__);
155
- }
156
- batch_newdb.Write (key, value);
157
- batch_olddb.Erase (key);
158
-
159
- if (batch_newdb.SizeEstimate () > batch_size || batch_olddb.SizeEstimate () > batch_size) {
160
- // NOTE: it's OK to delete the key pointed at by the current DB cursor while iterating
161
- // because LevelDB iterators are guaranteed to provide a consistent view of the
162
- // underlying data, like a lightweight snapshot.
163
- WriteTxIndexMigrationBatches (*this , block_tree_db,
164
- batch_newdb, batch_olddb,
165
- prev_key, key);
166
- prev_key = key;
167
- }
168
- }
169
-
170
- // If these final DB batches complete the migration, write the best block
171
- // hash marker to the new database and delete from the old one. This signals
172
- // that the former is fully caught up to that point in the blockchain and
173
- // that all txindex entries have been removed from the latter.
174
- if (!interrupted) {
175
- batch_olddb.Erase (DB_TXINDEX_BLOCK);
176
- batch_newdb.Write (DB_BEST_BLOCK, locator);
177
- }
178
-
179
- WriteTxIndexMigrationBatches (*this , block_tree_db,
180
- batch_newdb, batch_olddb,
181
- begin_key, key);
182
-
183
- if (interrupted) {
184
- LogPrintf (" [CANCELLED].\n " );
185
- return false ;
186
- }
187
-
188
- uiInterface.ShowProgress (" " , 100 , false );
189
-
190
- LogPrintf (" [DONE].\n " );
191
- return true ;
192
- }
193
-
194
49
TxIndex::TxIndex (size_t n_cache_size, bool f_memory, bool f_wipe)
195
50
: m_db(std::make_unique<TxIndex::DB>(n_cache_size, f_memory, f_wipe))
196
51
{}
197
52
198
53
TxIndex::~TxIndex () {}
199
54
200
- bool TxIndex::Init ()
201
- {
202
- LOCK (cs_main);
203
-
204
- // Attempt to migrate txindex from the old database to the new one. Even if
205
- // chain_tip is null, the node could be reindexing and we still want to
206
- // delete txindex records in the old database.
207
- if (!m_db->MigrateData (*m_chainstate->m_blockman .m_block_tree_db , m_chainstate->m_chain .GetLocator ())) {
208
- return false ;
209
- }
210
-
211
- return BaseIndex::Init ();
212
- }
213
-
214
55
bool TxIndex::WriteBlock (const CBlock& block, const CBlockIndex* pindex)
215
56
{
216
57
// Exclude genesis block transaction because outputs are not spendable.
0 commit comments