Skip to content

Commit b95f5a9

Browse files
committed
Create snapshot for get() synchronously
Has a tiny performance cost, which I negated by optimizing the passing of options from JS to C++. The end result is faster than before. However, I didn't check if it blocks the event loop for a significant amount of time. Benchmarking concurrent gets might answer that, later. Ref Level/community#118.
1 parent 41db25f commit b95f5a9

File tree

2 files changed

+47
-5
lines changed

2 files changed

+47
-5
lines changed

binding.cc

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,20 @@ static bool BooleanProperty (napi_env env, napi_value obj, const char* key,
166166
return DEFAULT;
167167
}
168168

169+
/**
170+
* Returns a boolean value.
171+
* Returns 'DEFAULT' if the JS value is undefined or otherwise not a boolean.
172+
*/
173+
static bool BooleanValue (napi_env env, napi_value value, bool DEFAULT) {
174+
bool result;
175+
176+
if (napi_get_value_bool(env, value, &result) == napi_ok) {
177+
return result;
178+
} else {
179+
return DEFAULT;
180+
}
181+
}
182+
169183
enum Encoding { buffer, utf8, view };
170184

171185
/**
@@ -188,6 +202,19 @@ static Encoding GetEncoding (napi_env env, napi_value options, const char* optio
188202
return Encoding::utf8;
189203
}
190204

205+
/**
206+
* Returns internal Encoding enum by its equivalent numeric value.
207+
*/
208+
static Encoding GetEncoding (napi_env env, napi_value value) {
209+
int32_t result;
210+
211+
if (napi_get_value_int32(env, value, &result) == napi_ok) {
212+
return static_cast<Encoding>(result);
213+
}
214+
215+
return Encoding::utf8;
216+
}
217+
191218
/**
192219
* Returns a uint32 property 'key' from 'obj'.
193220
* Returns 'DEFAULT' if the property doesn't exist.
@@ -1140,6 +1167,7 @@ struct GetWorker final : public PriorityWorker {
11401167
key_(key),
11411168
encoding_(encoding) {
11421169
options_.fill_cache = fillCache;
1170+
options_.snapshot = database->NewSnapshot();
11431171
}
11441172

11451173
~GetWorker () {
@@ -1148,6 +1176,7 @@ struct GetWorker final : public PriorityWorker {
11481176

11491177
void DoExecute () override {
11501178
SetStatus(database_->Get(options_, key_, value_));
1179+
database_->ReleaseSnapshot(options_.snapshot);
11511180
}
11521181

11531182
void HandleOKCallback (napi_env env, napi_deferred deferred) override {
@@ -1167,14 +1196,13 @@ struct GetWorker final : public PriorityWorker {
11671196
* Gets a value from a database.
11681197
*/
11691198
NAPI_METHOD(db_get) {
1170-
NAPI_ARGV(3);
1199+
NAPI_ARGV(4);
11711200
NAPI_DB_CONTEXT();
11721201
NAPI_PROMISE();
11731202

11741203
leveldb::Slice key = ToSlice(env, argv[1]);
1175-
napi_value options = argv[2];
1176-
const Encoding encoding = GetEncoding(env, options, "valueEncoding");
1177-
const bool fillCache = BooleanProperty(env, options, "fillCache", true);
1204+
const Encoding encoding = GetEncoding(env, argv[2]);
1205+
const bool fillCache = BooleanValue(env, argv[3], true);
11781206

11791207
GetWorker* worker = new GetWorker(
11801208
env, database, deferred, key, encoding, fillCache

index.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,12 @@ class ClassicLevel extends AbstractLevel {
5656
}
5757

5858
async _get (key, options) {
59-
return binding.db_get(this[kContext], key, options)
59+
return binding.db_get(
60+
this[kContext],
61+
key,
62+
encodingEnum(options.valueEncoding),
63+
options.fillCache
64+
)
6065
}
6166

6267
async _getMany (keys, options) {
@@ -162,3 +167,12 @@ class ClassicLevel extends AbstractLevel {
162167
}
163168

164169
exports.ClassicLevel = ClassicLevel
170+
171+
// It's faster to read options in JS than to pass options objects to C++.
172+
const encodingEnum = function (encoding) {
173+
if (encoding === 'buffer') return 0
174+
if (encoding === 'utf8') return 1
175+
if (encoding === 'view') return 2
176+
177+
throw new Error(`Unknown encoding: ${encoding}`)
178+
}

0 commit comments

Comments
 (0)