refactor: data management fixes.

This commit is contained in:
Christopher Jeffrey 2016-09-23 23:40:36 -07:00
parent 1906034106
commit 6589cdc95b
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
6 changed files with 113 additions and 104 deletions

View File

@ -903,7 +903,7 @@ Chain.prototype.setBestChain = co(function* setBestChain(entry, block, prev) {
} }
// Save block and connect inputs. // Save block and connect inputs.
yield this.db.save(entry, block, view, true); yield this.db.save(entry, block, view);
this.tip = entry; this.tip = entry;
this.height = entry.height; this.height = entry.height;
@ -1186,7 +1186,7 @@ Chain.prototype._add = co(function* add(block) {
// our tip's. Add the block but do _not_ // our tip's. Add the block but do _not_
// connect the inputs. // connect the inputs.
if (entry.chainwork.cmp(this.tip.chainwork) <= 0) { if (entry.chainwork.cmp(this.tip.chainwork) <= 0) {
yield this.db.save(entry, block, null, false); yield this.db.save(entry, block);
this.emit('competitor', block, entry); this.emit('competitor', block, entry);

View File

@ -16,6 +16,8 @@ var DUMMY = new Buffer([0]);
var BufferWriter = require('../utils/writer'); var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader'); var BufferReader = require('../utils/reader');
var spawn = require('../utils/spawn'); var spawn = require('../utils/spawn');
var CoinView = require('./coinview');
var Coins = require('./coins');
var co = spawn.co; var co = spawn.co;
/* /*
@ -232,7 +234,7 @@ ChainDB.prototype._open = co(function* open() {
genesis = bcoin.chainentry.fromBlock(this.chain, block); genesis = bcoin.chainentry.fromBlock(this.chain, block);
yield this.save(genesis, block, null, true); yield this.save(genesis, block, new CoinView());
} }
this.logger.info('Chain successfully loaded.'); this.logger.info('Chain successfully loaded.');
@ -544,28 +546,26 @@ ChainDB.prototype.get = co(function* get(hash) {
* instead performed in {@link Chain#add}. * instead performed in {@link Chain#add}.
* @param {ChainEntry} entry * @param {ChainEntry} entry
* @param {Block} block * @param {Block} block
* @param {CoinView} view * @param {CoinView?} view - Will not connect if null.
* @param {Boolean} connect - Whether to connect the
* block's inputs and add it as a tip.
* @returns {Promise} * @returns {Promise}
*/ */
ChainDB.prototype.save = co(function* save(entry, block, view, connect) { ChainDB.prototype.save = co(function* save(entry, block, view) {
var hash = block.hash(); var hash = block.hash();
var height = new Buffer(4); var height = new Buffer(4);
this.start();
height.writeUInt32LE(entry.height, 0, true); height.writeUInt32LE(entry.height, 0, true);
this.start();
this.put(layout.h(hash), height); this.put(layout.h(hash), height);
this.put(layout.e(hash), entry.toRaw()); this.put(layout.e(hash), entry.toRaw());
this.cacheHash.set(entry.hash, entry); this.cacheHash.set(entry.hash, entry);
if (!connect) { if (!view) {
try { try {
yield this.saveBlock(block, view, false); yield this.saveBlock(block);
} catch (e) { } catch (e) {
this.drop(); this.drop();
throw e; throw e;
@ -579,13 +579,14 @@ ChainDB.prototype.save = co(function* save(entry, block, view, connect) {
this.put(layout.H(entry.height), hash); this.put(layout.H(entry.height), hash);
try { try {
yield this.saveBlock(block, view, true); yield this.saveBlock(block, view);
} catch (e) { } catch (e) {
this.drop(); this.drop();
throw e; throw e;
} }
this.put(layout.R, this.pending.commit(hash)); this.put(layout.R, this.pending.commit(hash));
yield this.commit(); yield this.commit();
}); });
@ -814,13 +815,13 @@ ChainDB.prototype.has = co(function* has(height) {
* @returns {Promise} - Returns {@link Block}. * @returns {Promise} - Returns {@link Block}.
*/ */
ChainDB.prototype.saveBlock = co(function* saveBlock(block, view, connect) { ChainDB.prototype.saveBlock = co(function* saveBlock(block, view) {
if (this.options.spv) if (this.options.spv)
return block; return block;
this.put(layout.b(block.hash()), block.toRaw()); this.put(layout.b(block.hash()), block.toRaw());
if (!connect) if (!view)
return block; return block;
yield this.connectBlock(block, view); yield this.connectBlock(block, view);
@ -1107,7 +1108,7 @@ ChainDB.prototype.getCoin = co(function* getCoin(hash, index) {
var coins = this.coinCache.get(hash); var coins = this.coinCache.get(hash);
if (coins) if (coins)
return bcoin.coins.parseCoin(coins, hash, index); return Coins.parseCoin(coins, hash, index);
coins = yield this.db.get(layout.c(hash)); coins = yield this.db.get(layout.c(hash));
@ -1116,7 +1117,7 @@ ChainDB.prototype.getCoin = co(function* getCoin(hash, index) {
this.coinCache.set(hash, coins); this.coinCache.set(hash, coins);
return bcoin.coins.parseCoin(coins, hash, index); return Coins.parseCoin(coins, hash, index);
}); });
/** /**
@ -1129,7 +1130,7 @@ ChainDB.prototype.getCoins = co(function* getCoins(hash) {
var coins = this.coinCache.get(hash); var coins = this.coinCache.get(hash);
if (coins) if (coins)
return bcoin.coins.fromRaw(coins, hash); return Coins.fromRaw(coins, hash);
coins = yield this.db.get(layout.c(hash)); coins = yield this.db.get(layout.c(hash));
@ -1138,7 +1139,7 @@ ChainDB.prototype.getCoins = co(function* getCoins(hash) {
this.coinCache.set(hash, coins); this.coinCache.set(hash, coins);
return bcoin.coins.fromRaw(coins, hash); return Coins.fromRaw(coins, hash);
}); });
/** /**
@ -1401,7 +1402,7 @@ ChainDB.prototype.getFullBlock = co(function* getFullBlock(hash) {
*/ */
ChainDB.prototype.getCoinView = co(function* getCoinView(block, callback) { ChainDB.prototype.getCoinView = co(function* getCoinView(block, callback) {
var view = new bcoin.coinview(); var view = new CoinView();
var prevout = block.getPrevout(); var prevout = block.getPrevout();
var i, prev, coins; var i, prev, coins;

View File

@ -232,7 +232,8 @@ LowlevelUp.prototype.iterator = function iterator(options) {
fillCache: options.fillCache || false, fillCache: options.fillCache || false,
keyAsBuffer: this.bufferKeys, keyAsBuffer: this.bufferKeys,
valueAsBuffer: true, valueAsBuffer: true,
reverse: options.reverse || false reverse: options.reverse || false,
highWaterMark: options.highWaterMark || 16 * 1024
}; };
// Workaround for a leveldown // Workaround for a leveldown
@ -303,19 +304,24 @@ LowlevelUp.prototype.has = co(function* has(key) {
LowlevelUp.prototype.iterate = co(function* iterate(options) { LowlevelUp.prototype.iterate = co(function* iterate(options) {
var items = []; var items = [];
var parse = options.parse; var parse = options.parse;
var iter, result, data; var iter, item, data;
assert(typeof parse === 'function', 'Parse must be a function.'); assert(typeof parse === 'function', 'Parse must be a function.');
iter = this.iterator(options); iter = this.iterator(options);
for (;;) { for (;;) {
result = yield iter.next(); item = yield iter.next();
if (!result) if (!item)
break; break;
data = parse(result.key, result.value); try {
data = parse(item.key, item.value);
} catch (e) {
yield iter.end();
throw e;
}
if (data) if (data)
items.push(data); items.push(data);
@ -357,7 +363,7 @@ LowlevelUp.prototype.clone = co(function* clone(path) {
var opt = { keys: true, values: true }; var opt = { keys: true, values: true };
var hwm = 256 << 20; var hwm = 256 << 20;
var total = 0; var total = 0;
var tmp, batch, iter, result; var tmp, batch, iter, item;
assert(!this.loading); assert(!this.loading);
assert(!this.closing); assert(!this.closing);
@ -374,12 +380,12 @@ LowlevelUp.prototype.clone = co(function* clone(path) {
iter = this.iterator(opt); iter = this.iterator(opt);
for (;;) { for (;;) {
result = yield iter.next(); item = yield iter.next();
if (!result) if (!item)
break; break;
batch.put(result.key, result.value); batch.put(item.key, item.value);
total += value.length; total += value.length;
if (total >= hwm) { if (total >= hwm) {
@ -387,6 +393,7 @@ LowlevelUp.prototype.clone = co(function* clone(path) {
try { try {
yield batch.write(); yield batch.write();
} catch (e) { } catch (e) {
yield iter.end();
yield tmp.close(); yield tmp.close();
throw e; throw e;
} }

View File

@ -576,8 +576,7 @@ Mempool.prototype.addTX = co(function* addTX(tx) {
Mempool.prototype._addTX = co(function* _addTX(tx) { Mempool.prototype._addTX = co(function* _addTX(tx) {
var lockFlags = constants.flags.STANDARD_LOCKTIME_FLAGS; var lockFlags = constants.flags.STANDARD_LOCKTIME_FLAGS;
var hash = tx.hash('hex'); var hash = tx.hash('hex');
var ret, entry, missing; var ret, entry, result, exists;
var result, exists;
assert(!tx.mutable, 'Cannot add mutable TX to mempool.'); assert(!tx.mutable, 'Cannot add mutable TX to mempool.');
@ -665,10 +664,8 @@ Mempool.prototype._addTX = co(function* _addTX(tx) {
yield this.fillAllCoins(tx); yield this.fillAllCoins(tx);
if (!tx.hasCoins()) { if (!tx.hasCoins())
missing = this.storeOrphan(tx); return this.storeOrphan(tx);
return missing;
}
entry = MempoolEntry.fromTX(tx, this.chain.height); entry = MempoolEntry.fromTX(tx, this.chain.height);

View File

@ -239,7 +239,7 @@ WalletDB.prototype.backup = function backup(path) {
*/ */
WalletDB.prototype.getDepth = co(function* getDepth() { WalletDB.prototype.getDepth = co(function* getDepth() {
var result, iter, depth; var iter, item, depth;
// This may seem like a strange way to do // This may seem like a strange way to do
// this, but updating a global state when // this, but updating a global state when
@ -256,14 +256,14 @@ WalletDB.prototype.getDepth = co(function* getDepth() {
reverse: true reverse: true
}); });
result = yield iter.next(); item = yield iter.next();
if (!result) if (!item)
return 1; return 1;
yield iter.end(); yield iter.end();
depth = layout.ww(result.key); depth = layout.ww(item.key);
return depth + 1; return depth + 1;
}); });

View File

@ -1,4 +1,6 @@
var bcoin = require('../'); var bcoin = require('../');
var spawn = bcoin.spawn;
var co = spawn.co;
var assert = require('assert'); var assert = require('assert');
var file = process.argv[2]; var file = process.argv[2];
@ -22,91 +24,93 @@ function makeKey(data) {
return key; return key;
} }
function updateState(callback) { var checkVersion = co(function* checkVersion() {
var hash, batch, ver, p; var data, ver;
console.log('Checking version.');
data = yield db.get('V');
if (!data)
return;
ver = data.readUInt32LE(0, true);
if (ver !== 0)
throw Error('DB is version ' + ver + '.');
});
var updateState = co(function* updateState() {
var data, hash, batch, ver, p;
console.log('Updating chain state.'); console.log('Updating chain state.');
db.get('R', function(err, data) { data = yield db.get('R');
if (err)
return callback(err);
if (!data || data.length < 32) if (!data || data.length < 32)
return callback(new Error('No chain state.')); throw new Error('No chain state.');
hash = data.slice(0, 32); hash = data.slice(0, 32);
p = new bcoin.writer(); p = new bcoin.writer();
p.writeHash(hash); p.writeHash(hash);
p.writeU64(0); p.writeU64(0);
p.writeU64(0); p.writeU64(0);
p.writeU64(0); p.writeU64(0);
p = p.render(); p = p.render();
batch = db.batch(); batch = db.batch();
batch.put('R', p); batch.put('R', p);
ver = new Buffer(4); ver = new Buffer(4);
ver.writeUInt32LE(1, 0, true); ver.writeUInt32LE(1, 0, true);
batch.put('V', ver); batch.put('V', ver);
batch.write(function(err) { yield batch.write();
if (err)
return callback(err);
console.log('Updated chain state.');
callback();
});
});
}
function updateEndian(callback) { console.log('Updated chain state.');
var lo = new Buffer('4800000000', 'hex'); });
var hi = new Buffer('48ffffffff', 'hex');
var updateEndian = co(function* updateEndian() {
var batch = db.batch(); var batch = db.batch();
var total = 0; var total = 0;
var iter, item;
console.log('Updating endianness.'); console.log('Updating endianness.');
console.log('Iterating...'); console.log('Iterating...');
db.iterate({ iter = db.iterator({
gte: lo, gte: new Buffer('4800000000', 'hex'),
lte: hi, lte: new Buffer('48ffffffff', 'hex'),
values: true, values: true
parse: function(key, value) {
batch.del(key);
batch.put(makeKey(key), value);
total++;
}
}, function(err) {
if (err)
throw err;
console.log('Migrating %d items.', total);
batch.write(function(err) {
if (err)
throw err;
console.log('Migrated endianness.');
callback();
});
}); });
}
db.open(function(err) { for (;;) {
if (err) item = yield iter.next();
throw err;
console.log('Opened %s.', file); if (!item)
break;
updateState(function(err) { batch.del(item.key);
if (err) batch.put(makeKey(item.key), item.value);
throw err; total++;
updateEndian(function(err) { }
if (err)
throw err; console.log('Migrating %d items.', total);
console.log('Migration complete.');
process.exit(0); yield batch.write();
});
}); console.log('Migrated endianness.');
});
spawn(function *() {
yield db.open();
console.log('Opened %s.', file);
yield checkVersion();
yield updateState();
yield updateEndian();
}).then(function() {
console.log('Migration complete.');
process.exit(0);
}); });