bcoin: use bdb.
This commit is contained in:
parent
771a4ef17f
commit
d1e4be8343
@ -8,6 +8,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
const BDB = require('bdb');
|
||||||
const util = require('../utils/util');
|
const util = require('../utils/util');
|
||||||
const BufferReader = require('../utils/reader');
|
const BufferReader = require('../utils/reader');
|
||||||
const StaticWriter = require('../utils/staticwriter');
|
const StaticWriter = require('../utils/staticwriter');
|
||||||
@ -16,7 +17,6 @@ const encoding = require('../utils/encoding');
|
|||||||
const Network = require('../protocol/network');
|
const Network = require('../protocol/network');
|
||||||
const CoinView = require('../coins/coinview');
|
const CoinView = require('../coins/coinview');
|
||||||
const UndoCoins = require('../coins/undocoins');
|
const UndoCoins = require('../coins/undocoins');
|
||||||
const LDB = require('../db/ldb');
|
|
||||||
const layout = require('./layout');
|
const layout = require('./layout');
|
||||||
const LRU = require('../utils/lru');
|
const LRU = require('../utils/lru');
|
||||||
const Block = require('../primitives/block');
|
const Block = require('../primitives/block');
|
||||||
@ -51,7 +51,7 @@ function ChainDB(options) {
|
|||||||
this.network = this.options.network;
|
this.network = this.options.network;
|
||||||
this.logger = this.options.logger.context('chaindb');
|
this.logger = this.options.logger.context('chaindb');
|
||||||
|
|
||||||
this.db = LDB(this.options);
|
this.db = new BDB(this.options);
|
||||||
this.stateCache = new StateCache(this.network);
|
this.stateCache = new StateCache(this.network);
|
||||||
this.state = new ChainState();
|
this.state = new ChainState();
|
||||||
this.pending = null;
|
this.pending = null;
|
||||||
|
|||||||
@ -1,16 +0,0 @@
|
|||||||
/**
|
|
||||||
* backends-browser.js - database backends for bcoin
|
|
||||||
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
|
|
||||||
* https://github.com/bcoin-org/bcoin
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const level = require('./level');
|
|
||||||
const MemDB = require('./memdb');
|
|
||||||
|
|
||||||
exports.get = function get(name) {
|
|
||||||
if (name === 'memory')
|
|
||||||
return MemDB;
|
|
||||||
return level;
|
|
||||||
};
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
/**
|
|
||||||
* backends.js - database backends for bcoin
|
|
||||||
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
|
|
||||||
* https://github.com/bcoin-org/bcoin
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
exports.get = function get(name) {
|
|
||||||
try {
|
|
||||||
switch (name) {
|
|
||||||
case 'leveldown':
|
|
||||||
return require('leveldown');
|
|
||||||
case 'rocksdown':
|
|
||||||
return require('rocksdown');
|
|
||||||
case 'lmdb':
|
|
||||||
return require('lmdb');
|
|
||||||
case 'memory':
|
|
||||||
return require('./memdb');
|
|
||||||
default:
|
|
||||||
throw new Error(`Database backend "${name}" not found.`);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (e.code === 'MODULE_NOT_FOUND')
|
|
||||||
throw new Error(`Database backend "${name}" not found.`);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
/*!
|
|
||||||
* db/index.js - data management for bcoin
|
|
||||||
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
|
|
||||||
* https://github.com/bcoin-org/bcoin
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @module db
|
|
||||||
*/
|
|
||||||
|
|
||||||
exports.backends = require('./backends');
|
|
||||||
exports.LDB = require('./ldb');
|
|
||||||
exports.LowlevelUp = require('./lowlevelup');
|
|
||||||
exports.MemDB = require('./memdb');
|
|
||||||
100
lib/db/ldb.js
100
lib/db/ldb.js
@ -1,100 +0,0 @@
|
|||||||
/**
|
|
||||||
* ldb.js - database backend for bcoin
|
|
||||||
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
|
|
||||||
* Copyright (c) 2014-2017, Christopher Jeffrey (MIT License).
|
|
||||||
* https://github.com/bcoin-org/bcoin
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const assert = require('assert');
|
|
||||||
const LowlevelUp = require('./lowlevelup');
|
|
||||||
const backends = require('./backends');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a database.
|
|
||||||
* @alias module:db.LDB
|
|
||||||
* @param {Object} options
|
|
||||||
* @returns {LowlevelUp}
|
|
||||||
*/
|
|
||||||
|
|
||||||
function LDB(options) {
|
|
||||||
const result = LDB.getBackend(options);
|
|
||||||
const backend = result.backend;
|
|
||||||
const location = result.location;
|
|
||||||
|
|
||||||
return new LowlevelUp(backend, location, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get database name and extension based on options.
|
|
||||||
* @param {String} db
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
|
|
||||||
LDB.getName = function getName(db) {
|
|
||||||
let name, ext;
|
|
||||||
|
|
||||||
if (!db)
|
|
||||||
db = 'memory';
|
|
||||||
|
|
||||||
switch (db) {
|
|
||||||
case 'ldb':
|
|
||||||
case 'leveldb':
|
|
||||||
case 'leveldown':
|
|
||||||
name = 'leveldown';
|
|
||||||
ext = 'ldb';
|
|
||||||
break;
|
|
||||||
case 'rdb':
|
|
||||||
case 'rocksdb':
|
|
||||||
case 'rocksdown':
|
|
||||||
name = 'rocksdown';
|
|
||||||
ext = 'rdb';
|
|
||||||
break;
|
|
||||||
case 'mdb':
|
|
||||||
case 'lmdb':
|
|
||||||
name = 'lmdb';
|
|
||||||
ext = 'mdb';
|
|
||||||
break;
|
|
||||||
case 'mem':
|
|
||||||
case 'memory':
|
|
||||||
case 'rbt':
|
|
||||||
name = 'memory';
|
|
||||||
ext = 'mem';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
name = db;
|
|
||||||
ext = 'db';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [name, ext];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get target backend and location.
|
|
||||||
* @param {Object} options
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
|
|
||||||
LDB.getBackend = function getBackend(options) {
|
|
||||||
const [name, ext] = LDB.getName(options.db);
|
|
||||||
const backend = backends.get(name);
|
|
||||||
let location = options.location;
|
|
||||||
|
|
||||||
if (typeof location !== 'string') {
|
|
||||||
assert(name === 'memory', 'Location required.');
|
|
||||||
location = 'memory';
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
backend: backend,
|
|
||||||
location: `${location}.${ext}`
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Expose
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = LDB;
|
|
||||||
139
lib/db/level.js
139
lib/db/level.js
@ -1,139 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const Level = require('level-js');
|
|
||||||
|
|
||||||
function DB(location) {
|
|
||||||
this.level = new Level(location);
|
|
||||||
this.bufferKeys = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DB.prototype.open = function open(options, callback) {
|
|
||||||
this.bufferKeys = options.bufferKeys === true;
|
|
||||||
this.level.open(options, callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
DB.prototype.close = function close(callback) {
|
|
||||||
this.level.close(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
DB.prototype.get = function get(key, options, callback) {
|
|
||||||
this.level.get(toHex(key), options, callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
DB.prototype.put = function put(key, value, options, callback) {
|
|
||||||
this.level.put(toHex(key), value, options, callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
DB.prototype.del = function del(key, options, callback) {
|
|
||||||
this.level.del(toHex(key), options, callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
DB.prototype.batch = function batch() {
|
|
||||||
return new Batch(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
DB.prototype.iterator = function iterator(options) {
|
|
||||||
return new Iterator(this, options);
|
|
||||||
};
|
|
||||||
|
|
||||||
DB.destroy = function destroy(db, callback) {
|
|
||||||
Level.destroy(db, callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
function Batch(db) {
|
|
||||||
this.db = db;
|
|
||||||
this.batch = db.level.batch();
|
|
||||||
this.hasOps = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Batch.prototype.put = function put(key, value) {
|
|
||||||
this.batch.put(toHex(key), value);
|
|
||||||
this.hasOps = true;
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
Batch.prototype.del = function del(key) {
|
|
||||||
this.batch.del(toHex(key));
|
|
||||||
this.hasOps = true;
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
Batch.prototype.write = function write(callback) {
|
|
||||||
if (!this.hasOps)
|
|
||||||
return callback();
|
|
||||||
this.batch.write(callback);
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
Batch.prototype.clear = function clear() {
|
|
||||||
this.batch.clear();
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
function Iterator(db, options) {
|
|
||||||
const opt = {
|
|
||||||
gt: toHex(options.gt),
|
|
||||||
gte: toHex(options.gte),
|
|
||||||
lt: toHex(options.lt),
|
|
||||||
lte: toHex(options.lte),
|
|
||||||
limit: options.limit,
|
|
||||||
reverse: options.reverse,
|
|
||||||
keys: options.keys,
|
|
||||||
values: options.values,
|
|
||||||
keyAsBuffer: false,
|
|
||||||
valueAsBuffer: true
|
|
||||||
};
|
|
||||||
|
|
||||||
this.db = db;
|
|
||||||
this.iter = db.level.iterator(opt);
|
|
||||||
this.ended = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator.prototype.next = function next(callback) {
|
|
||||||
this.iter.next((err, key, value) => {
|
|
||||||
// Hack for level-js: it doesn't actually
|
|
||||||
// end iterators -- it keeps streaming keys
|
|
||||||
// and values.
|
|
||||||
if (this.ended)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key === undefined && value === undefined) {
|
|
||||||
callback(err, key, value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key && this.db.bufferKeys)
|
|
||||||
key = Buffer.from(key, 'hex');
|
|
||||||
|
|
||||||
if (value && !Buffer.isBuffer(value) && value.buffer)
|
|
||||||
value = Buffer.from(value.buffer);
|
|
||||||
|
|
||||||
callback(err, key, value);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Iterator.prototype.seek = function seek(key) {
|
|
||||||
this.iter.seek(toHex(key));
|
|
||||||
};
|
|
||||||
|
|
||||||
Iterator.prototype.end = function end(callback) {
|
|
||||||
if (this.ended) {
|
|
||||||
callback(new Error('end() already called on iterator.'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.ended = true;
|
|
||||||
this.iter.end(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
function toHex(key) {
|
|
||||||
if (Buffer.isBuffer(key))
|
|
||||||
return key.toString('hex');
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = DB;
|
|
||||||
1333
lib/db/lowlevelup.js
1333
lib/db/lowlevelup.js
File diff suppressed because it is too large
Load Diff
666
lib/db/memdb.js
666
lib/db/memdb.js
@ -1,666 +0,0 @@
|
|||||||
/*!
|
|
||||||
* memdb.js - in-memory database for bcoin
|
|
||||||
* Copyright (c) 2016-2017, Christopher Jeffrey (MIT License).
|
|
||||||
* https://github.com/bcoin-org/bcoin
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const assert = require('assert');
|
|
||||||
const RBT = require('../utils/rbt');
|
|
||||||
const DUMMY = Buffer.alloc(0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In memory database for bcoin
|
|
||||||
* using a red-black tree backend.
|
|
||||||
* @alias module:db.MemDB
|
|
||||||
* @constructor
|
|
||||||
* @param {String?} location - Phony location.
|
|
||||||
* @param {Object?} options
|
|
||||||
* @param {Function} options.compare - Comparator.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function MemDB(location) {
|
|
||||||
if (!(this instanceof MemDB))
|
|
||||||
return new MemDB(location);
|
|
||||||
|
|
||||||
this.location = location || 'memory';
|
|
||||||
this.options = {};
|
|
||||||
this.tree = new RBT(cmp, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do a key lookup.
|
|
||||||
* @private
|
|
||||||
* @param {Buffer|String} key
|
|
||||||
* @returns {Buffer?} value
|
|
||||||
*/
|
|
||||||
|
|
||||||
MemDB.prototype.search = function search(key) {
|
|
||||||
if (typeof key === 'string')
|
|
||||||
key = Buffer.from(key, 'utf8');
|
|
||||||
|
|
||||||
assert(Buffer.isBuffer(key), 'Key must be a Buffer.');
|
|
||||||
|
|
||||||
const node = this.tree.search(key);
|
|
||||||
|
|
||||||
if (!node)
|
|
||||||
return undefined;
|
|
||||||
|
|
||||||
return node.value;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert a record.
|
|
||||||
* @private
|
|
||||||
* @param {Buffer|String} key
|
|
||||||
* @param {Buffer} value
|
|
||||||
*/
|
|
||||||
|
|
||||||
MemDB.prototype.insert = function insert(key, value) {
|
|
||||||
if (typeof key === 'string')
|
|
||||||
key = Buffer.from(key, 'utf8');
|
|
||||||
|
|
||||||
if (typeof value === 'string')
|
|
||||||
value = Buffer.from(value, 'utf8');
|
|
||||||
|
|
||||||
if (value == null)
|
|
||||||
value = DUMMY;
|
|
||||||
|
|
||||||
assert(Buffer.isBuffer(key), 'Key must be a Buffer.');
|
|
||||||
assert(Buffer.isBuffer(value), 'Value must be a Buffer.');
|
|
||||||
|
|
||||||
return this.tree.insert(key, value) != null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a record.
|
|
||||||
* @private
|
|
||||||
* @param {Buffer|String} key
|
|
||||||
* @returns {Boolean}
|
|
||||||
*/
|
|
||||||
|
|
||||||
MemDB.prototype.remove = function remove(key) {
|
|
||||||
if (typeof key === 'string')
|
|
||||||
key = Buffer.from(key, 'utf8');
|
|
||||||
|
|
||||||
assert(Buffer.isBuffer(key), 'Key must be a Buffer.');
|
|
||||||
|
|
||||||
return this.tree.remove(key) != null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Traverse between a range of keys and collect records.
|
|
||||||
* @private
|
|
||||||
* @param {Buffer} min
|
|
||||||
* @param {Buffer} max
|
|
||||||
* @returns {RBTData[]} Records.
|
|
||||||
*/
|
|
||||||
|
|
||||||
MemDB.prototype.range = function range(min, max) {
|
|
||||||
if (typeof min === 'string')
|
|
||||||
min = Buffer.from(min, 'utf8');
|
|
||||||
|
|
||||||
if (typeof max === 'string')
|
|
||||||
max = Buffer.from(max, 'utf8');
|
|
||||||
|
|
||||||
assert(!min || Buffer.isBuffer(min), 'Key must be a Buffer.');
|
|
||||||
assert(!max || Buffer.isBuffer(max), 'Key must be a Buffer.');
|
|
||||||
|
|
||||||
return this.tree.range(min, max);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open the database (leveldown method).
|
|
||||||
* @param {Object?} options
|
|
||||||
* @param {Function} callback
|
|
||||||
*/
|
|
||||||
|
|
||||||
MemDB.prototype.open = function open(options, callback) {
|
|
||||||
if (!callback) {
|
|
||||||
callback = options;
|
|
||||||
options = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!options)
|
|
||||||
options = {};
|
|
||||||
|
|
||||||
this.options = options;
|
|
||||||
|
|
||||||
setImmediate(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the database (leveldown method).
|
|
||||||
* @param {Function} callback
|
|
||||||
*/
|
|
||||||
|
|
||||||
MemDB.prototype.close = function close(callback) {
|
|
||||||
setImmediate(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve a record (leveldown method).
|
|
||||||
* @param {Buffer|String} key
|
|
||||||
* @param {Object?} options
|
|
||||||
* @param {Function} callback - Returns Buffer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
MemDB.prototype.get = function get(key, options, callback) {
|
|
||||||
if (!callback) {
|
|
||||||
callback = options;
|
|
||||||
options = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!options)
|
|
||||||
options = {};
|
|
||||||
|
|
||||||
let value = this.search(key);
|
|
||||||
|
|
||||||
if (!value) {
|
|
||||||
const err = new Error('MEMDB_NOTFOUND: Key not found.');
|
|
||||||
err.notFound = true;
|
|
||||||
err.type = 'NotFoundError';
|
|
||||||
setImmediate(() => callback(err));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.asBuffer === false)
|
|
||||||
value = value.toString('utf8');
|
|
||||||
|
|
||||||
setImmediate(() => callback(null, value));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert a record (leveldown method).
|
|
||||||
* @param {Buffer|String} key
|
|
||||||
* @param {Buffer} value
|
|
||||||
* @param {Object?} options
|
|
||||||
* @param {Function} callback
|
|
||||||
*/
|
|
||||||
|
|
||||||
MemDB.prototype.put = function put(key, value, options, callback) {
|
|
||||||
if (!callback) {
|
|
||||||
callback = options;
|
|
||||||
options = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.insert(key, value);
|
|
||||||
|
|
||||||
setImmediate(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a record (leveldown method).
|
|
||||||
* @param {Buffer|String} key
|
|
||||||
* @param {Object?} options
|
|
||||||
* @param {Function} callback
|
|
||||||
*/
|
|
||||||
|
|
||||||
MemDB.prototype.del = function del(key, options, callback) {
|
|
||||||
if (!callback) {
|
|
||||||
callback = options;
|
|
||||||
options = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.remove(key);
|
|
||||||
|
|
||||||
setImmediate(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an atomic batch (leveldown method).
|
|
||||||
* @see Leveldown.Batch
|
|
||||||
* @param {Object[]?} ops
|
|
||||||
* @param {Object?} options
|
|
||||||
* @param {Function} callback
|
|
||||||
*/
|
|
||||||
|
|
||||||
MemDB.prototype.batch = function batch(ops, options, callback) {
|
|
||||||
if (!callback) {
|
|
||||||
callback = options;
|
|
||||||
options = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const b = new Batch(this, options);
|
|
||||||
|
|
||||||
if (ops) {
|
|
||||||
b.ops = ops;
|
|
||||||
b.write(callback);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return b;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an iterator (leveldown method).
|
|
||||||
* @param {Object} options - See {Leveldown.Iterator}.
|
|
||||||
* @returns {Leveldown.Iterator}.
|
|
||||||
*/
|
|
||||||
|
|
||||||
MemDB.prototype.iterator = function iterator(options) {
|
|
||||||
return new Iterator(this, options);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a database property (leveldown method) (NOP).
|
|
||||||
* @param {String} name - Property name.
|
|
||||||
* @returns {String}
|
|
||||||
*/
|
|
||||||
|
|
||||||
MemDB.prototype.getProperty = function getProperty(name) {
|
|
||||||
return '';
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate approximate database size (leveldown method).
|
|
||||||
* @param {Buffer|String} start - Start key.
|
|
||||||
* @param {Buffer|String} end - End key.
|
|
||||||
* @param {Function} callback - Returns Number.
|
|
||||||
*/
|
|
||||||
|
|
||||||
MemDB.prototype.approximateSize = function approximateSize(start, end, callback) {
|
|
||||||
const items = this.range(start, end);
|
|
||||||
let size = 0;
|
|
||||||
|
|
||||||
for (const item of items) {
|
|
||||||
size += item.key.length;
|
|
||||||
size += item.value.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
setImmediate(() => callback(null, size));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy the database (leveldown function) (NOP).
|
|
||||||
* @param {String} location
|
|
||||||
* @param {Function} callback
|
|
||||||
*/
|
|
||||||
|
|
||||||
MemDB.destroy = function destroy(location, callback) {
|
|
||||||
setImmediate(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Repair the database (leveldown function) (NOP).
|
|
||||||
* @param {String} location
|
|
||||||
* @param {Function} callback
|
|
||||||
*/
|
|
||||||
|
|
||||||
MemDB.repair = function repair(location, callback) {
|
|
||||||
setImmediate(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Batch
|
|
||||||
* @constructor
|
|
||||||
* @ignore
|
|
||||||
* @private
|
|
||||||
* @param {MemDB} db
|
|
||||||
* @param {Object?} options
|
|
||||||
*/
|
|
||||||
|
|
||||||
function Batch(db, options) {
|
|
||||||
this.options = options || {};
|
|
||||||
this.ops = [];
|
|
||||||
this.db = db;
|
|
||||||
this.written = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert a record.
|
|
||||||
* @param {Buffer|String} key
|
|
||||||
* @param {Buffer} value
|
|
||||||
*/
|
|
||||||
|
|
||||||
Batch.prototype.put = function put(key, value) {
|
|
||||||
assert(!this.written, 'Already written.');
|
|
||||||
this.ops.push(new BatchOp('put', key, value));
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a record.
|
|
||||||
* @param {Buffer|String} key
|
|
||||||
*/
|
|
||||||
|
|
||||||
Batch.prototype.del = function del(key) {
|
|
||||||
assert(!this.written, 'Already written.');
|
|
||||||
this.ops.push(new BatchOp('del', key));
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Commit the batch.
|
|
||||||
* @param {Function} callback
|
|
||||||
*/
|
|
||||||
|
|
||||||
Batch.prototype.write = function write(callback) {
|
|
||||||
if (this.written) {
|
|
||||||
setImmediate(() => callback(new Error('Already written.')));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const op of this.ops) {
|
|
||||||
switch (op.type) {
|
|
||||||
case 'put':
|
|
||||||
this.db.insert(op.key, op.value);
|
|
||||||
break;
|
|
||||||
case 'del':
|
|
||||||
this.db.remove(op.key);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
setImmediate(() => callback(new Error('Bad op.')));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.ops = [];
|
|
||||||
this.written = true;
|
|
||||||
|
|
||||||
setImmediate(callback);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear batch of all ops.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Batch.prototype.clear = function clear() {
|
|
||||||
assert(!this.written, 'Already written.');
|
|
||||||
this.ops = [];
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Batch Operation
|
|
||||||
* @constructor
|
|
||||||
* @ignore
|
|
||||||
* @private
|
|
||||||
* @param {String} type
|
|
||||||
* @param {Buffer} key
|
|
||||||
* @param {Buffer|null} value
|
|
||||||
*/
|
|
||||||
|
|
||||||
function BatchOp(type, key, value) {
|
|
||||||
this.type = type;
|
|
||||||
this.key = key;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterator
|
|
||||||
* @constructor
|
|
||||||
* @ignore
|
|
||||||
* @private
|
|
||||||
* @param {RBT} db
|
|
||||||
* @param {Object?} options
|
|
||||||
*/
|
|
||||||
|
|
||||||
function Iterator(db, options) {
|
|
||||||
this.db = db;
|
|
||||||
this.options = new IteratorOptions(options);
|
|
||||||
this.iter = null;
|
|
||||||
this.ended = false;
|
|
||||||
this.total = 0;
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the iterator.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Iterator.prototype.init = function init() {
|
|
||||||
const snapshot = this.db.tree.snapshot();
|
|
||||||
const iter = this.db.tree.iterator(snapshot);
|
|
||||||
|
|
||||||
if (this.options.reverse) {
|
|
||||||
if (this.options.end) {
|
|
||||||
iter.seekMax(this.options.end);
|
|
||||||
if (this.options.lt && iter.valid()) {
|
|
||||||
if (iter.compare(this.options.end) === 0)
|
|
||||||
iter.prev();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
iter.seekLast();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this.options.start) {
|
|
||||||
iter.seekMin(this.options.start);
|
|
||||||
if (this.options.gt && iter.valid()) {
|
|
||||||
if (iter.compare(this.options.start) === 0)
|
|
||||||
iter.next();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
iter.seekFirst();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.iter = iter;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Seek to the next key.
|
|
||||||
* @param {Function} callback
|
|
||||||
*/
|
|
||||||
|
|
||||||
Iterator.prototype.next = function next(callback) {
|
|
||||||
const options = this.options;
|
|
||||||
const iter = this.iter;
|
|
||||||
|
|
||||||
if (!this.iter) {
|
|
||||||
setImmediate(() => callback(new Error('Cannot call next.')));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let result;
|
|
||||||
if (options.reverse) {
|
|
||||||
result = iter.prev();
|
|
||||||
|
|
||||||
// Stop once we hit a key below our gte key.
|
|
||||||
if (result && options.start) {
|
|
||||||
if (options.gt) {
|
|
||||||
if (iter.compare(options.start) <= 0)
|
|
||||||
result = false;
|
|
||||||
} else {
|
|
||||||
if (iter.compare(options.start) < 0)
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = iter.next();
|
|
||||||
|
|
||||||
// Stop once we hit a key above our lte key.
|
|
||||||
if (result && options.end) {
|
|
||||||
if (options.lt) {
|
|
||||||
if (iter.compare(options.end) >= 0)
|
|
||||||
result = false;
|
|
||||||
} else {
|
|
||||||
if (iter.compare(options.end) > 0)
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
this.iter = null;
|
|
||||||
setImmediate(callback);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.limit !== -1) {
|
|
||||||
if (this.total >= options.limit) {
|
|
||||||
this.iter = null;
|
|
||||||
setImmediate(callback);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.total += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let key = iter.key;
|
|
||||||
let value = iter.value;
|
|
||||||
|
|
||||||
if (!options.keys)
|
|
||||||
key = DUMMY;
|
|
||||||
|
|
||||||
if (!options.values)
|
|
||||||
value = DUMMY;
|
|
||||||
|
|
||||||
if (!options.keyAsBuffer)
|
|
||||||
key = key.toString('utf8');
|
|
||||||
|
|
||||||
if (!options.valueAsBuffer)
|
|
||||||
value = value.toString('utf8');
|
|
||||||
|
|
||||||
setImmediate(() => callback(null, key, value));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Seek to a key gte to `key`.
|
|
||||||
* @param {String|Buffer} key
|
|
||||||
*/
|
|
||||||
|
|
||||||
Iterator.prototype.seek = function seek(key) {
|
|
||||||
assert(this.iter, 'Already ended.');
|
|
||||||
|
|
||||||
if (typeof key === 'string')
|
|
||||||
key = Buffer.from(key, 'utf8');
|
|
||||||
|
|
||||||
assert(Buffer.isBuffer(key), 'Key must be a Buffer.');
|
|
||||||
|
|
||||||
if (this.options.reverse)
|
|
||||||
this.iter.seekMax(key);
|
|
||||||
else
|
|
||||||
this.iter.seekMin(key);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* End the iterator. Free up snapshot.
|
|
||||||
* @param {Function} callback
|
|
||||||
*/
|
|
||||||
|
|
||||||
Iterator.prototype.end = function end(callback) {
|
|
||||||
if (this.ended) {
|
|
||||||
setImmediate(() => callback(new Error('Already ended.')));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.ended = true;
|
|
||||||
this.iter = null;
|
|
||||||
|
|
||||||
setImmediate(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterator Options
|
|
||||||
* @constructor
|
|
||||||
* @ignore
|
|
||||||
* @param {Object} options
|
|
||||||
*/
|
|
||||||
|
|
||||||
function IteratorOptions(options) {
|
|
||||||
this.keys = true;
|
|
||||||
this.values = true;
|
|
||||||
this.start = null;
|
|
||||||
this.end = null;
|
|
||||||
this.gt = false;
|
|
||||||
this.lt = false;
|
|
||||||
this.keyAsBuffer = true;
|
|
||||||
this.valueAsBuffer = true;
|
|
||||||
this.reverse = false;
|
|
||||||
this.limit = -1;
|
|
||||||
|
|
||||||
if (options)
|
|
||||||
this.fromOptions(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inject properties from options.
|
|
||||||
* @private
|
|
||||||
* @param {Object} options
|
|
||||||
* @returns {IteratorOptions}
|
|
||||||
*/
|
|
||||||
|
|
||||||
IteratorOptions.prototype.fromOptions = function fromOptions(options) {
|
|
||||||
if (options.keys != null) {
|
|
||||||
assert(typeof options.keys === 'boolean');
|
|
||||||
this.keys = options.keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.values != null) {
|
|
||||||
assert(typeof options.values === 'boolean');
|
|
||||||
this.values = options.values;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.start != null)
|
|
||||||
this.start = options.start;
|
|
||||||
|
|
||||||
if (options.end != null)
|
|
||||||
this.end = options.end;
|
|
||||||
|
|
||||||
if (options.gte != null)
|
|
||||||
this.start = options.gte;
|
|
||||||
|
|
||||||
if (options.lte != null)
|
|
||||||
this.end = options.lte;
|
|
||||||
|
|
||||||
if (options.gt != null) {
|
|
||||||
this.gt = true;
|
|
||||||
this.start = options.gt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.lt != null) {
|
|
||||||
this.lt = true;
|
|
||||||
this.end = options.lt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.start != null) {
|
|
||||||
if (typeof this.start === 'string')
|
|
||||||
this.start = Buffer.from(this.start, 'utf8');
|
|
||||||
assert(Buffer.isBuffer(this.start), '`start` must be a Buffer.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.end != null) {
|
|
||||||
if (typeof this.end === 'string')
|
|
||||||
this.end = Buffer.from(this.end, 'utf8');
|
|
||||||
assert(Buffer.isBuffer(this.end), '`end` must be a Buffer.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.keyAsBuffer != null) {
|
|
||||||
assert(typeof options.keyAsBuffer === 'boolean');
|
|
||||||
this.keyAsBuffer = options.keyAsBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.valueAsBuffer != null) {
|
|
||||||
assert(typeof options.valueAsBuffer === 'boolean');
|
|
||||||
this.valueAsBuffer = options.valueAsBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.reverse != null) {
|
|
||||||
assert(typeof options.reverse === 'boolean');
|
|
||||||
this.reverse = options.reverse;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.limit != null) {
|
|
||||||
assert(typeof options.limit === 'number');
|
|
||||||
this.limit = options.limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Helpers
|
|
||||||
*/
|
|
||||||
|
|
||||||
function cmp(a, b) {
|
|
||||||
return a.compare(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Expose
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = MemDB;
|
|
||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const BDB = require('bdb');
|
||||||
const AsyncObject = require('../utils/asyncobject');
|
const AsyncObject = require('../utils/asyncobject');
|
||||||
const common = require('../blockchain/common');
|
const common = require('../blockchain/common');
|
||||||
const consensus = require('../protocol/consensus');
|
const consensus = require('../protocol/consensus');
|
||||||
@ -26,7 +27,6 @@ const MempoolEntry = require('./mempoolentry');
|
|||||||
const Network = require('../protocol/network');
|
const Network = require('../protocol/network');
|
||||||
const encoding = require('../utils/encoding');
|
const encoding = require('../utils/encoding');
|
||||||
const layout = require('./layout');
|
const layout = require('./layout');
|
||||||
const LDB = require('../db/ldb');
|
|
||||||
const Fees = require('./fees');
|
const Fees = require('./fees');
|
||||||
const CoinView = require('../coins/coinview');
|
const CoinView = require('../coins/coinview');
|
||||||
const Heap = require('../utils/heap');
|
const Heap = require('../utils/heap');
|
||||||
@ -2372,7 +2372,7 @@ function MempoolCache(options) {
|
|||||||
this.batch = null;
|
this.batch = null;
|
||||||
|
|
||||||
if (options.persistent)
|
if (options.persistent)
|
||||||
this.db = LDB(options);
|
this.db = new BDB(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
MempoolCache.VERSION = 2;
|
MempoolCache.VERSION = 2;
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const BDB = require('bdb');
|
||||||
const AsyncObject = require('../utils/asyncobject');
|
const AsyncObject = require('../utils/asyncobject');
|
||||||
const util = require('../utils/util');
|
const util = require('../utils/util');
|
||||||
const Lock = require('../utils/lock');
|
const Lock = require('../utils/lock');
|
||||||
@ -21,7 +22,6 @@ const Path = require('./path');
|
|||||||
const common = require('./common');
|
const common = require('./common');
|
||||||
const Wallet = require('./wallet');
|
const Wallet = require('./wallet');
|
||||||
const Account = require('./account');
|
const Account = require('./account');
|
||||||
const LDB = require('../db/ldb');
|
|
||||||
const Bloom = require('../utils/bloom');
|
const Bloom = require('../utils/bloom');
|
||||||
const Logger = require('../node/logger');
|
const Logger = require('../node/logger');
|
||||||
const Outpoint = require('../primitives/outpoint');
|
const Outpoint = require('../primitives/outpoint');
|
||||||
@ -56,7 +56,7 @@ function WalletDB(options) {
|
|||||||
this.workers = this.options.workers;
|
this.workers = this.options.workers;
|
||||||
this.client = this.options.client || new NullClient(this);
|
this.client = this.options.client || new NullClient(this);
|
||||||
this.feeRate = this.options.feeRate;
|
this.feeRate = this.options.feeRate;
|
||||||
this.db = LDB(this.options);
|
this.db = new BDB(this.options);
|
||||||
|
|
||||||
this.primary = null;
|
this.primary = null;
|
||||||
this.state = new ChainState();
|
this.state = new ChainState();
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
const BDB = require('bdb');
|
||||||
const encoding = require('../lib/utils/encoding');
|
const encoding = require('../lib/utils/encoding');
|
||||||
const networks = require('../lib/protocol/networks');
|
const networks = require('../lib/protocol/networks');
|
||||||
const co = require('../lib/utils/co');
|
const co = require('../lib/utils/co');
|
||||||
@ -11,7 +12,7 @@ const Coins = require('../lib/coins/coins');
|
|||||||
const UndoCoins = require('../lib/coins/undocoins');
|
const UndoCoins = require('../lib/coins/undocoins');
|
||||||
const Coin = require('../lib/primitives/coin');
|
const Coin = require('../lib/primitives/coin');
|
||||||
const Output = require('../lib/primitives/output');
|
const Output = require('../lib/primitives/output');
|
||||||
const LDB = require('../lib/db/ldb');
|
|
||||||
let file = process.argv[2];
|
let file = process.argv[2];
|
||||||
let batch;
|
let batch;
|
||||||
|
|
||||||
@ -19,7 +20,7 @@ assert(typeof file === 'string', 'Please pass in a database path.');
|
|||||||
|
|
||||||
file = file.replace(/\.ldb\/?$/, '');
|
file = file.replace(/\.ldb\/?$/, '');
|
||||||
|
|
||||||
const db = LDB({
|
const db = new BDB({
|
||||||
location: file,
|
location: file,
|
||||||
db: 'leveldb',
|
db: 'leveldb',
|
||||||
compression: true,
|
compression: true,
|
||||||
|
|||||||
@ -16,6 +16,7 @@ if (process.argv.indexOf('-h') !== -1
|
|||||||
}
|
}
|
||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
const BDB = require('bdb');
|
||||||
const encoding = require('../lib/utils/encoding');
|
const encoding = require('../lib/utils/encoding');
|
||||||
const co = require('../lib/utils/co');
|
const co = require('../lib/utils/co');
|
||||||
const util = require('../lib/utils/util');
|
const util = require('../lib/utils/util');
|
||||||
@ -28,7 +29,6 @@ const OldUndoCoins = require('./coins/undocoins');
|
|||||||
const CoinEntry = require('../lib/coins/coinentry');
|
const CoinEntry = require('../lib/coins/coinentry');
|
||||||
const UndoCoins = require('../lib/coins/undocoins');
|
const UndoCoins = require('../lib/coins/undocoins');
|
||||||
const Block = require('../lib/primitives/block');
|
const Block = require('../lib/primitives/block');
|
||||||
const LDB = require('../lib/db/ldb');
|
|
||||||
const LRU = require('../lib/utils/lru');
|
const LRU = require('../lib/utils/lru');
|
||||||
|
|
||||||
const file = process.argv[2].replace(/\.ldb\/?$/, '');
|
const file = process.argv[2].replace(/\.ldb\/?$/, '');
|
||||||
@ -37,7 +37,7 @@ let hasIndex = false;
|
|||||||
let hasPruned = false;
|
let hasPruned = false;
|
||||||
let hasSPV = false;
|
let hasSPV = false;
|
||||||
|
|
||||||
const db = LDB({
|
const db = new BDB({
|
||||||
location: file,
|
location: file,
|
||||||
db: 'leveldb',
|
db: 'leveldb',
|
||||||
compression: true,
|
compression: true,
|
||||||
|
|||||||
@ -1,13 +1,14 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
const BDB = require('bdb');
|
||||||
const encoding = require('../lib/utils/encoding');
|
const encoding = require('../lib/utils/encoding');
|
||||||
const BufferReader = require('../lib/utils/reader');
|
const BufferReader = require('../lib/utils/reader');
|
||||||
const digest = require('bcrypto/lib/digest');
|
const digest = require('bcrypto/lib/digest');
|
||||||
const util = require('../lib/utils/util');
|
const util = require('../lib/utils/util');
|
||||||
const LDB = require('../lib/db/ldb');
|
|
||||||
const BN = require('bcrypto/lib/bn');
|
const BN = require('bcrypto/lib/bn');
|
||||||
const DUMMY = Buffer.from([0]);
|
const DUMMY = Buffer.from([0]);
|
||||||
|
|
||||||
let file = process.argv[2];
|
let file = process.argv[2];
|
||||||
let batch;
|
let batch;
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ assert(typeof file === 'string', 'Please pass in a database path.');
|
|||||||
|
|
||||||
file = file.replace(/\.ldb\/?$/, '');
|
file = file.replace(/\.ldb\/?$/, '');
|
||||||
|
|
||||||
const db = LDB({
|
const db = new BDB({
|
||||||
location: file,
|
location: file,
|
||||||
db: 'leveldb',
|
db: 'leveldb',
|
||||||
compression: true,
|
compression: true,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user