@@ -726,6 +726,33 @@ NAPI_METHOD(db_init) {
726726 return result;
727727}
728728
729+ // Hook for when the environment exits.
730+ static void env_cleanup_hook (void * arg) {
731+ Database* database = (Database*)arg;
732+
733+ // Do everything that db_close() does but synchronously. We're expecting that
734+ // GC did not yet collect the database because that would be a user mistake (not
735+ // closing their db) made during the lifetime of (and within) the environment.
736+ // That's different from an environment being torn down (like the main process
737+ // or a worker thread) where it's our responsibility to clean up.
738+ if (database && database->db_ != NULL ) {
739+ std::map<uint32_t , Iterator*> iterators = database->iterators_ ;
740+ std::map<uint32_t , Iterator*>::iterator it;
741+
742+ for (it = iterators.begin (); it != iterators.end (); ++it) {
743+ Iterator* iterator = it->second ;
744+
745+ if (!iterator->ended_ ) {
746+ iterator->ended_ = true ;
747+ iterator->IteratorEnd ();
748+ }
749+ }
750+
751+ // Having ended the iterators (and released snapshots) we can safely close.
752+ database->CloseDatabase ();
753+ }
754+ }
755+
729756/* *
730757 * Worker class for opening a database.
731758 */
@@ -791,6 +818,11 @@ NAPI_METHOD(db_open) {
791818
792819 database->blockCache_ = leveldb::NewLRUCache (cacheSize);
793820
821+ // Register a hook for when the environment exits. Will be called after
822+ // already-scheduled napi_async_work items have finished, which gives us
823+ // the guarantee that no db operations will be in-flight at that time.
824+ napi_add_env_cleanup_hook (env, env_cleanup_hook, database);
825+
794826 napi_value callback = argv[3 ];
795827 OpenWorker* worker = new OpenWorker (env, database, callback, location,
796828 createIfMissing, errorIfExists,
@@ -833,6 +865,12 @@ NAPI_METHOD(db_close) {
833865 napi_value callback = argv[1 ];
834866 CloseWorker* worker = new CloseWorker (env, database, callback);
835867
868+ // Remove hook for when the environment exits. Don't need it anymore
869+ // because we're closing here and although that is asynchronous, the
870+ // environment will wait for already-scheduled napi_async_work items
871+ // to finish before exiting.
872+ napi_remove_env_cleanup_hook (env, env_cleanup_hook, database);
873+
836874 if (!database->HasPriorityWork ()) {
837875 worker->Queue ();
838876 NAPI_RETURN_UNDEFINED ();
0 commit comments