Skip to content

Commit

Permalink
Add db.getMany(keys)
Browse files Browse the repository at this point in the history
(cherry picked from commit Level/leveldown@50dc50b)
  • Loading branch information
vweevers committed Nov 27, 2021
1 parent f9f99ec commit e6ae598
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 3 deletions.
118 changes: 118 additions & 0 deletions binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,31 @@ static std::string* RangeOption (napi_env env, napi_value opts, const char* name
return NULL;
}

/**
* Converts an array containing Buffer or string keys to a vector.
* Empty elements are skipped.
*/
static std::vector<std::string>* KeyArray (napi_env env, napi_value arr) {
uint32_t length;
std::vector<std::string>* result = new std::vector<std::string>();

if (napi_get_array_length(env, arr, &length) == napi_ok) {
result->reserve(length);

for (uint32_t i = 0; i < length; i++) {
napi_value element;

if (napi_get_element(env, arr, i, &element) == napi_ok &&
StringOrBufferLength(env, element) > 0) {
LD_STRING_OR_BUFFER_TO_COPY(env, element, to);
result->emplace_back(toCh_, toSz_);
}
}
}

return result;
}

/**
* Calls a function.
*/
Expand Down Expand Up @@ -1184,6 +1209,98 @@ NAPI_METHOD(db_get) {
NAPI_RETURN_UNDEFINED();
}

/**
* Worker class for getting many values.
*/
struct GetManyWorker final : public PriorityWorker {
GetManyWorker (napi_env env,
Database* database,
const std::vector<std::string>* keys,
napi_value callback,
const bool valueAsBuffer,
const bool fillCache)
: PriorityWorker(env, database, callback, "leveldown.get.many"),
keys_(keys), valueAsBuffer_(valueAsBuffer) {
options_.fill_cache = fillCache;
options_.snapshot = database->NewSnapshot();
}

~GetManyWorker() {
delete keys_;
}

void DoExecute () override {
cache_.reserve(keys_->size());

for (const std::string& key: *keys_) {
std::string* value = new std::string();
leveldb::Status status = database_->Get(options_, key, *value);

if (status.ok()) {
cache_.push_back(value);
} else if (status.IsNotFound()) {
delete value;
cache_.push_back(NULL);
} else {
delete value;
for (const std::string* value: cache_) {
if (value != NULL) delete value;
}
SetStatus(status);
break;
}
}

database_->ReleaseSnapshot(options_.snapshot);
}

void HandleOKCallback (napi_env env, napi_value callback) override {
size_t size = cache_.size();
napi_value array;
napi_create_array_with_length(env, size, &array);

for (size_t idx = 0; idx < size; idx++) {
std::string* value = cache_[idx];
napi_value element;
Entry::Convert(env, value, valueAsBuffer_, &element);
napi_set_element(env, array, static_cast<uint32_t>(idx), element);
if (value != NULL) delete value;
}

napi_value argv[2];
napi_get_null(env, &argv[0]);
argv[1] = array;
CallFunction(env, callback, 2, argv);
}

private:
leveldb::ReadOptions options_;
const std::vector<std::string>* keys_;
const bool valueAsBuffer_;
std::vector<std::string*> cache_;
};

/**
* Gets many values from a database.
*/
NAPI_METHOD(db_get_many) {
NAPI_ARGV(4);
NAPI_DB_CONTEXT();

const std::vector<std::string>* keys = KeyArray(env, argv[1]);
napi_value options = argv[2];
const bool asBuffer = BooleanProperty(env, options, "asBuffer", true);
const bool fillCache = BooleanProperty(env, options, "fillCache", true);
napi_value callback = argv[3];

GetManyWorker* worker = new GetManyWorker(
env, database, keys, callback, asBuffer, fillCache
);

worker->Queue(env);
NAPI_RETURN_UNDEFINED();
}

/**
* Worker class for deleting a value from a database.
*/
Expand Down Expand Up @@ -1978,6 +2095,7 @@ NAPI_INIT() {
NAPI_EXPORT_FUNCTION(db_close);
NAPI_EXPORT_FUNCTION(db_put);
NAPI_EXPORT_FUNCTION(db_get);
NAPI_EXPORT_FUNCTION(db_get_many);
NAPI_EXPORT_FUNCTION(db_del);
NAPI_EXPORT_FUNCTION(db_clear);
NAPI_EXPORT_FUNCTION(db_approximate_size);
Expand Down
5 changes: 5 additions & 0 deletions leveldown.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function LevelDOWN (location) {
permanence: true,
seek: true,
clear: true,
getMany: true,
createIfMissing: true,
errorIfExists: true,
additionalMethods: {
Expand Down Expand Up @@ -59,6 +60,10 @@ LevelDOWN.prototype._get = function (key, options, callback) {
binding.db_get(this.context, key, options, callback)
}

LevelDOWN.prototype._getMany = function (keys, options, callback) {
binding.db_get_many(this.context, keys, options, callback)
}

LevelDOWN.prototype._del = function (key, options, callback) {
binding.db_del(this.context, key, options, callback)
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"prepublishOnly": "npm run dependency-check"
},
"dependencies": {
"abstract-leveldown": "^7.0.0",
"abstract-leveldown": "^7.2.0",
"napi-macros": "^2.0.0",
"node-gyp-build": "^4.3.0"
},
Expand Down
5 changes: 3 additions & 2 deletions test/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module.exports = suite.common({
return leveldown(tempy.directory())
},

// Opt-in to new clear() tests
clear: true
// Opt-in to new tests
clear: true,
getMany: true
})

0 comments on commit e6ae598

Please sign in to comment.