From d1e4be8343d00935013e152ffd3e4815fd5cd425 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sun, 29 Oct 2017 05:23:15 -0700 Subject: [PATCH] bcoin: use bdb. --- lib/blockchain/chaindb.js | 4 +- lib/db/backends-browser.js | 16 - lib/db/backends.js | 28 - lib/db/index.js | 16 - lib/db/ldb.js | 100 --- lib/db/level.js | 139 ---- lib/db/lowlevelup.js | 1333 ----------------------------------- lib/db/memdb.js | 666 ----------------- lib/mempool/mempool.js | 4 +- lib/wallet/walletdb.js | 4 +- migrate/chaindb1to2.js | 5 +- migrate/chaindb2to3.js | 4 +- migrate/ensure-tip-index.js | 5 +- 13 files changed, 14 insertions(+), 2310 deletions(-) delete mode 100644 lib/db/backends-browser.js delete mode 100644 lib/db/backends.js delete mode 100644 lib/db/index.js delete mode 100644 lib/db/ldb.js delete mode 100644 lib/db/level.js delete mode 100644 lib/db/lowlevelup.js delete mode 100644 lib/db/memdb.js diff --git a/lib/blockchain/chaindb.js b/lib/blockchain/chaindb.js index a1c1d228..d3aece8f 100644 --- a/lib/blockchain/chaindb.js +++ b/lib/blockchain/chaindb.js @@ -8,6 +8,7 @@ 'use strict'; const assert = require('assert'); +const BDB = require('bdb'); const util = require('../utils/util'); const BufferReader = require('../utils/reader'); const StaticWriter = require('../utils/staticwriter'); @@ -16,7 +17,6 @@ const encoding = require('../utils/encoding'); const Network = require('../protocol/network'); const CoinView = require('../coins/coinview'); const UndoCoins = require('../coins/undocoins'); -const LDB = require('../db/ldb'); const layout = require('./layout'); const LRU = require('../utils/lru'); const Block = require('../primitives/block'); @@ -51,7 +51,7 @@ function ChainDB(options) { this.network = this.options.network; 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.state = new ChainState(); this.pending = null; diff --git a/lib/db/backends-browser.js b/lib/db/backends-browser.js deleted file mode 100644 index 62189e99..00000000 --- a/lib/db/backends-browser.js +++ /dev/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; -}; diff --git a/lib/db/backends.js b/lib/db/backends.js deleted file mode 100644 index 0f589764..00000000 --- a/lib/db/backends.js +++ /dev/null @@ -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; - } -}; diff --git a/lib/db/index.js b/lib/db/index.js deleted file mode 100644 index 492be96a..00000000 --- a/lib/db/index.js +++ /dev/null @@ -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'); diff --git a/lib/db/ldb.js b/lib/db/ldb.js deleted file mode 100644 index fc0294e6..00000000 --- a/lib/db/ldb.js +++ /dev/null @@ -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; diff --git a/lib/db/level.js b/lib/db/level.js deleted file mode 100644 index 22c72021..00000000 --- a/lib/db/level.js +++ /dev/null @@ -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; diff --git a/lib/db/lowlevelup.js b/lib/db/lowlevelup.js deleted file mode 100644 index e0809f32..00000000 --- a/lib/db/lowlevelup.js +++ /dev/null @@ -1,1333 +0,0 @@ -/*! - * lowlevelup.js - LevelUP module 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 LOW = Buffer.from([0x00]); -const HIGH = Buffer.from([0xff]); -const DUMMY = Buffer.alloc(0); - -let VERSION_ERROR; - -/** - * Extremely low-level version of levelup. - * - * This avoids pulling in extra deps and - * lowers memory usage. - * - * @alias module:db.LowlevelUp - * @constructor - * @param {Function} backend - Database backend. - * @param {String} location - File location. - * @param {Object?} options - Leveldown options. - */ - -function LowlevelUp(backend, location, options) { - if (!(this instanceof LowlevelUp)) - return new LowlevelUp(backend, location, options); - - assert(typeof backend === 'function', 'Backend is required.'); - assert(typeof location === 'string', 'Filename is required.'); - - this.options = new LLUOptions(options); - this.backend = backend; - this.location = location; - - this.loading = false; - this.closing = false; - this.loaded = false; - - this.binding = null; - this.leveldown = false; - - this.init(); -} - -/** - * Initialize the database. - * @private - */ - -LowlevelUp.prototype.init = function init() { - const Backend = this.backend; - - let db = new Backend(this.location); - - // Stay as close to the metal as possible. - // We want to make calls to C++ directly. - while (db.db) { - // Not a database. - if (typeof db.db.put !== 'function') - break; - - // Recursive. - if (db.db === db) - break; - - // Go deeper. - db = db.db; - } - - // A lower-level binding. - if (db.binding) { - this.binding = db.binding; - this.leveldown = db !== db.binding; - } else { - this.binding = db; - } -}; - -/** - * Open the database. - * @returns {Promise} - */ - -LowlevelUp.prototype.open = async function open() { - if (this.loaded) - throw new Error('Database is already open.'); - - assert(!this.loading); - assert(!this.closing); - - this.loading = true; - - try { - await this.load(); - } catch (e) { - this.loading = false; - throw e; - } - - this.loading = false; - this.loaded = true; -}; - -/** - * Close the database. - * @returns {Promise} - */ - -LowlevelUp.prototype.close = async function close() { - if (!this.loaded) - throw new Error('Database is already closed.'); - - assert(!this.loading); - assert(!this.closing); - - this.loaded = false; - this.closing = true; - - try { - await this.unload(); - } catch (e) { - this.loaded = true; - this.closing = false; - throw e; - } - - this.closing = false; -}; - -/** - * Open the database. - * @private - * @returns {Promise} - */ - -LowlevelUp.prototype.load = function load() { - return new Promise((resolve, reject) => { - this.binding.open(this.options, wrap(resolve, reject)); - }); -}; - -/** - * Close the database. - * @private - * @returns {Promise} - */ - -LowlevelUp.prototype.unload = function unload() { - return new Promise((resolve, reject) => { - this.binding.close(wrap(resolve, reject)); - }); -}; - -/** - * Destroy the database. - * @returns {Promise} - */ - -LowlevelUp.prototype.destroy = function destroy() { - return new Promise((resolve, reject) => { - if (this.loaded || this.closing) { - reject(new Error('Cannot destroy open database.')); - return; - } - - if (!this.backend.destroy) { - reject(new Error('Cannot destroy (method not available).')); - return; - } - - this.backend.destroy(this.location, wrap(resolve, reject)); - }); -}; - -/** - * Repair the database. - * @returns {Promise} - */ - -LowlevelUp.prototype.repair = function repair() { - return new Promise((resolve, reject) => { - if (this.loaded || this.closing) { - reject(new Error('Cannot repair open database.')); - return; - } - - if (!this.backend.repair) { - reject(new Error('Cannot repair (method not available).')); - return; - } - - this.backend.repair(this.location, wrap(resolve, reject)); - }); -}; - -/** - * Backup the database. - * @param {String} path - * @returns {Promise} - */ - -LowlevelUp.prototype.backup = function backup(path) { - if (!this.binding.backup) - return this.clone(path); - - return new Promise((resolve, reject) => { - if (!this.loaded) { - reject(new Error('Database is closed.')); - return; - } - this.binding.backup(path, wrap(resolve, reject)); - }); -}; - -/** - * Retrieve a record from the database. - * @param {String|Buffer} key - * @returns {Promise} - Returns Buffer. - */ - -LowlevelUp.prototype.get = function get(key) { - return new Promise((resolve, reject) => { - if (!this.loaded) { - reject(new Error('Database is closed.')); - return; - } - this.binding.get(key, (err, result) => { - if (err) { - if (isNotFound(err)) { - resolve(null); - return; - } - reject(err); - return; - } - resolve(result); - }); - }); -}; - -/** - * Store a record in the database. - * @param {String|Buffer} key - * @param {Buffer} value - * @returns {Promise} - */ - -LowlevelUp.prototype.put = function put(key, value) { - if (!value) - value = LOW; - - return new Promise((resolve, reject) => { - if (!this.loaded) { - reject(new Error('Database is closed.')); - return; - } - this.binding.put(key, value, wrap(resolve, reject)); - }); -}; - -/** - * Remove a record from the database. - * @param {String|Buffer} key - * @returns {Promise} - */ - -LowlevelUp.prototype.del = function del(key) { - return new Promise((resolve, reject) => { - if (!this.loaded) { - reject(new Error('Database is closed.')); - return; - } - this.binding.del(key, wrap(resolve, reject)); - }); -}; - -/** - * Create an atomic batch. - * @returns {Batch} - */ - -LowlevelUp.prototype.batch = function batch() { - if (!this.loaded) - throw new Error('Database is closed.'); - - return new Batch(this); -}; - -/** - * Create a bucket. - * @param {Buffer} [prefix=DUMMY] - * @returns {Bucket} - */ - -LowlevelUp.prototype.bucket = function bucket(prefix) { - if (!this.loaded) - throw new Error('Database is closed.'); - - return new Bucket(this, this.batch(), prefix); -}; - -/** - * Create an iterator. - * @param {Object} options - * @returns {Iterator} - */ - -LowlevelUp.prototype.iterator = function iterator(options) { - if (!this.loaded) - throw new Error('Database is closed.'); - - return new Iterator(this, options); -}; - -/** - * Get a database property. - * @param {String} name - Property name. - * @returns {String} - */ - -LowlevelUp.prototype.getProperty = function getProperty(name) { - if (!this.loaded) - throw new Error('Database is closed.'); - - if (!this.binding.getProperty) - return ''; - - return this.binding.getProperty(name); -}; - -/** - * Calculate approximate database size. - * @param {String|Buffer} start - Start key. - * @param {String|Buffer} end - End key. - * @returns {Promise} - Returns Number. - */ - -LowlevelUp.prototype.approximateSize = function approximateSize(start, end) { - return new Promise((resolve, reject) => { - if (!this.loaded) { - reject(new Error('Database is closed.')); - return; - } - - if (!this.binding.approximateSize) { - reject(new Error('Cannot get size.')); - return; - } - - this.binding.approximateSize(start, end, wrap(resolve, reject)); - }); -}; - -/** - * Compact range of keys. - * @param {String|Buffer|null} start - Start key. - * @param {String|Buffer|null} end - End key. - * @returns {Promise} - */ - -LowlevelUp.prototype.compactRange = function compactRange(start, end) { - if (!start) - start = LOW; - - if (!end) - end = HIGH; - - return new Promise((resolve, reject) => { - if (!this.loaded) { - reject(new Error('Database is closed.')); - return; - } - - if (!this.binding.compactRange) { - resolve(); - return; - } - - this.binding.compactRange(start, end, wrap(resolve, reject)); - }); -}; - -/** - * Test whether a key exists. - * @param {String} key - * @returns {Promise} - Returns Boolean. - */ - -LowlevelUp.prototype.has = async function has(key) { - const value = await this.get(key); - return value != null; -}; - -/** - * Collect all keys from iterator options. - * @param {Object} options - Iterator options. - * @returns {Promise} - Returns Array. - */ - -LowlevelUp.prototype.range = function range(options) { - const iter = this.iterator({ - gte: options.gte, - lte: options.lte, - keys: true, - values: true - }); - return iter.range(options.parse); -}; - -/** - * Collect all keys from iterator options. - * @param {Object} options - Iterator options. - * @returns {Promise} - Returns Array. - */ - -LowlevelUp.prototype.keys = function keys(options) { - const iter = this.iterator({ - gte: options.gte, - lte: options.lte, - keys: true, - values: false - }); - return iter.keys(options.parse); -}; - -/** - * Collect all keys from iterator options. - * @param {Object} options - Iterator options. - * @returns {Promise} - Returns Array. - */ - -LowlevelUp.prototype.values = function values(options) { - const iter = this.iterator({ - gte: options.gte, - lte: options.lte, - keys: false, - values: true - }); - return iter.values(options.parse); -}; - -/** - * Dump database (for debugging). - * @returns {Promise} - Returns Object. - */ - -LowlevelUp.prototype.dump = async function dump() { - const records = Object.create(null); - - const items = await this.range({ - gte: LOW, - lte: HIGH - }); - - for (const item of items) { - const key = item.key.toString('hex'); - const value = item.value.toString('hex'); - records[key] = value; - } - - return records; -}; - -/** - * Write and assert a version number for the database. - * @param {Number} version - * @returns {Promise} - */ - -LowlevelUp.prototype.checkVersion = async function checkVersion(key, version) { - const data = await this.get(key); - - if (!data) { - const value = Buffer.allocUnsafe(4); - value.writeUInt32LE(version, 0, true); - const batch = this.batch(); - batch.put(key, value); - await batch.write(); - return; - } - - const num = data.readUInt32LE(0, true); - - if (num !== version) - throw new Error(VERSION_ERROR); -}; - -/** - * Clone the database. - * @param {String} path - * @returns {Promise} - */ - -LowlevelUp.prototype.clone = async function clone(path) { - if (!this.loaded) - throw new Error('Database is closed.'); - - const hwm = 256 << 20; - - const options = new LLUOptions(this.options); - options.createIfMissing = true; - options.errorIfExists = true; - - const tmp = new LowlevelUp(this.backend, path, options); - - await tmp.open(); - - const iter = this.iterator({ - keys: true, - values: true - }); - - let batch = tmp.batch(); - let total = 0; - - while (await iter.next()) { - const {key, value} = iter; - - batch.put(key, value); - - total += key.length + 80; - total += value.length + 80; - - if (total >= hwm) { - total = 0; - - try { - await batch.write(); - } catch (e) { - await iter.end(); - await tmp.close(); - throw e; - } - - batch = tmp.batch(); - } - } - - try { - await batch.write(); - } finally { - await tmp.close(); - } -}; - -/** - * Batch - * @constructor - * @ignore - * @param {LowlevelUp} db - */ - -function Batch(db) { - this.batch = db.binding.batch(); -} - -/** - * Write a value to the batch. - * @param {String|Buffer} key - * @param {Buffer} value - */ - -Batch.prototype.put = function put(key, value) { - if (!value) - value = LOW; - - this.batch.put(key, value); - - return this; -}; - -/** - * Delete a value from the batch. - * @param {String|Buffer} key - */ - -Batch.prototype.del = function del(key) { - this.batch.del(key); - return this; -}; - -/** - * Write batch to database. - * @returns {Promise} - */ - -Batch.prototype.write = function write() { - return new Promise((resolve, reject) => { - this.batch.write(wrap(resolve, reject)); - }); -}; - -/** - * Clear the batch. - */ - -Batch.prototype.clear = function clear() { - this.batch.clear(); - return this; -}; - -/** - * Bucket - * @constructor - * @ignore - * @param {LowlevelUp} db - * @param {Batch} batch - * @param {Buffer} [prefix=DUMMY] - */ - -function Bucket(db, batch, prefix, parent) { - this.db = db; - this.batch = batch; - this.prefix = prefix || DUMMY; - this.parent = parent || DUMMY; -} - -/** - * Get child bucket. - * @param {Buffer} [prefix=DUMMY] - */ - -Bucket.prototype.batch = function batch() { - return new Bucket(this.db, this.batch, this.prefix, this.parent); -}; - -/** - * Get child bucket. - * @param {Buffer} [prefix=DUMMY] - */ - -Bucket.prototype.bucket = function bucket(prefix = DUMMY) { - const parent = this.prefix; - const child = concat(parent, prefix); - return new Bucket(this.db, this.batch, child, parent); -}; - -/** - * Get child bucket. - * @param {Buffer} [prefix=DUMMY] - */ - -Bucket.prototype.up = function up() { - return new Bucket(this.db, this.batch, this.parent); -}; - -/** - * Get a value from the bucket. - * @param {String|Buffer} key - * @returns {Promise} - */ - -Bucket.prototype.has = function has(key) { - return this.db.has(concat(this.prefix, key)); -}; - -/** - * Get a value from the bucket. - * @param {String|Buffer} key - * @returns {Promise} - */ - -Bucket.prototype.get = function get(key) { - return this.db.get(concat(this.prefix, key)); -}; - -/** - * Create an iterator. - * @param {Object} options - * @returns {Iterator} - */ - -Bucket.prototype.iterator = function iterator(options) { - return new Iterator(this.db, options, this.prefix); -}; - -/** - * Collect all keys from iterator options. - * @param {Object} options - Iterator options. - * @returns {Promise} - Returns Array. - */ - -Bucket.prototype.range = function range(options = {}) { - const iter = this.iterator({ - gte: options.gte, - lte: options.lte, - keys: true, - values: true - }); - return iter.range(options.parse); -}; - -/** - * Collect all keys from iterator options. - * @param {Object} options - Iterator options. - * @returns {Promise} - Returns Array. - */ - -Bucket.prototype.keys = function keys(options = {}) { - const iter = this.iterator({ - gte: options.gte, - lte: options.lte, - keys: true, - values: false - }); - return iter.keys(options.parse); -}; - -/** - * Collect all keys from iterator options. - * @param {Object} options - Iterator options. - * @returns {Promise} - Returns Array. - */ - -Bucket.prototype.values = function values(options = {}) { - const iter = this.iterator({ - gte: options.gte, - lte: options.lte, - keys: false, - values: true - }); - return iter.values(options.parse); -}; - -/** - * Write a value to the bucket. - * @param {String|Buffer} key - * @param {Buffer} value - */ - -Bucket.prototype.put = function put(key, value) { - this.batch.put(concat(this.prefix, key), value); - return this; -}; - -/** - * Delete a value from the bucket. - * @param {String|Buffer} key - */ - -Bucket.prototype.del = function del(key) { - this.batch.del(concat(this.prefix, key)); - return this; -}; - -/** - * Write batch to database. - * @returns {Promise} - */ - -Bucket.prototype.write = function write() { - return this.batch.write(); -}; - -/** - * Clear the batch. - */ - -Bucket.prototype.clear = function clear() { - this.batch.clear(); - return this; -}; - -/** - * Iterator - * @constructor - * @ignore - * @param {LowlevelUp} db - * @param {Object} options - */ - -function Iterator(db, options, prefix) { - this.prefix = prefix || DUMMY; - this.options = new IteratorOptions(options, prefix); - this.options.keyAsBuffer = db.options.bufferKeys; - - this.iter = db.binding.iterator(this.options); - this.leveldown = db.leveldown; - - this.cache = []; - this.finished = false; - - this.key = null; - this.value = null; - this.valid = true; -} - -/** - * Clean up iterator. - * @private - */ - -Iterator.prototype.cleanup = function cleanup() { - this.cache = []; - this.finished = true; - this.key = null; - this.value = null; - this.valid = false; -}; - -/** - * For each. - * @returns {Promise} - */ - -Iterator.prototype.each = async function each(cb) { - assert(this.valid); - - const {keys, values} = this.options; - - while (!this.finished) { - await this.read(); - - while (this.cache.length > 0) { - const key = slice(this.prefix, this.cache.pop()); - const value = this.cache.pop(); - - let result = null; - - try { - if (keys && values) - result = cb(key, value); - else if (keys) - result = cb(key); - else if (values) - result = cb(value); - else - assert(false); - - if (result instanceof Promise) - result = await result; - } catch (e) { - await this.end(); - throw e; - } - - if (result === false) { - await this.end(); - break; - } - } - } -}; - -/** - * Seek to the next key. - * @returns {Promise} - */ - -Iterator.prototype.next = async function next() { - assert(this.valid); - - if (!this.finished) { - if (this.cache.length === 0) - await this.read(); - } - - if (this.cache.length > 0) { - this.key = slice(this.prefix, this.cache.pop()); - this.value = this.cache.pop(); - return true; - } - - assert(this.finished); - - this.cleanup(); - - return false; -}; - -/** - * Seek to the next key (buffer values). - * @private - * @returns {Promise} - */ - -Iterator.prototype.read = function read() { - return new Promise((resolve, reject) => { - if (!this.leveldown) { - this.iter.next((err, key, value) => { - if (err) { - this.cleanup(); - this.iter.end(() => reject(err)); - return; - } - - if (key === undefined && value === undefined) { - this.cleanup(); - this.iter.end(wrap(resolve, reject)); - return; - } - - this.cache = [value, key]; - - resolve(); - }); - return; - } - - this.iter.next((err, cache, finished) => { - if (err) { - this.cleanup(); - this.iter.end(() => reject(err)); - return; - } - - this.cache = cache; - this.finished = finished; - - resolve(); - }); - }); -}; - -/** - * Seek to an arbitrary key. - * @param {String|Buffer} key - */ - -Iterator.prototype.seek = function seek(key) { - assert(this.valid); - this.iter.seek(key); -}; - -/** - * End the iterator. - * @returns {Promise} - */ - -Iterator.prototype.end = function end() { - return new Promise((resolve, reject) => { - this.cleanup(); - this.iter.end(wrap(resolve, reject)); - }); -}; - -/** - * Collect all keys from iterator options. - * @param {Object} options - Iterator options. - * @returns {Promise} - Returns Array. - */ - -Iterator.prototype.range = async function range(parse) { - const items = []; - - await this.each((key, value) => { - if (parse) { - const item = parse(key, value); - if (item) - items.push(item); - } else { - items.push(new IteratorItem(key, value)); - } - }); - - return items; -}; - -/** - * Collect all keys from iterator options. - * @param {Object} options - Iterator options. - * @returns {Promise} - Returns Array. - */ - -Iterator.prototype.keys = async function keys(parse) { - const items = []; - - await this.each((key) => { - if (parse) - key = parse(key); - items.push(key); - }); - - return items; -}; - -/** - * Collect all keys from iterator options. - * @param {Object} options - Iterator options. - * @returns {Promise} - Returns Array. - */ - -Iterator.prototype.values = async function values(parse) { - const items = []; - - await this.each((value) => { - if (parse) - value = parse(value); - items.push(value); - }); - - return items; -}; - -/** - * Iterator Item - * @ignore - * @constructor - * @param {String|Buffer} key - * @param {String|Buffer} value - * @property {String|Buffer} key - * @property {String|Buffer} value - */ - -function IteratorItem(key, value) { - this.key = key; - this.value = value; -} - -/** - * LowlevelUp Options - * @constructor - * @ignore - * @param {Object} options - */ - -function LLUOptions(options) { - this.createIfMissing = true; - this.errorIfExists = false; - this.compression = true; - this.cacheSize = 8 << 20; - this.writeBufferSize = 4 << 20; - this.maxOpenFiles = 64; - this.maxFileSize = 2 << 20; - this.paranoidChecks = false; - this.memory = false; - this.sync = false; - this.mapSize = 256 * (1024 << 20); - this.writeMap = false; - this.noSubdir = true; - this.bufferKeys = true; - - if (options) - this.fromOptions(options); -} - -/** - * Inject properties from options. - * @private - * @param {Object} options - * @returns {LLUOptions} - */ - -LLUOptions.prototype.fromOptions = function fromOptions(options) { - assert(options, 'Options are required.'); - - if (options.createIfMissing != null) { - assert(typeof options.createIfMissing === 'boolean', - '`createIfMissing` must be a boolean.'); - this.createIfMissing = options.createIfMissing; - } - - if (options.errorIfExists != null) { - assert(typeof options.errorIfExists === 'boolean', - '`errorIfExists` must be a boolean.'); - this.errorIfExists = options.errorIfExists; - } - - if (options.compression != null) { - assert(typeof options.compression === 'boolean', - '`compression` must be a boolean.'); - this.compression = options.compression; - } - - if (options.cacheSize != null) { - assert(typeof options.cacheSize === 'number', - '`cacheSize` must be a number.'); - assert(options.cacheSize >= 0); - this.cacheSize = Math.floor(options.cacheSize / 2); - this.writeBufferSize = Math.floor(options.cacheSize / 4); - } - - if (options.maxFiles != null) { - assert(typeof options.maxFiles === 'number', - '`maxFiles` must be a number.'); - assert(options.maxFiles >= 0); - this.maxOpenFiles = options.maxFiles; - } - - if (options.maxFileSize != null) { - assert(typeof options.maxFileSize === 'number', - '`maxFileSize` must be a number.'); - assert(options.maxFileSize >= 0); - this.maxFileSize = options.maxFileSize; - } - - if (options.paranoidChecks != null) { - assert(typeof options.paranoidChecks === 'boolean', - '`paranoidChecks` must be a boolean.'); - this.paranoidChecks = options.paranoidChecks; - } - - if (options.memory != null) { - assert(typeof options.memory === 'boolean', - '`memory` must be a boolean.'); - this.memory = options.memory; - } - - if (options.sync != null) { - assert(typeof options.sync === 'boolean', - '`sync` must be a boolean.'); - this.sync = options.sync; - } - - if (options.mapSize != null) { - assert(typeof options.mapSize === 'number', - '`mapSize` must be a number.'); - assert(options.mapSize >= 0); - this.mapSize = options.mapSize; - } - - if (options.writeMap != null) { - assert(typeof options.writeMap === 'boolean', - '`writeMap` must be a boolean.'); - this.writeMap = options.writeMap; - } - - if (options.noSubdir != null) { - assert(typeof options.noSubdir === 'boolean', - '`noSubdir` must be a boolean.'); - this.noSubdir = options.noSubdir; - } - - if (options.bufferKeys != null) { - assert(typeof options.bufferKeys === 'boolean', - '`bufferKeys` must be a boolean.'); - this.bufferKeys = options.bufferKeys; - } - - return this; -}; - -/** - * Iterator Options - * @constructor - * @ignore - * @param {Object} options - */ - -function IteratorOptions(options, prefix) { - this.gte = null; - this.lte = null; - this.gt = null; - this.lt = null; - this.keys = true; - this.values = false; - this.fillCache = false; - this.keyAsBuffer = true; - this.valueAsBuffer = true; - this.reverse = false; - this.highWaterMark = 16 * 1024; - - // Note: do not add this property. - // this.limit = null; - - this.fromOptions(options || {}, prefix || DUMMY); -} - -/** - * Inject properties from options. - * @private - * @param {Object} options - * @returns {IteratorOptions} - */ - -IteratorOptions.prototype.fromOptions = function fromOptions(options, prefix) { - assert(options, 'Options are required.'); - - if (options.gte != null) { - assert(Buffer.isBuffer(options.gte) || typeof options.gte === 'string'); - this.gte = concat(prefix, options.gte); - } - - if (options.lte != null) { - assert(Buffer.isBuffer(options.lte) || typeof options.lte === 'string'); - this.lte = concat(prefix, options.lte); - } - - if (options.gt != null) { - assert(Buffer.isBuffer(options.gt) || typeof options.gt === 'string'); - this.gt = concat(prefix, options.gt); - } - - if (options.lt != null) { - assert(Buffer.isBuffer(options.lt) || typeof options.lt === 'string'); - this.lt = concat(prefix, options.lt); - } - - if (prefix.length > 0) { - if (!this.gt && !this.gte) - this.gt = prefix; - - if (!this.lt && !this.lte) { - const pre = Buffer.from(prefix); - for (let i = pre.length - 1; i >= 0; i--) { - if (pre[i] !== 0xff) { - pre[i] += 1; - break; - } - pre[i] = 0; - } - this.lt = pre; - } - } - - 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.fillCache != null) { - assert(typeof options.fillCache === 'boolean'); - this.fillCache = options.fillCache; - } - - if (options.keyAsBuffer != null) { - assert(typeof options.keyAsBuffer === 'boolean'); - this.keyAsBuffer = options.keyAsBuffer; - } - - if (options.reverse != null) { - assert(typeof options.reverse === 'boolean'); - this.reverse = options.reverse; - } - - if (options.limit != null) { - assert(typeof options.limit === 'number'); - assert(options.limit >= 0); - this.limit = options.limit; - } - - if (!this.keys && !this.values) - throw new Error('Keys and/or values must be chosen.'); - - return this; -}; - -/* - * Helpers - */ - -function isNotFound(err) { - if (!err) - return false; - - return err.notFound - || err.type === 'NotFoundError' - || /not\s*found/i.test(err.message); -} - -function wrap(resolve, reject) { - return function(err, result) { - if (err) { - reject(err); - return; - } - resolve(result); - }; -} - -function slice(prefix, key) { - if (!key || key.length === 0) - return key; - - if (prefix.length === 0) - return key; - - if (typeof key === 'string') { - if (Buffer.isBuffer(prefix)) - prefix = prefix.toString('ascii'); - assert(typeof prefix === 'string'); - assert(key.length > prefix.length); - return key.slice(prefix.length); - } - - assert(Buffer.isBuffer(key)); - assert(key.length > prefix.length); - - return key.slice(prefix.length); -} - -function concat(prefix, key) { - if (prefix.length === 0) - return key; - - if (typeof key === 'string') { - if (Buffer.isBuffer(prefix)) - prefix = prefix.toString('ascii'); - assert(typeof prefix === 'string'); - return prefix + key; - } - - assert(Buffer.isBuffer(key)); - - const data = Buffer.allocUnsafe(prefix.length + key.length); - - if (typeof prefix === 'string') { - data.write(prefix, 0, 'ascii'); - } else { - assert(Buffer.isBuffer(prefix)); - prefix.copy(data, 0); - } - - key.copy(data, prefix.length); - - return data; -} - -VERSION_ERROR = 'Warning:' - + ' Your database does not match the current database version.' - + ' This is likely because the database layout or serialization' - + ' format has changed drastically. If you want to dump your' - + ' data, downgrade to your previous version first. If you do' - + ' not think you should be seeing this error, post an issue on' - + ' the repo.'; - -/* - * Expose - */ - -module.exports = LowlevelUp; diff --git a/lib/db/memdb.js b/lib/db/memdb.js deleted file mode 100644 index 4fc4dc53..00000000 --- a/lib/db/memdb.js +++ /dev/null @@ -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; diff --git a/lib/mempool/mempool.js b/lib/mempool/mempool.js index 28479c45..972eaf3c 100644 --- a/lib/mempool/mempool.js +++ b/lib/mempool/mempool.js @@ -8,6 +8,7 @@ const assert = require('assert'); const path = require('path'); +const BDB = require('bdb'); const AsyncObject = require('../utils/asyncobject'); const common = require('../blockchain/common'); const consensus = require('../protocol/consensus'); @@ -26,7 +27,6 @@ const MempoolEntry = require('./mempoolentry'); const Network = require('../protocol/network'); const encoding = require('../utils/encoding'); const layout = require('./layout'); -const LDB = require('../db/ldb'); const Fees = require('./fees'); const CoinView = require('../coins/coinview'); const Heap = require('../utils/heap'); @@ -2372,7 +2372,7 @@ function MempoolCache(options) { this.batch = null; if (options.persistent) - this.db = LDB(options); + this.db = new BDB(options); } MempoolCache.VERSION = 2; diff --git a/lib/wallet/walletdb.js b/lib/wallet/walletdb.js index 20dfd668..435eec1d 100644 --- a/lib/wallet/walletdb.js +++ b/lib/wallet/walletdb.js @@ -9,6 +9,7 @@ const assert = require('assert'); const path = require('path'); +const BDB = require('bdb'); const AsyncObject = require('../utils/asyncobject'); const util = require('../utils/util'); const Lock = require('../utils/lock'); @@ -21,7 +22,6 @@ const Path = require('./path'); const common = require('./common'); const Wallet = require('./wallet'); const Account = require('./account'); -const LDB = require('../db/ldb'); const Bloom = require('../utils/bloom'); const Logger = require('../node/logger'); const Outpoint = require('../primitives/outpoint'); @@ -56,7 +56,7 @@ function WalletDB(options) { this.workers = this.options.workers; this.client = this.options.client || new NullClient(this); this.feeRate = this.options.feeRate; - this.db = LDB(this.options); + this.db = new BDB(this.options); this.primary = null; this.state = new ChainState(); diff --git a/migrate/chaindb1to2.js b/migrate/chaindb1to2.js index 3189267c..8547d1ad 100644 --- a/migrate/chaindb1to2.js +++ b/migrate/chaindb1to2.js @@ -1,6 +1,7 @@ 'use strict'; const assert = require('assert'); +const BDB = require('bdb'); const encoding = require('../lib/utils/encoding'); const networks = require('../lib/protocol/networks'); const co = require('../lib/utils/co'); @@ -11,7 +12,7 @@ const Coins = require('../lib/coins/coins'); const UndoCoins = require('../lib/coins/undocoins'); const Coin = require('../lib/primitives/coin'); const Output = require('../lib/primitives/output'); -const LDB = require('../lib/db/ldb'); + let file = process.argv[2]; let batch; @@ -19,7 +20,7 @@ assert(typeof file === 'string', 'Please pass in a database path.'); file = file.replace(/\.ldb\/?$/, ''); -const db = LDB({ +const db = new BDB({ location: file, db: 'leveldb', compression: true, diff --git a/migrate/chaindb2to3.js b/migrate/chaindb2to3.js index a4d7871f..98a910de 100644 --- a/migrate/chaindb2to3.js +++ b/migrate/chaindb2to3.js @@ -16,6 +16,7 @@ if (process.argv.indexOf('-h') !== -1 } const assert = require('assert'); +const BDB = require('bdb'); const encoding = require('../lib/utils/encoding'); const co = require('../lib/utils/co'); const util = require('../lib/utils/util'); @@ -28,7 +29,6 @@ const OldUndoCoins = require('./coins/undocoins'); const CoinEntry = require('../lib/coins/coinentry'); const UndoCoins = require('../lib/coins/undocoins'); const Block = require('../lib/primitives/block'); -const LDB = require('../lib/db/ldb'); const LRU = require('../lib/utils/lru'); const file = process.argv[2].replace(/\.ldb\/?$/, ''); @@ -37,7 +37,7 @@ let hasIndex = false; let hasPruned = false; let hasSPV = false; -const db = LDB({ +const db = new BDB({ location: file, db: 'leveldb', compression: true, diff --git a/migrate/ensure-tip-index.js b/migrate/ensure-tip-index.js index 6c6d0950..906de391 100644 --- a/migrate/ensure-tip-index.js +++ b/migrate/ensure-tip-index.js @@ -1,13 +1,14 @@ 'use strict'; const assert = require('assert'); +const BDB = require('bdb'); const encoding = require('../lib/utils/encoding'); const BufferReader = require('../lib/utils/reader'); const digest = require('bcrypto/lib/digest'); const util = require('../lib/utils/util'); -const LDB = require('../lib/db/ldb'); const BN = require('bcrypto/lib/bn'); const DUMMY = Buffer.from([0]); + let file = process.argv[2]; let batch; @@ -15,7 +16,7 @@ assert(typeof file === 'string', 'Please pass in a database path.'); file = file.replace(/\.ldb\/?$/, ''); -const db = LDB({ +const db = new BDB({ location: file, db: 'leveldb', compression: true,