add some async functions.

This commit is contained in:
Christopher Jeffrey 2016-02-18 18:36:25 -08:00
parent 469d3c35d0
commit d2a4f995fd
2 changed files with 187 additions and 5 deletions

View File

@ -753,10 +753,13 @@ Chain.prototype.resetHeight = function resetHeight(height) {
for (i = height + 1; i < count; i++) {
existing = this.db.get(i);
assert(existing);
// this.db.remove(i);
this.db.drop(i);
delete this.heightLookup[existing.hash];
this.db.remove(i);
}
this.db.truncate(height);
// Reset the orphan map completely. There may
// have been some orphans on a forked chain we
// no longer need.
@ -772,6 +775,63 @@ Chain.prototype.resetHeight = function resetHeight(height) {
this.emit('tip', this.tip);
};
Chain.prototype.resetHeightAsync = function resetHeightAsync(height, callback) {
var self = this;
var count = this.db.count();
var i, lock;
assert(height <= count - 1);
assert(this.tip);
if (height === count - 1)
return utils.nextTick(callback);
lock = this.locked;
this.locked = true;
i = height + 1;
function next() {
if (i === count)
return self.db.truncateAsync(height, done);
self.db.getAsync(i, function(err, existing) {
if (err)
return done(err);
assert(existing);
delete self.heightLookup[existing.hash];
self.db.drop(i);
i++;
next();
});
}
function done(err) {
self.locked = lock;
if (err)
return callback(err);
// Reset the orphan map completely. There may
// have been some orphans on a forked chain we
// no longer need.
self.emit('purge', self.orphan.count, self.orphan.size);
self.orphan.map = {};
self.orphan.bmap = {};
self.orphan.count = 0;
self.orphan.size = 0;
self.tip = self.db.get(height);
assert(self.tip);
self.height = self.tip.height;
self.emit('tip', self.tip);
return callback();
}
};
Chain.prototype.revertHeight = function revertHeight(height, callback) {
var self = this;
var chainHeight;
@ -1399,6 +1459,94 @@ Chain.prototype.getLocator = function getLocator(start) {
return hashes;
};
Chain.prototype.getLocatorAsync = function getLocatorAsync(start, callback) {
var self = this;
var hashes = [];
var top = this.height;
var step = 1;
var i, called;
if (start) {
if (utils.isBuffer(start))
start = utils.toHex(start);
else if (start.hash)
start = start.hash('hex');
}
if (typeof start === 'string') {
top = this.heightLookup[start];
if (top == null) {
// We could simply `return [start]` here,
// but there is no standardized "spacing"
// for locator hashes. Pretend this hash
// is our tip. This is useful for getheaders
// when not using headers-first.
hashes.push(start);
top = this.db.count() - 1;
}
} else if (typeof start === 'number') {
top = start;
}
function done(err) {
if (called)
return;
called = true;
if (err)
return callback(err);
return callback(null, hashes);
}
this.db.hasAsync(top, function(err, has) {
var pending;
if (err)
return done(err);
if (!has)
return done(new Error('Potential reset.'));
i = top;
for (;;) {
hashes.push(i);
i = i - step;
if (i <= 0) {
if (i + step !== 0)
hashes.push(0);
break;
}
if (hashes.length >= 10)
step *= 2;
}
pending = hashes.length;
hashes.forEach(function(height, i) {
if (typeof height === 'string') {
if (!--pending)
done();
return;
}
self.db.getAsync(height, function(err, existing) {
if (err)
return done(err);
if (!existing)
return done(new Error('Potential reset.'));
hashes[i] = existing.hash;
if (!--pending)
done();
});
});
});
};
Chain.prototype.getOrphanRoot = function getOrphanRoot(hash) {
var self = this;
var root;

View File

@ -323,7 +323,7 @@ ChainDB.prototype.saveAsync = function saveAsync(entry, callback) {
});
};
ChainDB.prototype.remove = function remove(height) {
ChainDB.prototype.drop = function drop(height) {
assert(height >= 0);
// Potential race condition here. Not sure how
@ -333,8 +333,17 @@ ChainDB.prototype.remove = function remove(height) {
delete this._queue[height];
}
this._writeSync(this._nullBlock, height * BLOCK_SIZE);
delete this._cache[height];
};
ChainDB.prototype.remove = function remove(height) {
assert(height >= 0);
// Drop the queue and cache
this.drop(height);
// Write a null block
this._writeSync(this._nullBlock, height * BLOCK_SIZE);
// If we deleted several blocks at the end, go back
// to the last non-null block and truncate the file
@ -345,13 +354,13 @@ ChainDB.prototype.remove = function remove(height) {
assert(height >= 0);
this.truncateSync(height);
this.truncate(height);
}
return true;
};
ChainDB.prototype.truncateSync = function truncateSync(height) {
ChainDB.prototype.truncate = function truncate(height) {
var size = (height + 1) * BLOCK_SIZE;
if (!bcoin.fs) {
@ -417,6 +426,31 @@ ChainDB.prototype.has = function has(height) {
return utils.read32(data, 0) !== 0;
};
ChainDB.prototype.hasAsync = function hasAsync(height, callback) {
var data;
callback = utils.asyncify(callback);
if (this._queue[height] || this._cache[height])
return callback(null, true);
if (height < 0 || height == null)
return callback(null, false);
if ((height + 1) * BLOCK_SIZE > this.size)
return callback(null, false);
this._readAsync(4, height * BLOCK_SIZE, function(err, data) {
if (err)
return callback(err);
if (!data)
return callback(null, false);
return callback(null, utils.read32(data, 0) !== 0);
});
};
ChainDB.prototype._readSync = function _readSync(size, offset) {
var index = 0;
var data, bytes;