add some async functions.
This commit is contained in:
parent
469d3c35d0
commit
d2a4f995fd
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user