Skip to content

Commit

Permalink
Remove prime optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
vweevers committed Dec 29, 2021
1 parent 2db5669 commit fc8af12
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 89 deletions.
122 changes: 45 additions & 77 deletions abstract-level.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ const kDefaultOptions = Symbol('defaultOptions')
const kTranscoder = Symbol('transcoder')
const kKeyEncoding = Symbol('keyEncoding')
const kValueEncoding = Symbol('valueEncoding')
const kPrime = Symbol('prime')
const noop = () => {}

function AbstractLevel (manifest, options) {
Expand All @@ -35,18 +34,14 @@ function AbstractLevel (manifest, options) {
options = getOptions(options)
EventEmitter.call(this)

const { keyEncoding, valueEncoding, passive, prime, ...forward } = options
const { keyEncoding, valueEncoding, passive, ...forward } = options

this[kResources] = new Set()
this[kOperations] = []
this[kDeferOpen] = true
this[kOptions] = forward
this[kStatus] = 'opening'

// Undocumented and experimental option.
// TODO: benchmark
this[kPrime] = prime === true

this.supports = supports(manifest, {
status: true,
promises: true,
Expand Down Expand Up @@ -294,13 +289,8 @@ AbstractLevel.prototype.get = function (key, options, callback) {
const valueFormat = valueEncoding.format

// Forward encoding options to the underlying store
if (options.keyEncoding !== keyFormat ||
options.valueEncoding !== valueFormat) {
options = {
...options,
keyEncoding: keyFormat,
valueEncoding: valueFormat
}
if (options.keyEncoding !== keyFormat || options.valueEncoding !== valueFormat) {
options = { ...options, keyEncoding: keyFormat, valueEncoding: valueFormat }
}

this._get(this.prefixKey(keyEncoding.encode(key), keyFormat), options, (err, value) => {
Expand Down Expand Up @@ -365,11 +355,7 @@ AbstractLevel.prototype.getMany = function (keys, options, callback) {

// Forward encoding options
if (options.keyEncoding !== keyFormat || options.valueEncoding !== valueFormat) {
options = {
...options,
keyEncoding: keyFormat,
valueEncoding: valueFormat
}
options = { ...options, keyEncoding: keyFormat, valueEncoding: valueFormat }
}

const mappedKeys = new Array(keys.length)
Expand Down Expand Up @@ -439,13 +425,8 @@ AbstractLevel.prototype.put = function (key, value, options, callback) {
const valueFormat = valueEncoding.format

// Forward encoding options
if (options.keyEncoding !== keyFormat ||
options.valueEncoding !== valueFormat) {
options = {
...options,
keyEncoding: keyFormat,
valueEncoding: valueFormat
}
if (options.keyEncoding !== keyFormat || options.valueEncoding !== valueFormat) {
options = { ...options, keyEncoding: keyFormat, valueEncoding: valueFormat }
}

const mappedKey = this.prefixKey(keyEncoding.encode(key), keyFormat)
Expand Down Expand Up @@ -542,66 +523,56 @@ AbstractLevel.prototype.batch = function (operations, options, callback) {
return callback[kPromise]
}

// Skip processing operations if another layer already did
const prime = this[kPrime] ? options.primed !== true : true
const mapped = prime ? new Array(operations.length) : operations
const mapped = new Array(operations.length)
const { keyEncoding: ke, valueEncoding: ve, ...forward } = options

let forward = options
for (let i = 0; i < operations.length; i++) {
if (typeof operations[i] !== 'object' || operations[i] === null) {
this.nextTick(callback, new TypeError('A batch operation must be an object'))
return callback[kPromise]
}

if (prime) {
const { keyEncoding: ke, valueEncoding: ve, ...rest } = options
const op = Object.assign({}, operations[i])

forward = rest
if (this[kPrime]) forward.primed = true
if (op.type !== 'put' && op.type !== 'del') {
this.nextTick(callback, new TypeError("A batch operation must have a type property that is 'put' or 'del'"))
return callback[kPromise]
}

for (let i = 0; i < operations.length; i++) {
if (typeof operations[i] !== 'object' || operations[i] === null) {
this.nextTick(callback, new TypeError('A batch operation must be an object'))
return callback[kPromise]
}
const err = this._checkKey(op.key)

const op = Object.assign({}, operations[i])
if (err) {
this.nextTick(callback, err)
return callback[kPromise]
}

if (op.type !== 'put' && op.type !== 'del') {
this.nextTick(callback, new TypeError("A batch operation must have a type property that is 'put' or 'del'"))
return callback[kPromise]
}
const db = op.sublevel != null ? op.sublevel : this
const keyEncoding = db.keyEncoding(op.keyEncoding || ke)
const keyFormat = keyEncoding.format

const err = this._checkKey(op.key)
op.key = db.prefixKey(keyEncoding.encode(op.key), keyFormat)
op.keyEncoding = keyFormat

if (err) {
this.nextTick(callback, err)
if (op.type === 'put') {
const valueErr = this._checkValue(op.value)

if (valueErr) {
this.nextTick(callback, valueErr)
return callback[kPromise]
}

const db = op.sublevel != null ? op.sublevel : this
const keyEncoding = db.keyEncoding(op.keyEncoding || ke)
const keyFormat = keyEncoding.format

op.key = db.prefixKey(keyEncoding.encode(op.key), keyFormat)
op.keyEncoding = keyFormat

if (op.type === 'put') {
const valueErr = this._checkValue(op.value)
const valueEncoding = db.valueEncoding(op.valueEncoding || ve)

if (valueErr) {
this.nextTick(callback, valueErr)
return callback[kPromise]
}

const valueEncoding = db.valueEncoding(op.valueEncoding || ve)

op.value = valueEncoding.encode(op.value)
op.valueEncoding = valueEncoding.format
}

// Prevent double prefixing
if (db !== this) {
op.sublevel = null
}
op.value = valueEncoding.encode(op.value)
op.valueEncoding = valueEncoding.format
}

mapped[i] = op
// Prevent double prefixing
if (db !== this) {
op.sublevel = null
}

mapped[i] = op
}

this._batch(mapped, forward, (err) => {
Expand Down Expand Up @@ -644,13 +615,10 @@ AbstractLevel.prototype.clear = function (options, callback) {
}

const original = options
const keyEncoding = this.keyEncoding(options.keyEncoding)

if (this[kPrime] ? options.primed !== true : true) {
const keyEncoding = this.keyEncoding(options.keyEncoding)
options = rangeOptions(options, keyEncoding)
options.keyEncoding = keyEncoding.format
if (this[kPrime]) options.primed = true
}
options = rangeOptions(options, keyEncoding)
options.keyEncoding = keyEncoding.format

this._clear(options, (err) => {
if (err) return callback(err)
Expand Down
5 changes: 1 addition & 4 deletions lib/abstract-sublevel.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ module.exports = function ({ AbstractLevel }) {
})
}

// TODO: use in every method
forward.prime = true
super(mergeManifests(parent, manifest), forward)

const prefix = (db.prefix || '') + separator + name + separator
Expand Down Expand Up @@ -188,8 +186,7 @@ const mergeManifests = function (parent, manifest) {
}

const supportsEncoding = function (parent, encoding) {
// Prefer a non-transcoded encoding, for optimal performance
// and so that "primed" arguments can be forwarded as-is.
// Prefer a non-transcoded encoding for optimal performance
return parent.supports.encodings[encoding]
? parent.keyEncoding(encoding).name === encoding
: false
Expand Down
12 changes: 4 additions & 8 deletions test/self/sublevel-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -493,35 +493,31 @@ test('sublevel operations are prefixed', function (t) {
lte: '!sub"',
keyEncoding: 'utf8',
reverse: false,
limit: -1,
primed: true
limit: -1
})

await test({ gt: 'a' }, {
gt: '!sub!a',
lte: '!sub"',
keyEncoding: 'utf8',
reverse: false,
limit: -1,
primed: true
limit: -1
})

await test({ gte: 'a', lt: 'x' }, {
gte: '!sub!a',
lt: '!sub!x',
keyEncoding: 'utf8',
reverse: false,
limit: -1,
primed: true
limit: -1
})

await test({ lte: 'x' }, {
gte: '!sub!',
lte: '!sub!x',
keyEncoding: 'utf8',
reverse: false,
limit: -1,
primed: true
limit: -1
})
})

Expand Down

0 comments on commit fc8af12

Please sign in to comment.