Skip to content

Commit

Permalink
Support signal option on iterators
Browse files Browse the repository at this point in the history
This is a new optional feature in `abstract-level` 2.0.0.

Category: addition
  • Loading branch information
vweevers committed Oct 20, 2024
1 parent 50e03dc commit 6e196dc
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 1 deletion.
25 changes: 24 additions & 1 deletion binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <map>
#include <vector>
#include <mutex>
#include <atomic>

/**
* Forward declarations.
Expand Down Expand Up @@ -943,6 +944,7 @@ struct Iterator final : public BaseIterator {
first_(true),
nexting_(false),
isClosing_(false),
aborted_(false),
ended_(false),
state_(state),
ref_(NULL) {
Expand All @@ -966,7 +968,7 @@ struct Iterator final : public BaseIterator {
size_t bytesRead = 0;
leveldb::Slice empty;

while (true) {
while (!aborted_) {
if (!first_) Next();
else first_ = false;

Expand Down Expand Up @@ -1005,6 +1007,7 @@ struct Iterator final : public BaseIterator {
bool first_;
bool nexting_;
bool isClosing_;
std::atomic<bool> aborted_;
bool ended_;
unsigned char* state_;
std::vector<Entry> cache_;
Expand Down Expand Up @@ -1819,6 +1822,16 @@ NAPI_METHOD(iterator_close) {
return promise;
}

/**
* Aborts a NextWorker (if any, eventually).
*/
NAPI_METHOD(iterator_abort) {
NAPI_ARGV(1);
NAPI_ITERATOR_CONTEXT();
iterator->aborted_ = true;
NAPI_RETURN_UNDEFINED();
}

/**
* Worker class for nexting an iterator.
*/
Expand All @@ -1842,6 +1855,15 @@ struct NextWorker final : public BaseWorker {
}

void HandleOKCallback (napi_env env, napi_deferred deferred) override {
if (iterator_->aborted_) {
napi_value err = CreateCodeError(env, "LEVEL_ABORTED", "Operation has been aborted");
napi_value name;
napi_create_string_utf8(env, "AbortError", NAPI_AUTO_LENGTH, &name);
napi_set_named_property(env, err, "name", name);
napi_reject_deferred(env, deferred, err);
return;
}

size_t size = iterator_->cache_.size();
napi_value jsArray;
napi_create_array_with_length(env, size, &jsArray);
Expand Down Expand Up @@ -2173,6 +2195,7 @@ NAPI_INIT() {
NAPI_EXPORT_FUNCTION(iterator_seek);
NAPI_EXPORT_FUNCTION(iterator_close);
NAPI_EXPORT_FUNCTION(iterator_nextv);
NAPI_EXPORT_FUNCTION(iterator_abort);

NAPI_EXPORT_FUNCTION(batch_do);
NAPI_EXPORT_FUNCTION(batch_init);
Expand Down
3 changes: 3 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ class ClassicLevel extends AbstractLevel {
additionalMethods: {
approximateSize: true,
compactRange: true
},
signals: {
iterators: true
}
}, options)

Expand Down
20 changes: 20 additions & 0 deletions iterator.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ class Iterator extends AbstractIterator {
this[kFirst] = true
this[kCache] = empty
this[kPosition] = 0
this[kAbort] = this[kAbort].bind(this)

// TODO: consider exposing iterator.signal in abstract-level
if (options.signal != null) {
this[kSignal] = options.signal
this[kSignal].addEventListener('abort', this[kAbort], { once: true })
} else {
this[kSignal] = null
}
}

_seek (target, options) {
Expand Down Expand Up @@ -81,9 +90,20 @@ class Iterator extends AbstractIterator {

async _close () {
this[kCache] = empty

if (this[kSignal] !== null) {
this[kSignal].removeEventListener('abort', this[kAbort])
this[kSignal] = null
}

return binding.iterator_close(this[kContext])
}

[kAbort] () {
this[kSignal] = null
binding.iterator_abort(this[kContext])
}

// Undocumented, exposed for tests only
get cached () {
return this[kCache].length - this[kPosition]
Expand Down

0 comments on commit 6e196dc

Please sign in to comment.