@@ -468,15 +468,6 @@ struct Database {
468468 uint32_t priorityWork_;
469469};
470470
471- /* *
472- * Runs when a Database is garbage collected.
473- */
474- static void FinalizeDatabase (napi_env env, void * data, void * hint) {
475- if (data) {
476- delete (Database*)data;
477- }
478- }
479-
480471/* *
481472 * Base worker class for doing async work that defers closing the database.
482473 */
@@ -713,11 +704,55 @@ struct Iterator {
713704 napi_ref ref_;
714705};
715706
707+ /* *
708+ * Hook for when the environment exits. This hook will be called after
709+ * already-scheduled napi_async_work items have finished, which gives us
710+ * the guarantee that no db operations will be in-flight at this time.
711+ */
712+ static void env_cleanup_hook (void * arg) {
713+ Database* database = (Database*)arg;
714+
715+ // Do everything that db_close() does but synchronously. We're expecting that GC
716+ // did not (yet) collect the database because that would be a user mistake (not
717+ // closing their db) made during the lifetime of the environment. That's different
718+ // from an environment being torn down (like the main process or a worker thread)
719+ // where it's our responsibility to clean up. Note also, the following code must
720+ // be a safe noop if called before db_open() or after db_close().
721+ if (database && database->db_ != NULL ) {
722+ std::map<uint32_t , Iterator*> iterators = database->iterators_ ;
723+ std::map<uint32_t , Iterator*>::iterator it;
724+
725+ for (it = iterators.begin (); it != iterators.end (); ++it) {
726+ Iterator* iterator = it->second ;
727+
728+ if (!iterator->ended_ ) {
729+ iterator->ended_ = true ;
730+ iterator->IteratorEnd ();
731+ }
732+ }
733+
734+ // Having ended the iterators (and released snapshots) we can safely close.
735+ database->CloseDatabase ();
736+ }
737+ }
738+
739+ /* *
740+ * Runs when a Database is garbage collected.
741+ */
742+ static void FinalizeDatabase (napi_env env, void * data, void * hint) {
743+ if (data) {
744+ Database* database = (Database*)data;
745+ napi_remove_env_cleanup_hook (env, env_cleanup_hook, database);
746+ delete database;
747+ }
748+ }
749+
716750/* *
717751 * Returns a context object for a database.
718752 */
719753NAPI_METHOD (db_init) {
720754 Database* database = new Database (env);
755+ napi_add_env_cleanup_hook (env, env_cleanup_hook, database);
721756
722757 napi_value result;
723758 NAPI_STATUS_THROWS (napi_create_external (env, database,
0 commit comments