@@ -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 }
0 commit comments