]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Backport r377688 to certified 1.8 to resolve astdb corruption issue.
authorJonathan Rose <jrose@digium.com>
Wed, 21 Aug 2013 22:55:29 +0000 (22:55 +0000)
committerJonathan Rose <jrose@digium.com>
Wed, 21 Aug 2013 22:55:29 +0000 (22:55 +0000)
(issue AST-1172)
Reported by: Guenther Kelleter

git-svn-id: https://origsvn.digium.com/svn/asterisk/certified/branches/1.8.15@397364 65c4cc65-6c06-0410-ace0-fbb531ad65f3

main/db.c

index 1c4ad1a2de86d6afe8378922c09a3c34db3d19aa..3e0bcad9962f9ffdbfd9afa606cb1ecb266c8bf0 100644 (file)
--- a/main/db.c
+++ b/main/db.c
@@ -109,12 +109,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 static DB *astdb;
 AST_MUTEX_DEFINE_STATIC(dblock);
 static ast_cond_t dbcond;
+static pthread_t syncthread;
+static int doexit;
 typedef int (*process_keys_cb)(DBT *key, DBT *value, const char *filter, void *data);
 
 static void db_sync(void);
 
 static int dbinit(void) 
 {
+       if (doexit) {
+               return -1;
+       }
        if (!astdb && !(astdb = dbopen(ast_config_AST_DB, O_CREAT | O_RDWR, AST_FILE_MODE, DB_BTREE, NULL))) {
                ast_log(LOG_WARNING, "Unable to open Asterisk database '%s': %s\n", ast_config_AST_DB, strerror(errno));
                return -1;
@@ -122,7 +127,6 @@ static int dbinit(void)
        return 0;
 }
 
-
 static inline int keymatch(const char *key, const char *prefix)
 {
        int preflen = strlen(prefix);
@@ -780,31 +784,84 @@ static void *db_sync_thread(void *data)
        ast_mutex_lock(&dblock);
        for (;;) {
                ast_cond_wait(&dbcond, &dblock);
+               if (doexit) {
+                       /*
+                        * We were likely awakened just to exit.  Sync anyway just in
+                        * case.
+                        */
+                       if (astdb) {
+                               astdb->sync(astdb, 0);
+                       }
+                       ast_mutex_unlock(&dblock);
+                       break;
+               }
+
                ast_mutex_unlock(&dblock);
+               /*
+                * Sleep so if we have a bunch of db puts in a row, they won't
+                * get written one at a time to the db but in a batch.
+                */
                sleep(1);
                ast_mutex_lock(&dblock);
+
+               /* The db should be successfully opened to get here. */
+               ast_assert(astdb != NULL);
                astdb->sync(astdb, 0);
+
+               if (doexit) {
+                       /* We were asked to exit while sleeping. */
+                       ast_mutex_unlock(&dblock);
+                       break;
+               }
        }
 
        return NULL;
 }
 
-int astdb_init(void)
+static void astdb_shutdown(void)
 {
-       pthread_t dont_care;
+       ast_cli_unregister_multiple(cli_database, ARRAY_LEN(cli_database));
+       ast_manager_unregister("DBGet");
+       ast_manager_unregister("DBPut");
+       ast_manager_unregister("DBDel");
+       ast_manager_unregister("DBDelTree");
+
+       ast_mutex_lock(&dblock);
+       doexit = 1;
+       db_sync();
+       ast_mutex_unlock(&dblock);
 
+       pthread_join(syncthread, NULL);
+
+#if defined(DEBUG_FD_LEAKS) && defined(close)
+/* DEBUG_FD_LEAKS causes conflicting define of close() in asterisk.h */
+#undef close
+#endif
+
+       if (astdb) {
+               astdb->close(astdb);
+               astdb = NULL;
+       }
+}
+
+int astdb_init(void)
+{
        ast_cond_init(&dbcond, NULL);
-       if (ast_pthread_create_background(&dont_care, NULL, db_sync_thread, NULL)) {
+       if (ast_pthread_create_background(&syncthread, NULL, db_sync_thread, NULL)) {
                return -1;
        }
 
+       ast_mutex_lock(&dblock);
        /* Ignore check_return warning from Coverity for dbinit below */
        dbinit();
+       ast_mutex_unlock(&dblock);
 
        ast_cli_register_multiple(cli_database, ARRAY_LEN(cli_database));
        ast_manager_register_xml("DBGet", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_dbget);
        ast_manager_register_xml("DBPut", EVENT_FLAG_SYSTEM, manager_dbput);
        ast_manager_register_xml("DBDel", EVENT_FLAG_SYSTEM, manager_dbdel);
        ast_manager_register_xml("DBDelTree", EVENT_FLAG_SYSTEM, manager_dbdeltree);
+
+       ast_register_atexit(astdb_shutdown);
        return 0;
 }