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.
yield this.db.save(entry, block, view, true);
yield this.db.save(entry, block, view);
this.tip = entry;
this.height = entry.height;
@ -1186,7 +1186,7 @@ Chain.prototype._add = co(function* add(block) {
// our tip's. Add the block but do _not_
// connect the inputs.
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);

View File

@ -16,6 +16,8 @@ var DUMMY = new Buffer([0]);
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
var spawn = require('../utils/spawn');
var CoinView = require('./coinview');
var Coins = require('./coins');
var co = spawn.co;
/*
@ -232,7 +234,7 @@ ChainDB.prototype._open = co(function* open() {
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.');
@ -544,28 +546,26 @@ ChainDB.prototype.get = co(function* get(hash) {
* instead performed in {@link Chain#add}.
* @param {ChainEntry} entry
* @param {Block} block
* @param {CoinView} view
* @param {Boolean} connect - Whether to connect the
* block's inputs and add it as a tip.
* @param {CoinView?} view - Will not connect if null.
* @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 height = new Buffer(4);
this.start();
height.writeUInt32LE(entry.height, 0, true);
this.start();
this.put(layout.h(hash), height);
this.put(layout.e(hash), entry.toRaw());
this.cacheHash.set(entry.hash, entry);
if (!connect) {
if (!view) {
try {
yield this.saveBlock(block, view, false);
yield this.saveBlock(block);
} catch (e) {
this.drop();
throw e;
@ -579,13 +579,14 @@ ChainDB.prototype.save = co(function* save(entry, block, view, connect) {
this.put(layout.H(entry.height), hash);
try {
yield this.saveBlock(block, view, true);
yield this.saveBlock(block, view);
} catch (e) {
this.drop();
throw e;
}
this.put(layout.R, this.pending.commit(hash));
yield this.commit();
});
@ -814,13 +815,13 @@ ChainDB.prototype.has = co(function* has(height) {
* @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)
return block;
this.put(layout.b(block.hash()), block.toRaw());
if (!connect)
if (!view)
return block;
yield this.connectBlock(block, view);
@ -1107,7 +1108,7 @@ ChainDB.prototype.getCoin = co(function* getCoin(hash, index) {
var coins = this.coinCache.get(hash);
if (coins)
return bcoin.coins.parseCoin(coins, hash, index);
return Coins.parseCoin(coins, hash, index);
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);
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);
if (coins)
return bcoin.coins.fromRaw(coins, hash);
return Coins.fromRaw(coins, 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);
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) {
var view = new bcoin.coinview();
var view = new CoinView();
var prevout = block.getPrevout();
var i, prev, coins;

View File

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

View File

@ -576,8 +576,7 @@ Mempool.prototype.addTX = co(function* addTX(tx) {
Mempool.prototype._addTX = co(function* _addTX(tx) {
var lockFlags = constants.flags.STANDARD_LOCKTIME_FLAGS;
var hash = tx.hash('hex');
var ret, entry, missing;
var result, exists;
var ret, entry, result, exists;
assert(!tx.mutable, 'Cannot add mutable TX to mempool.');
@ -665,10 +664,8 @@ Mempool.prototype._addTX = co(function* _addTX(tx) {
yield this.fillAllCoins(tx);
if (!tx.hasCoins()) {
missing = this.storeOrphan(tx);
return missing;
}
if (!tx.hasCoins())
return this.storeOrphan(tx);
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() {
var result, iter, depth;
var iter, item, depth;
// This may seem like a strange way to do
// this, but updating a global state when
@ -256,14 +256,14 @@ WalletDB.prototype.getDepth = co(function* getDepth() {
reverse: true
});
result = yield iter.next();
item = yield iter.next();
if (!result)
if (!item)
return 1;
yield iter.end();
depth = layout.ww(result.key);
depth = layout.ww(item.key);
return depth + 1;
});

View File

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