Skip to content
This repository was archived by the owner on Dec 1, 2024. It is now read-only.

Commit 47fc4db

Browse files
committed
Add PriorityWorker to defer closing until put is done
1 parent ff5eaae commit 47fc4db

2 files changed

Lines changed: 45 additions & 7 deletions

File tree

binding.cc

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ struct BaseWorker {
290290
delete self;
291291
}
292292

293-
void DoComplete () {
293+
virtual void DoComplete () {
294294
if (status_.ok()) {
295295
return HandleOKCallback();
296296
}
@@ -309,7 +309,7 @@ struct BaseWorker {
309309
CallFunction(env_, callback, 1, &argv);
310310
}
311311

312-
void Queue () {
312+
virtual void Queue () {
313313
napi_queue_async_work(env_, asyncWork_);
314314
}
315315

@@ -333,6 +333,7 @@ struct Database {
333333
blockCache_(NULL),
334334
filterPolicy_(leveldb::NewBloomFilterPolicy(10)),
335335
currentIteratorId_(0),
336+
priorityWork_(0),
336337
pendingCloseWorker_(NULL) {}
337338

338339
~Database () {
@@ -407,24 +408,39 @@ struct Database {
407408

408409
void AttachIterator (uint32_t id, Iterator* iterator) {
409410
iterators_[id] = iterator;
411+
IncrementPriorityWork();
410412
}
411413

412414
void DetachIterator (uint32_t id) {
413415
iterators_.erase(id);
416+
DecrementPriorityWork();
417+
}
418+
419+
void IncrementPriorityWork () {
420+
++priorityWork_;
421+
}
414422

415-
if (iterators_.empty() && pendingCloseWorker_ != NULL) {
423+
void DecrementPriorityWork () {
424+
if (--priorityWork_ == 0 && pendingCloseWorker_ != NULL) {
416425
pendingCloseWorker_->Queue();
417426
pendingCloseWorker_ = NULL;
418427
}
419428
}
420429

430+
bool HasPriorityWork () {
431+
return priorityWork_ > 0;
432+
}
433+
421434
napi_env env_;
422435
leveldb::DB* db_;
423436
leveldb::Cache* blockCache_;
424437
const leveldb::FilterPolicy* filterPolicy_;
425438
uint32_t currentIteratorId_;
426439
BaseWorker *pendingCloseWorker_;
427440
std::map< uint32_t, Iterator * > iterators_;
441+
442+
private:
443+
uint32_t priorityWork_;
428444
};
429445

430446
/**
@@ -436,6 +452,28 @@ static void FinalizeDatabase (napi_env env, void* data, void* hint) {
436452
}
437453
}
438454

455+
/**
456+
* Base worker class for doing async work that defers closing the database.
457+
* @TODO Use this for Get-, Del-, Batch-, BatchWrite-, ApproximateSize- and CompactRangeWorker too.
458+
*/
459+
struct PriorityWorker : public BaseWorker {
460+
PriorityWorker (napi_env env, Database* database, napi_value callback, const char* resourceName)
461+
: BaseWorker(env, database, callback, resourceName) {
462+
}
463+
464+
virtual ~PriorityWorker () {}
465+
466+
void Queue () final {
467+
database_->IncrementPriorityWork();
468+
BaseWorker::Queue();
469+
}
470+
471+
void DoComplete () final {
472+
database_->DecrementPriorityWork();
473+
BaseWorker::DoComplete();
474+
}
475+
};
476+
439477
/**
440478
* Owns a leveldb iterator.
441479
*/
@@ -821,7 +859,7 @@ NAPI_METHOD(db_close) {
821859
napi_value callback = argv[1];
822860
CloseWorker* worker = new CloseWorker(env, database, callback);
823861

824-
if (database->iterators_.empty()) {
862+
if (!database->HasPriorityWork()) {
825863
worker->Queue();
826864
NAPI_RETURN_UNDEFINED();
827865
}
@@ -844,14 +882,14 @@ NAPI_METHOD(db_close) {
844882
/**
845883
* Worker class for putting key/value to the database
846884
*/
847-
struct PutWorker : public BaseWorker {
885+
struct PutWorker : public PriorityWorker {
848886
PutWorker (napi_env env,
849887
Database* database,
850888
napi_value callback,
851889
leveldb::Slice key,
852890
leveldb::Slice value,
853891
bool sync)
854-
: BaseWorker(env, database, callback, "leveldown.db.put"),
892+
: PriorityWorker(env, database, callback, "leveldown.db.put"),
855893
key_(key), value_(value) {
856894
options_.sync = sync;
857895
}

test/segfault-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const test = require('tape')
22
const testCommon = require('./common')
33

44
// Open issue: https://github.com/Level/leveldown/issues/157
5-
test.skip('close() does not segfault if there is a pending write', function (t) {
5+
test('close() does not segfault if there is a pending write', function (t) {
66
t.plan(3)
77

88
const db = testCommon.factory()

0 commit comments

Comments
 (0)