@@ -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,27 @@ static void FinalizeDatabase (napi_env env, void* data, void* hint) {
436452 }
437453}
438454
455+ /* *
456+ * Base worker class for doing async work that must delay closing the database.
457+ */
458+ struct PriorityWorker : public BaseWorker {
459+ PriorityWorker (napi_env env, Database* database, napi_value callback, const char * resourceName)
460+ : BaseWorker(env, database, callback, resourceName) {
461+ }
462+
463+ virtual ~PriorityWorker () {}
464+
465+ void Queue () final {
466+ database_->IncrementPriorityWork ();
467+ BaseWorker::Queue ();
468+ }
469+
470+ void DoComplete () final {
471+ database_->DecrementPriorityWork ();
472+ BaseWorker::DoComplete ();
473+ }
474+ };
475+
439476/* *
440477 * Owns a leveldb iterator.
441478 */
@@ -821,7 +858,7 @@ NAPI_METHOD(db_close) {
821858 napi_value callback = argv[1 ];
822859 CloseWorker* worker = new CloseWorker (env, database, callback);
823860
824- if (database->iterators_ . empty ()) {
861+ if (! database->HasPriorityWork ()) {
825862 worker->Queue ();
826863 NAPI_RETURN_UNDEFINED ();
827864 }
@@ -844,24 +881,24 @@ NAPI_METHOD(db_close) {
844881/* *
845882 * Worker class for putting key/value to the database
846883 */
847- struct PutWorker : public BaseWorker {
884+ struct PutWorker : public PriorityWorker {
848885 PutWorker (napi_env env,
849886 Database* database,
850887 napi_value callback,
851888 leveldb::Slice key,
852889 leveldb::Slice value,
853890 bool sync)
854- : BaseWorker (env, database, callback, " leveldown.db.put" ),
891+ : PriorityWorker (env, database, callback, " leveldown.db.put" ),
855892 key_ (key), value_(value) {
856893 options_.sync = sync;
857894 }
858895
859- virtual ~PutWorker () {
896+ ~PutWorker () final {
860897 DisposeSliceBuffer (key_);
861898 DisposeSliceBuffer (value_);
862899 }
863900
864- virtual void DoExecute () {
901+ void DoExecute () final {
865902 SetStatus (database_->Put (options_, key_, value_));
866903 }
867904
0 commit comments