Comparing version 1.8.1 to 1.8.2
@@ -1,6 +0,5 @@ | ||
const Hyperbee = require('../../') | ||
const Hypercore = require('hypercore') | ||
const Hyperb = require('../../') | ||
const hypercore = require('hypercore') | ||
const core = new Hypercore('./db-clone', '95c4bff66d3faa78cf8c70bd070089e5e25b4c9bcbbf6ce5eb98e47b3129ca93') | ||
const db = new Hyperbee(core) | ||
const db = new Hyperb(hypercore('./db-clone', '95c4bff66d3faa78cf8c70bd070089e5e25b4c9bcbbf6ce5eb98e47b3129ca93', { sparse: true })) | ||
@@ -7,0 +6,0 @@ const swarm = require('@hyperswarm/replicator')(db.feed, { |
@@ -1,6 +0,5 @@ | ||
const Hyperbee = require('../../') | ||
const Hypercore = require('hypercore') | ||
const Hyperb = require('../../') | ||
const hypercore = require('hypercore') | ||
const core = new Hypercore('./db') | ||
const db = new Hyperbee(core) | ||
const db = new Hyperb(hypercore('./db', { sparse: true })) | ||
@@ -7,0 +6,0 @@ require('@hyperswarm/replicator')(db.feed, { |
143
index.js
@@ -270,3 +270,21 @@ const codecs = require('codecs') | ||
// we might wanna fold something like this into hypercore | ||
class ActiveRequests { | ||
constructor (feed) { | ||
this.feed = feed | ||
this.requests = new Set() | ||
} | ||
add (req) { | ||
this.requests.add(req) | ||
} | ||
remove (req) { | ||
this.requests.delete(req) | ||
} | ||
cancel () { | ||
for (const req of this.requests) this.feed.cancel(req) | ||
} | ||
} | ||
class HyperBee { | ||
@@ -312,13 +330,44 @@ constructor (feed, opts = {}) { | ||
async getRoot (ensureHeader, opts, batch = this) { | ||
await this.ready() | ||
if (ensureHeader) { | ||
if (this._feed.length === 0 && this._feed.writable && !this.readonly) { | ||
await this._feed.append(Header.encode({ | ||
protocol: 'hyperbee', | ||
metadata: this.metadata | ||
})) | ||
} | ||
} | ||
if (this._checkout === 0 && (opts && opts.update) !== false) await this.update() | ||
const len = this._checkout || this._feed.length | ||
if (len < 2) return null | ||
return (await batch.getBlock(len - 1, opts)).getTreeNode(0) | ||
} | ||
async getKey (seq) { | ||
return (await this.getBlock(seq)).key | ||
} | ||
async getBlock (seq, opts, batch = this) { | ||
const active = opts.active | ||
const request = this._feed.get(seq, { ...opts, valueEncoding: Node }) | ||
if (active) active.add(request) | ||
try { | ||
const entry = await request | ||
return new BlockEntry(seq, batch, entry) | ||
} finally { | ||
if (active) active.remove(request) | ||
} | ||
} | ||
async peek (opts) { | ||
// copied from the batch since we can then use the iterator warmup ext... | ||
// TODO: figure out how to not simply copy the code | ||
const ite = this.createRangeIterator({ ...opts, limit: 1 }) | ||
await ite.open() | ||
const block = await ite.next() | ||
await ite.close() | ||
return block | ||
return ite.next() | ||
} | ||
createRangeIterator (opts = {}) { | ||
createRangeIterator (opts = {}, active = null) { | ||
const extension = (opts.extension === false && opts.limit !== 0) ? null : this.extension | ||
@@ -334,2 +383,3 @@ | ||
sub: this._sub, | ||
active, | ||
onseq (seq) { | ||
@@ -349,6 +399,6 @@ if (!version) version = seq + 1 | ||
} else { | ||
opts = encRange(this.keyEncoding, { ...opts, sub: this._sub }) | ||
opts = encRange(this.keyEncoding, { ...opts, sub: this._sub, active }) | ||
} | ||
const ite = new RangeIterator(new Batch(this, this._feed.snapshot(), null, false, opts), opts) | ||
const ite = new RangeIterator(new Batch(this, null, false, opts), opts) | ||
return ite | ||
@@ -358,26 +408,26 @@ } | ||
createReadStream (opts) { | ||
return iteratorToStream(this.createRangeIterator(opts)) | ||
return iteratorToStream(this.createRangeIterator(opts, new ActiveRequests(this._feed))) | ||
} | ||
createHistoryStream (opts) { | ||
const session = (opts && opts.live) ? this._feed.session() : this._feed.snapshot() | ||
return iteratorToStream(new HistoryIterator(new Batch(this, session, null, false, opts), opts)) | ||
const active = new ActiveRequests(this._feed) | ||
opts = { active, ...opts } | ||
return iteratorToStream(new HistoryIterator(new Batch(this, null, false, opts), opts), active) | ||
} | ||
createDiffStream (right, opts) { | ||
const active = new ActiveRequests(this._feed) | ||
if (typeof right === 'number') right = this.checkout(Math.max(1, right)) | ||
const snapshot = right.version > this.version ? right._feed.snapshot() : this._feed.snapshot() | ||
if (this.keyEncoding) opts = encRange(this.keyEncoding, { ...opts, sub: this._sub }) | ||
return iteratorToStream(new DiffIterator(new Batch(this, snapshot, null, false, opts), new Batch(right, snapshot, null, false, opts), opts)) | ||
if (this.keyEncoding) opts = encRange(this.keyEncoding, { ...opts, sub: this._sub, active }) | ||
else opts = { ...opts, active } | ||
return iteratorToStream(new DiffIterator(new Batch(this, null, false, opts), new Batch(right, null, false, opts), opts), active) | ||
} | ||
async get (key, opts) { | ||
const b = new Batch(this, this._feed.snapshot(), null, true, opts) | ||
const block = await b.get(key) | ||
await b.close() | ||
return block | ||
get (key, opts) { | ||
const b = new Batch(this, null, true, { ...opts }) | ||
return b.get(key) | ||
} | ||
put (key, value, opts) { | ||
const b = new Batch(this, this._feed, null, true, opts) | ||
const b = new Batch(this, null, true, opts) | ||
return b.put(key, value) | ||
@@ -387,7 +437,7 @@ } | ||
batch (opts) { | ||
return new Batch(this, this._feed, mutexify(), true, opts) | ||
return new Batch(this, mutexify(), true, opts) | ||
} | ||
del (key, opts) { | ||
const b = new Batch(this, this._feed, null, true, opts) | ||
const b = new Batch(this, null, true, opts) | ||
return b.del(key) | ||
@@ -397,3 +447,3 @@ } | ||
checkout (version) { | ||
return new HyperBee(this._feed.snapshot(), { | ||
return new HyperBee(this._feed, { | ||
_ready: this.ready(), | ||
@@ -435,12 +485,7 @@ _sub: false, | ||
} | ||
close () { | ||
return this._feed.close() | ||
} | ||
} | ||
class Batch { | ||
constructor (tree, feed, batchLock, cache, options = {}) { | ||
constructor (tree, batchLock, cache, options = {}) { | ||
this.tree = tree | ||
this.feed = feed | ||
this.keyEncoding = tree.keyEncoding | ||
@@ -471,19 +516,8 @@ this.valueEncoding = tree.valueEncoding | ||
get version () { | ||
return Math.max(1, this.tree._checkout ? this.tree._checkout : this.feed.length + this.length) | ||
return this.tree.version + this.length | ||
} | ||
async getRoot (ensureHeader, opts) { | ||
opts = { ...opts, ...this.options } | ||
await this.ready() | ||
if (ensureHeader) { | ||
if (this.feed.length === 0 && this.feed.writable && !this.tree.readonly) { | ||
await this.feed.append(Header.encode({ | ||
protocol: 'hyperbee', | ||
metadata: this.tree.metadata | ||
})) | ||
} | ||
} | ||
if (this.tree._checkout === 0 && (opts && opts.update) !== false) await this.feed.update() | ||
if (this.version < 2) return null | ||
return (await this.getBlock(this.version - 1, opts)).getTreeNode(0) | ||
getRoot (ensureHeader) { | ||
if (this.root !== null) return this.root | ||
return this.tree.getRoot(ensureHeader, this.options, this) | ||
} | ||
@@ -495,3 +529,3 @@ | ||
async getBlock (seq, opts) { | ||
async getBlock (seq) { | ||
if (this.rootSeq === 0) this.rootSeq = seq | ||
@@ -501,4 +535,3 @@ let b = this.blocks && this.blocks.get(seq) | ||
this.onseq(seq) | ||
const entry = await this.feed.get(seq, { ...opts, valueEncoding: Node }) | ||
b = new BlockEntry(seq, this, entry) | ||
b = await this.tree.getBlock(seq, this.options, this) | ||
if (this.blocks) this.blocks.set(seq, b) | ||
@@ -574,3 +607,3 @@ return b | ||
const seq = this.feed.length + this.length | ||
const seq = this.tree._feed.length + this.length | ||
const target = new Key(seq, key) | ||
@@ -647,3 +680,3 @@ | ||
const seq = this.feed.length + this.length | ||
const seq = this.tree._feed.length + this.length | ||
@@ -771,6 +804,2 @@ while (true) { | ||
} | ||
close () { | ||
return this.feed.close() | ||
} | ||
} | ||
@@ -844,10 +873,7 @@ | ||
function iteratorToStream (ite) { | ||
function iteratorToStream (ite, active) { | ||
let done | ||
let closing | ||
const rs = new Readable({ | ||
predestroy () { | ||
closing = ite.close() | ||
closing.catch(noop) | ||
if (active) active.cancel() | ||
}, | ||
@@ -861,7 +887,2 @@ open (cb) { | ||
ite.next().then(push, fin) | ||
}, | ||
destroy (cb) { | ||
done = cb | ||
if (!closing) closing = ite.close() | ||
closing.then(fin, fin) | ||
} | ||
@@ -868,0 +889,0 @@ }) |
@@ -67,4 +67,4 @@ class SubTree { | ||
class TreeIterator { | ||
constructor (batch, opts) { | ||
this.batch = batch | ||
constructor (db, opts) { | ||
this.db = db | ||
this.stack = [] | ||
@@ -79,3 +79,3 @@ this.lt = opts.lt || opts.lte || null | ||
async open () { | ||
const node = await this.batch.getRoot(false) | ||
const node = await this.db.getRoot(false) | ||
if (!node || !node.keys.length) return | ||
@@ -130,3 +130,3 @@ const tree = new SubTree(node, null) | ||
this.seeking = false | ||
return this.batch.getBlock(seq) | ||
return this.db.getBlock(seq) | ||
} | ||
@@ -142,6 +142,2 @@ | ||
} | ||
close () { | ||
return this.batch.close() | ||
} | ||
} | ||
@@ -160,6 +156,2 @@ | ||
async close () { | ||
await Promise.all([this.left.close(), this.right.close()]) | ||
} | ||
async next () { | ||
@@ -166,0 +158,0 @@ if (this.limit === 0) return null |
module.exports = class HistoryIterator { | ||
constructor (batch, opts = {}) { | ||
this.batch = batch | ||
constructor (db, opts = {}) { | ||
this.db = db | ||
this.options = opts | ||
@@ -16,5 +16,5 @@ this.live = !!opts.live | ||
async open () { | ||
await this.batch.getRoot(false) // does the update dance | ||
this.gte = gte(this.options, this.batch.version) | ||
this.lt = this.live ? Infinity : lt(this.options, this.batch.version) | ||
await this.db.getRoot(false) // does the update dance | ||
this.gte = gte(this.options, this.db.version) | ||
this.lt = this.live ? Infinity : lt(this.options, this.db.version) | ||
} | ||
@@ -30,11 +30,7 @@ | ||
if (this.lt <= 1) return null | ||
return final(await this.batch.getBlock(--this.lt, this.options)) | ||
return final(await this.db.getBlock(--this.lt, this.options)) | ||
} | ||
return final(await this.batch.getBlock(this.gte++, this.options)) | ||
return final(await this.db.getBlock(this.gte++, this.options)) | ||
} | ||
close () { | ||
return this.batch.close() | ||
} | ||
} | ||
@@ -41,0 +37,0 @@ |
module.exports = class RangeIterator { | ||
constructor (batch, opts = {}) { | ||
this.batch = batch | ||
constructor (db, opts = {}) { | ||
this.db = db | ||
this.stack = [] | ||
@@ -53,3 +53,3 @@ this.opened = false | ||
this.stack.push({ | ||
node: (await this.batch.getBlock(seq)).getTreeNode(offset), | ||
node: (await this.db.getBlock(seq)).getTreeNode(offset), | ||
i | ||
@@ -63,3 +63,3 @@ }) | ||
let node = await this.batch.getRoot(false) | ||
let node = await this.db.getRoot(false) | ||
if (!node) { | ||
@@ -146,3 +146,3 @@ this._nexting = false | ||
const key = top.node.keys[n] | ||
const block = await this.batch.getBlock(key.seq) | ||
const block = await this.db.getBlock(key.seq) | ||
if (end) { | ||
@@ -163,6 +163,2 @@ const c = Buffer.compare(block.key, end) | ||
} | ||
close () { | ||
return this.batch.close() | ||
} | ||
} |
{ | ||
"name": "hyperbee", | ||
"version": "1.8.1", | ||
"version": "1.8.2", | ||
"description": "An append-only Btree running on a Hypercore.", | ||
@@ -14,3 +14,3 @@ "main": "index.js", | ||
"devDependencies": { | ||
"hypercore": "next", | ||
"hypercore": "^9.5.0", | ||
"protocol-buffers": "^4.2.0", | ||
@@ -17,0 +17,0 @@ "random-access-memory": "^3.1.1", |
@@ -1,6 +0,4 @@ | ||
const ram = require('random-access-memory') | ||
const tape = require('tape') | ||
const { create, collect } = require('./helpers') | ||
const Hypercore = require('hypercore') | ||
const Hyperbee = require('..') | ||
@@ -405,3 +403,4 @@ | ||
tape('feed is unwrapped in getter', async t => { | ||
const feed = new Hypercore(ram) | ||
const Hypercore = require('hypercore') | ||
const feed = new Hypercore(require('random-access-memory')) | ||
const db = new Hyperbee(feed) | ||
@@ -408,0 +407,0 @@ await db.ready() |
@@ -1,6 +0,4 @@ | ||
const ram = require('random-access-memory') | ||
const Hyperbee = require('../../') | ||
const Hypercore = require('hypercore') | ||
const Hyperbee = require('../../') | ||
module.exports = { | ||
@@ -73,4 +71,5 @@ toString, | ||
function create (opts) { | ||
const feed = new Hypercore(ram) | ||
return new Hyperbee(feed, { keyEncoding: 'utf-8', valueEncoding: 'utf-8', ...opts }) | ||
opts = { keyEncoding: 'utf-8', valueEncoding: 'utf-8', ...opts } | ||
const feed = new Hypercore(require('random-access-memory')) | ||
return new Hyperbee(feed, opts) | ||
} |
@@ -165,4 +165,3 @@ const { createRange, collect } = require('./helpers') | ||
// TODO: Re-enable once request cancellation on snapshot.close is implemented | ||
tape.skip('live history can be destroyed', async function (t) { | ||
tape('live history can be destroyed', async function (t) { | ||
const db = await createRange(1) | ||
@@ -183,5 +182,3 @@ | ||
await new Promise(resolve => setTimeout(resolve, 1000)) | ||
return end | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
100497