Prevent CDR backends from unregistering while billing data is in flight
authorMatthew Jordan <mjordan@digium.com>
Sun, 27 Oct 2013 20:04:17 +0000 (20:04 +0000)
committerMatthew Jordan <mjordan@digium.com>
Sun, 27 Oct 2013 20:04:17 +0000 (20:04 +0000)
This patch makes it so that CDR backends cannot be unregistered while active
CDR records exist. This helps to prevent billing data from being lost during
restarts and shutdowns.

Review: https://reviewboard.asterisk.org/r/2880/
........

Merged revisions 402081 from http://svn.asterisk.org/svn/asterisk/branches/12

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@402082 65c4cc65-6c06-0410-ace0-fbb531ad65f3

14 files changed:
addons/cdr_mysql.c
cdr/cdr_adaptive_odbc.c
cdr/cdr_csv.c
cdr/cdr_custom.c
cdr/cdr_manager.c
cdr/cdr_odbc.c
cdr/cdr_pgsql.c
cdr/cdr_radius.c
cdr/cdr_sqlite.c
cdr/cdr_sqlite3_custom.c
cdr/cdr_syslog.c
cdr/cdr_tds.c
include/asterisk/cdr.h
main/cdr.c

index 25b55b3..b00a3f3 100644 (file)
@@ -384,9 +384,11 @@ static int my_unload_module(int reload)
        }
 
        dbport = 0;
-       ast_cdr_unregister(name);
-       
-       return 0;
+       if (reload) {
+               return ast_cdr_backend_suspend(name);
+       } else {
+               return ast_cdr_unregister(name);
+       }
 }
 
 static int my_load_config_string(struct ast_config *cfg, const char *category, const char *variable, struct ast_str **field, const char *def)
@@ -660,7 +662,11 @@ static int my_load_module(int reload)
                return AST_MODULE_LOAD_FAILURE;
        }
 
-       res = ast_cdr_register(name, desc, mysql_log);
+       if (!reload) {
+               res = ast_cdr_register(name, desc, mysql_log);
+       } else {
+               res = ast_cdr_backend_unsuspend(name);
+       }
        if (res) {
                ast_log(LOG_ERROR, "Unable to register MySQL CDR handling\n");
        } else {
index 0a9cfdb..4078b79 100644 (file)
@@ -767,7 +767,10 @@ early_release:
 
 static int unload_module(void)
 {
-       ast_cdr_unregister(name);
+       if (ast_cdr_unregister(name)) {
+               return -1;
+       }
+
        if (AST_RWLIST_WRLOCK(&odbc_tables)) {
                ast_cdr_register(name, ast_module_info->description, odbc_log);
                ast_log(LOG_ERROR, "Unable to lock column list.  Unload failed.\n");
index a6f8a4d..1cc1747 100644 (file)
@@ -315,7 +315,10 @@ static int csv_log(struct ast_cdr *cdr)
 
 static int unload_module(void)
 {
-       ast_cdr_unregister(name);
+       if (ast_cdr_unregister(name)) {
+               return -1;
+       }
+
        loaded = 0;
        return 0;
 }
index 2a3b1a1..51235db 100644 (file)
@@ -184,7 +184,9 @@ static int custom_log(struct ast_cdr *cdr)
 
 static int unload_module(void)
 {
-       ast_cdr_unregister(name);
+       if (ast_cdr_unregister(name)) {
+               return -1;
+       }
 
        if (AST_RWLIST_WRLOCK(&sinks)) {
                ast_cdr_register(name, ast_module_info->description, custom_log);
index e3ae7a5..90c5dbd 100644 (file)
@@ -86,8 +86,9 @@ static int load_config(int reload)
        if (!cfg) {
                /* Standard configuration */
                ast_log(LOG_WARNING, "Failed to load configuration file. Module not activated.\n");
-               if (enablecdr)
-                       ast_cdr_unregister(name);
+               if (enablecdr) {
+                       ast_cdr_backend_suspend(name);
+               }
                enablecdr = 0;
                return -1;
        }
@@ -135,10 +136,11 @@ static int load_config(int reload)
 
        ast_config_destroy(cfg);
 
-       if (enablecdr && !newenablecdr)
-               ast_cdr_unregister(name);
-       else if (!enablecdr && newenablecdr)
-               ast_cdr_register(name, "Asterisk Manager Interface CDR Backend", manager_log);
+       if (!newenablecdr) {
+               ast_cdr_backend_suspend(name);
+       } else if (newenablecdr) {
+               ast_cdr_backend_unsuspend(name);
+       }
        enablecdr = newenablecdr;
 
        return 0;
@@ -210,7 +212,10 @@ static int manager_log(struct ast_cdr *cdr)
 
 static int unload_module(void)
 {
-       ast_cdr_unregister(name);
+       if (ast_cdr_unregister(name)) {
+               return -1;
+       }
+
        if (customfields)
                ast_free(customfields);
 
@@ -219,7 +224,12 @@ static int unload_module(void)
 
 static int load_module(void)
 {
+       if (ast_cdr_register(name, "Asterisk Manager Interface CDR Backend", manager_log)) {
+               return AST_MODULE_LOAD_DECLINE;
+       }
+
        if (load_config(0)) {
+               ast_cdr_unregister(name);
                return AST_MODULE_LOAD_DECLINE;
        }
 
index 022d752..be07a8a 100644 (file)
@@ -266,8 +266,10 @@ static int odbc_load_module(int reload)
        } while (0);
 
        if (ast_test_flag(&config, CONFIG_REGISTERED) && (!cfg || dsn == NULL || table == NULL)) {
-               ast_cdr_unregister(name);
+               ast_cdr_backend_suspend(name);
                ast_clear_flag(&config, CONFIG_REGISTERED);
+       } else {
+               ast_cdr_backend_unsuspend(name);
        }
 
        if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg != CONFIG_STATUS_FILEINVALID) {
@@ -283,7 +285,9 @@ static int load_module(void)
 
 static int unload_module(void)
 {
-       ast_cdr_unregister(name);
+       if (ast_cdr_unregister(name)) {
+               return -1;
+       }
 
        if (dsn) {
                ast_verb(11, "cdr_odbc: free dsn\n");
index dc73de4..6ac3897 100644 (file)
@@ -436,7 +436,10 @@ static void empty_columns(void)
 
 static int unload_module(void)
 {
-       ast_cdr_unregister(name);
+       if (ast_cdr_unregister(name)) {
+               return -1;
+       }
+
        ast_cli_unregister_multiple(cdr_pgsql_status_cli, ARRAY_LEN(cdr_pgsql_status_cli));
 
        PQfinish(conn);
index 2bf2002..1466808 100644 (file)
@@ -230,7 +230,10 @@ return_cleanup:
 
 static int unload_module(void)
 {
-       ast_cdr_unregister(name);
+       if (ast_cdr_unregister(name)) {
+               return -1;
+       }
+
        if (rh) {
                rc_destroy(rh);
                rh = NULL;
index 46aa42b..884837c 100644 (file)
@@ -191,7 +191,10 @@ static int sqlite_log(struct ast_cdr *cdr)
 
 static int unload_module(void)
 {
-       ast_cdr_unregister(name);
+       if (ast_cdr_unregister(name)) {
+               return -1;
+       }
+
        if (db) {
                sqlite_close(db);
        }
index 6012346..83dac6a 100644 (file)
@@ -289,7 +289,9 @@ static int write_cdr(struct ast_cdr *cdr)
 
 static int unload_module(void)
 {
-       ast_cdr_unregister(name);
+       if (ast_cdr_unregister(name)) {
+               return -1;
+       }
 
        free_config(0);
 
index dec4d65..de8cae4 100644 (file)
@@ -235,7 +235,9 @@ static int load_config(int reload)
 
 static int unload_module(void)
 {
-       ast_cdr_unregister(name);
+       if (ast_cdr_unregister(name)) {
+               return -1;
+       }
 
        if (AST_RWLIST_WRLOCK(&sinks)) {
                ast_cdr_register(name, ast_module_info->description, syslog_log);
index aef57b5..5a1312e 100644 (file)
@@ -443,6 +443,10 @@ failed:
 
 static int tds_unload_module(void)
 {
+       if (ast_cdr_unregister(name)) {
+               return -1;
+       }
+
        if (settings) {
                ast_mutex_lock(&tds_lock);
                mssql_disconnect();
@@ -452,8 +456,6 @@ static int tds_unload_module(void)
                ast_free(settings);
        }
 
-       ast_cdr_unregister(name);
-
        dbexit();
 
        return 0;
index 49acc61..801b1b4 100644 (file)
@@ -503,8 +503,27 @@ int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be);
  * \brief Unregister a CDR handling engine
  * \param name name of CDR handler to unregister
  * Unregisters a CDR by it's name
+ *
+ * \retval 0 The backend unregistered successfully
+ * \retval -1 The backend could not be unregistered at this time
+ */
+int ast_cdr_unregister(const char *name);
+
+/*!
+ * \brief Suspend a CDR backend temporarily
+ *
+  * \retval 0 The backend is suspdended
+  * \retval -1 The backend could not be suspended
+  */
+int ast_cdr_backend_suspend(const char *name);
+
+/*!
+ * \brief Unsuspend a CDR backend
+ *
+ * \retval 0 The backend was unsuspended
+ * \retval -1 The back could not be unsuspended
  */
-void ast_cdr_unregister(const char *name);
+int ast_cdr_backend_unsuspend(const char *name);
 
 /*!
  * \brief Disposition to a string
index d4c2b96..02056ec 100644 (file)
@@ -294,6 +294,7 @@ struct cdr_beitem {
        char desc[80];
        ast_cdrbe be;
        AST_RWLIST_ENTRY(cdr_beitem) list;
+       int suspended:1;
 };
 
 /*! \brief List of registered backends */
@@ -2581,6 +2582,42 @@ int ast_cdr_is_enabled(void)
        return ast_test_flag(&mod_cfg->general->settings, CDR_ENABLED);
 }
 
+int ast_cdr_backend_suspend(const char *name)
+{
+       int success = -1;
+       struct cdr_beitem *i = NULL;
+
+       AST_RWLIST_WRLOCK(&be_list);
+       AST_RWLIST_TRAVERSE(&be_list, i, list) {
+               if (!strcasecmp(name, i->name)) {
+                       ast_debug(3, "Suspending CDR backend %s\n", i->name);
+                       i->suspended = 1;
+                       success = 0;
+               }
+       }
+       AST_RWLIST_UNLOCK(&be_list);
+
+       return success;
+}
+
+int ast_cdr_backend_unsuspend(const char *name)
+{
+       int success = -1;
+       struct cdr_beitem *i = NULL;
+
+       AST_RWLIST_WRLOCK(&be_list);
+       AST_RWLIST_TRAVERSE(&be_list, i, list) {
+               if (!strcasecmp(name, i->name)) {
+                       ast_debug(3, "Unsuspending CDR backend %s\n", i->name);
+                       i->suspended = 0;
+                       success = 0;
+               }
+       }
+       AST_RWLIST_UNLOCK(&be_list);
+
+       return success;
+}
+
 int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
 {
        struct cdr_beitem *i = NULL;
@@ -2615,24 +2652,39 @@ int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
        return 0;
 }
 
-void ast_cdr_unregister(const char *name)
+int ast_cdr_unregister(const char *name)
 {
-       struct cdr_beitem *i = NULL;
+       struct cdr_beitem *match = NULL;
+       int active_count;
 
        AST_RWLIST_WRLOCK(&be_list);
-       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
-               if (!strcasecmp(name, i->name)) {
-                       AST_RWLIST_REMOVE_CURRENT(list);
+       AST_RWLIST_TRAVERSE(&be_list, match, list) {
+               if (!strcasecmp(name, match->name)) {
                        break;
                }
        }
-       AST_RWLIST_TRAVERSE_SAFE_END;
-       AST_RWLIST_UNLOCK(&be_list);
 
-       if (i) {
-               ast_verb(2, "Unregistered '%s' CDR backend\n", name);
-               ast_free(i);
+       if (!match) {
+               AST_RWLIST_UNLOCK(&be_list);
+               return 0;
+       }
+
+       active_count = ao2_container_count(active_cdrs_by_channel);
+
+       if (!match->suspended && active_count != 0) {
+               AST_RWLIST_UNLOCK(&be_list);
+               ast_log(AST_LOG_WARNING, "Unable to unregister CDR backend %s; %d CDRs are still active\n",
+                       name, active_count);
+               return -1;
        }
+
+       AST_RWLIST_REMOVE(&be_list, match, list);
+       AST_RWLIST_UNLOCK(&be_list);
+
+       ast_verb(2, "Unregistered '%s' CDR backend\n", name);
+       ast_free(match);
+
+       return 0;
 }
 
 struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr)
@@ -3159,7 +3211,9 @@ static void post_cdr(struct ast_cdr *cdr)
                }
                AST_RWLIST_RDLOCK(&be_list);
                AST_RWLIST_TRAVERSE(&be_list, i, list) {
-                       i->be(cdr);
+                       if (!i->suspended) {
+                               i->be(cdr);
+                       }
                }
                AST_RWLIST_UNLOCK(&be_list);
        }
@@ -3772,7 +3826,7 @@ static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_
                        ast_cli(a->fd, "    (none)\n");
                } else {
                        AST_RWLIST_TRAVERSE(&be_list, beitem, list) {
-                               ast_cli(a->fd, "    %s\n", beitem->name);
+                               ast_cli(a->fd, "    %s%s\n", beitem->name, beitem->suspended ? " (suspended) " : "");
                        }
                }
                AST_RWLIST_UNLOCK(&be_list);