diff --git a/index.js b/index.js index e83f3b54..d8297fff 100644 --- a/index.js +++ b/index.js @@ -137,7 +137,8 @@ class TreeNode { if (cas) { const prev = await this.getKeyNode(mid) if (cas && !(await cas(prev.final(encoding), node))) return true - } else if (!this.block.tree.tree.putSameValue) { + } + if (!this.block.tree.tree.alwaysDuplicate) { const prev = await this.getKeyNode(mid) if (prev && b4a.equals(prev.value, enc(encoding.value, node.value))) return true } @@ -326,7 +327,7 @@ class Hyperbee extends ReadyResource { this.lock = opts.lock || mutexify() this.sep = opts.sep || SEP this.readonly = !!opts.readonly - this.putSameValue = opts.putSameValue !== false + this.alwaysDuplicate = opts.alwaysDuplicate !== false this.prefix = opts.prefix || null this._unprefixedKeyEncoding = this.keyEncoding @@ -825,7 +826,8 @@ class Batch { if (cas) { const prev = await node.getKeyNode(mid) if (cas && !(await cas(prev.final(encoding), newNode))) return this._unlockMaybe() - } else if (!this.tree.putSameValue) { + } + if (!this.tree.alwaysDuplicate) { const prev = await node.getKeyNode(mid) if (prev && b4a.equals(prev.value, value)) return this._unlockMaybe() } @@ -906,7 +908,14 @@ class Batch { c = b4a.compare(key, await node.getKey(mid)) if (c === 0) { - if (cas && !(await cas((await node.getKeyNode(mid)).final(encoding), delNode))) return this._unlockMaybe() + if (cas) { + const prev = await node.getKeyNode(mid) + if (!(await cas(prev.final(encoding), delNode))) return this._unlockMaybe() + } + if (!this.tree.alwaysDuplicate) { + const prev = await node.getKeyNode(mid) + if (!prev) return this._unlockMaybe() + } if (node.children.length) await setKeyToNearestLeaf(node, mid, stack) else node.removeKey(mid) // we mark these as changed late, so we don't rewrite them if it is a 404 diff --git a/test/basic.js b/test/basic.js index aff204d3..18d39974 100644 --- a/test/basic.js +++ b/test/basic.js @@ -539,40 +539,3 @@ test('get by seq', async function (t) { t.alike(await db.getBySeq(1), { key: '/a', value: '1' }) t.alike(await db.getBySeq(2), { key: '/b', value: '2' }) }) - -test('putSameValue - should not insert the same kv-pair twice', async function (t) { - const db1 = create() - const db2 = create({ putSameValue: false }) - - await db1.put('/a', '1') - await db2.put('/a', '1') - - const version = db1.version - - await db1.put('/a', '1') - await db2.put('/a', '1') - await db1.put('/a', '1') - await db2.put('/a', '1') - - t.is(db1.version, version + 2) - t.is(db2.version, version) -}) - -test('putSameValue - works on batch puts', async function (t) { - const db1 = create() - const db2 = create({ putSameValue: false }) - - const b1 = db1.batch() - const b2 = db2.batch() - - await b1.put('/a', '1') - await b2.put('/a', '1') - await b1.put('/a', '1') - await b2.put('/a', '1') - - await b1.flush() - await b2.flush() - - t.is(db1.version, 3) - t.is(db2.version, 2) -}) diff --git a/test/cas.js b/test/cas.js index 777f9cb0..f8ff5a15 100644 --- a/test/cas.js +++ b/test/cas.js @@ -508,3 +508,40 @@ test('flushing an empty batch after a "failed" cas op releases lock (allows prog b.destroy() } }) + +test('alwaysDuplicate - should not insert the same kv-pair twice', async function (t) { + const db1 = create() + const db2 = create({ alwaysDuplicate: false }) + + await db1.put('/a', '1') + await db2.put('/a', '1') + + const version = db1.version + + await db1.put('/a', '1') + await db2.put('/a', '1') + await db1.put('/a', '1') + await db2.put('/a', '1') + + t.is(db1.version, version + 2) + t.is(db2.version, version) +}) + +test('alwaysDuplicate - works on batch puts', async function (t) { + const db1 = create() + const db2 = create({ alwaysDuplicate: false }) + + const b1 = db1.batch() + const b2 = db2.batch() + + await b1.put('/a', '1') + await b2.put('/a', '1') + await b1.put('/a', '1') + await b2.put('/a', '1') + + await b1.flush() + await b2.flush() + + t.is(db1.version, 3) + t.is(db2.version, 2) +})