Merge "jansson: Upgrade to 2.12."
authorKevin Harwell <kharwell@digium.com>
Thu, 29 Nov 2018 18:57:32 +0000 (12:57 -0600)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Thu, 29 Nov 2018 18:57:32 +0000 (12:57 -0600)
101 files changed:
CHANGES
UPGRADE.txt
apps/app_agent_pool.c
apps/app_confbridge.c
apps/app_meetme.c
apps/app_queue.c
apps/app_skel.c
apps/app_voicemail.c
apps/confbridge/conf_config_parser.c
apps/confbridge/confbridge_manager.c
channels/chan_console.c
channels/chan_iax2.c
channels/chan_motif.c
channels/chan_pjsip.c
channels/chan_sip.c
channels/chan_unistim.c
channels/pjsip/cli_commands.c
channels/sig_pri.c
configs/samples/ari.conf.sample
configs/samples/manager.conf.sample
funcs/func_dialgroup.c
funcs/func_lock.c
funcs/func_odbc.c
funcs/func_strings.c
include/asterisk/astobj2.h
include/asterisk/channel.h
include/asterisk/stasis_channels.h
main/aoc.c
main/app.c
main/astobj2_container.c
main/bridge.c
main/cdr.c
main/cel.c
main/channel.c
main/channel_internal_api.c
main/cli.c
main/config.c
main/config_options.c
main/core_local.c
main/datastore.c
main/endpoints.c
main/indications.c
main/manager.c
main/manager_bridges.c
main/manager_channels.c
main/media_index.c
main/message.c
main/named_acl.c
main/pbx.c
main/stasis.c
main/stasis_bridges.c
main/stasis_channels.c
main/taskprocessor.c
main/threadpool.c
main/xmldoc.c
pbx/pbx_realtime.c
res/ari/resource_bridges.c
res/ari/resource_channels.c
res/ari/resource_events.c
res/parking/parking_applications.c
res/parking/parking_bridge_features.c
res/res_agi.c
res/res_calendar.c
res/res_chan_stats.c
res/res_clialiases.c
res/res_config_sqlite3.c
res/res_corosync.c
res/res_fax.c
res/res_http_websocket.c
res/res_odbc.c
res/res_parking.c
res/res_phoneprov.c
res/res_pjsip/config_transport.c
res/res_pjsip/pjsip_configuration.c
res/res_pjsip/pjsip_transport_management.c
res/res_pjsip_exten_state.c
res/res_pjsip_mwi.c
res/res_pjsip_outbound_publish.c
res/res_pjsip_outbound_registration.c
res/res_pjsip_pubsub.c
res/res_pjsip_refer.c
res/res_pjsip_session.c
res/res_rtp_asterisk.c
res/res_sorcery_memory.c
res/res_sorcery_memory_cache.c
res/res_stasis.c
res/res_stasis_device_state.c
res/res_stasis_playback.c
res/res_stasis_recording.c
res/res_timing_pthread.c
res/res_xmpp.c
res/stasis/app.c
res/stasis/control.c
tests/test_astobj2.c
tests/test_astobj2_thrash.c
tests/test_astobj2_weaken.c
tests/test_cel.c
tests/test_config.c
tests/test_scoped_lock.c
tests/test_stasis_channels.c
tests/test_stasis_endpoints.c

diff --git a/CHANGES b/CHANGES
index 2c98062..111a030 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -19,6 +19,22 @@ chan_sip
      https://wiki.asterisk.org/wiki/x/tAHOAQ
      https://wiki.asterisk.org/wiki/x/hYCLAQ
 
+Channels
+------------------
+ * The core no longer uses the stasis cache for channels snapshots.
+   The following APIs are no longer available:
+       ast_channel_topic_cached()
+       ast_channel_topic_all_cached()
+   The ast_channel_cache_all() and ast_channel_cache_by_name() functions
+   now returns an ao2_container of ast_channel_snapshots rather than a
+   container of stasis_messages therefore you can't call stasis_cache
+   functions on it.
+   The ast_channel_topic_all() function now returns a normal topic,
+   not a cached one so you can't use stasis cache functions on it either.
+   The ast_channel_snapshot_type() stasis message now has the
+   ast_channel_snapshot_update structure as it's data.
+   ast_channel_snapshot_get_latest() still returns the latest snapshot.
+
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 16.0.0 to Asterisk 16.1.0 ------------
 ------------------------------------------------------------------------------
index 3cf8e27..c299d83 100644 (file)
@@ -43,3 +43,18 @@ res_parking:
 
 res_xmpp:
  - The JabberStatus application, deprecated in Asterisk 12, has been removed.
+
+Channels:
+ - The core no longer uses the stasis cache for channels snapshots.
+   The following APIs are no longer available:
+       ast_channel_topic_cached()
+       ast_channel_topic_all_cached()
+   The ast_channel_cache_all() and ast_channel_cache_by_name() functions
+   now returns an ao2_container of ast_channel_snapshots rather than a
+   container of stasis_messages therefore you can't call stasis_cache
+   functions on it.
+   The ast_channel_topic_all() function now returns a normal topic,
+   not a cached one so you can't use stasis cache functions on it either.
+   The ast_channel_snapshot_type() stasis message now has the
+   ast_channel_snapshot_update structure as it's data.
+   ast_channel_snapshot_get_latest() still returns the latest snapshot.
index 805c403..5bd6a4d 100644 (file)
@@ -1448,7 +1448,7 @@ static void send_agent_login(struct ast_channel *chan, const char *agent)
                return;
        }
 
-       ast_channel_publish_cached_blob(chan, ast_channel_agent_login_type(), blob);
+       ast_channel_publish_blob(chan, ast_channel_agent_login_type(), blob);
 }
 
 static void send_agent_logoff(struct ast_channel *chan, const char *agent, long logintime)
@@ -1464,7 +1464,7 @@ static void send_agent_logoff(struct ast_channel *chan, const char *agent, long
                return;
        }
 
-       ast_channel_publish_cached_blob(chan, ast_channel_agent_logoff_type(), blob);
+       ast_channel_publish_blob(chan, ast_channel_agent_logoff_type(), blob);
 }
 
 /*!
index 5936400..ad871e0 100644 (file)
@@ -4196,8 +4196,9 @@ static int load_module(void)
        }
 
        /* Create a container to hold the conference bridges */
-       conference_bridges = ao2_container_alloc(CONFERENCE_BRIDGE_BUCKETS,
-               conference_bridge_hash_cb, conference_bridge_cmp_cb);
+       conference_bridges = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               CONFERENCE_BRIDGE_BUCKETS,
+               conference_bridge_hash_cb, NULL, conference_bridge_cmp_cb);
        if (!conference_bridges) {
                unload_module();
                return AST_MODULE_LOAD_DECLINE;
index 40c0bd2..6984bd2 100644 (file)
@@ -1624,8 +1624,14 @@ static struct ast_conference *build_conf(const char *confno, const char *pin,
 
        ast_format_cap_append(cap_slin, ast_format_slin, 0);
        /* Make a new one */
-       if (!(cnf = ast_calloc(1, sizeof(*cnf))) ||
-               !(cnf->usercontainer = ao2_container_alloc(1, NULL, user_no_cmp))) {
+       cnf = ast_calloc(1, sizeof(*cnf));
+       if (!cnf) {
+               goto cnfout;
+       }
+
+       cnf->usercontainer = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               NULL, user_no_cmp);
+       if (!cnf->usercontainer) {
                goto cnfout;
        }
 
@@ -7395,13 +7401,6 @@ static void sla_station_destructor(void *obj)
        ast_string_field_free_memory(station);
 }
 
-static int sla_trunk_hash(const void *obj, const int flags)
-{
-       const struct sla_trunk *trunk = obj;
-
-       return ast_str_case_hash(trunk->name);
-}
-
 static int sla_trunk_cmp(void *obj, void *arg, int flags)
 {
        struct sla_trunk *trunk = obj, *trunk2 = arg;
@@ -7409,13 +7408,6 @@ static int sla_trunk_cmp(void *obj, void *arg, int flags)
        return !strcasecmp(trunk->name, trunk2->name) ? CMP_MATCH | CMP_STOP : 0;
 }
 
-static int sla_station_hash(const void *obj, const int flags)
-{
-       const struct sla_station *station = obj;
-
-       return ast_str_case_hash(station->name);
-}
-
 static int sla_station_cmp(void *obj, void *arg, int flags)
 {
        struct sla_station *station = obj, *station2 = arg;
@@ -7869,8 +7861,10 @@ static int sla_load_config(int reload)
        if (!reload) {
                ast_mutex_init(&sla.lock);
                ast_cond_init(&sla.cond, NULL);
-               sla_trunks = ao2_container_alloc(1, sla_trunk_hash, sla_trunk_cmp);
-               sla_stations = ao2_container_alloc(1, sla_station_hash, sla_station_cmp);
+               sla_trunks = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+                       NULL, sla_trunk_cmp);
+               sla_stations = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+                       NULL, sla_station_cmp);
        }
 
        if (!(cfg = ast_config_load(SLA_CONFIG_FILE, config_flags))) {
index 5bb8733..2e59bf6 100644 (file)
@@ -2800,10 +2800,11 @@ static void init_queue(struct call_queue *q)
        q->autopausedelay = 0;
        if (!q->members) {
                if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED) {
-                       /* linear strategy depends on order, so we have to place all members in a single bucket */
-                       q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
+                       /* linear strategy depends on order, so we have to place all members in a list */
+                       q->members = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, member_cmp_fn);
                } else {
-                       q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
+                       q->members = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 37,
+                               member_hash_fn, NULL, member_cmp_fn);
                }
        }
        q->found = 1;
@@ -5889,13 +5890,13 @@ static void queue_agent_cb(void *userdata, struct stasis_subscription *sub,
        agent_blob = stasis_message_data(msg);
 
        if (ast_channel_agent_login_type() == stasis_message_type(msg)) {
-               ast_queue_log("NONE", agent_blob->snapshot->uniqueid,
+               ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
                        ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
-                       "AGENTLOGIN", "%s", agent_blob->snapshot->name);
+                       "AGENTLOGIN", "%s", agent_blob->snapshot->base->name);
        } else if (ast_channel_agent_logoff_type() == stasis_message_type(msg)) {
-               ast_queue_log("NONE", agent_blob->snapshot->uniqueid,
+               ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
                        ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
-                       "AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->name,
+                       "AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->base->name,
                        (long) ast_json_integer_get(ast_json_object_get(agent_blob->blob, "logintime")));
        }
 }
@@ -6087,8 +6088,8 @@ static void log_attended_transfer(struct queue_stasis_data *queue_data, struct a
                ast_str_set(&transfer_str, 0, "APP|%s", atxfer_msg->dest.app);
                break;
        case AST_ATTENDED_TRANSFER_DEST_LINK:
-               ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->name,
-                               atxfer_msg->dest.links[1]->name);
+               ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->base->name,
+                               atxfer_msg->dest.links[1]->base->name);
                break;
        case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
        case AST_ATTENDED_TRANSFER_DEST_FAIL:
@@ -6097,7 +6098,7 @@ static void log_attended_transfer(struct queue_stasis_data *queue_data, struct a
                return;
        }
 
-       ast_queue_log(queue_data->queue->name, caller->uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
+       ast_queue_log(queue_data->queue->name, caller->base->uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
                        ast_str_buffer(transfer_str),
                        (long) (queue_data->starttime - queue_data->holdstart),
                        (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
@@ -6130,11 +6131,11 @@ static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub,
                return;
        }
 
-       if (!strcmp(enter_blob->channel->uniqueid, queue_data->caller_uniqueid)) {
+       if (!strcmp(enter_blob->channel->base->uniqueid, queue_data->caller_uniqueid)) {
                ast_string_field_set(queue_data, bridge_uniqueid,
                                enter_blob->bridge->uniqueid);
                ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
-                               enter_blob->channel->name, queue_data->bridge_uniqueid);
+                               enter_blob->channel->base->name, queue_data->bridge_uniqueid);
        }
 }
 
@@ -6185,7 +6186,7 @@ static void handle_blind_transfer(void *userdata, struct stasis_subscription *su
        context = transfer_msg->context;
 
        ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
-       ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername,
+       ast_queue_log(queue_data->queue->name, caller_snapshot->base->uniqueid, queue_data->member->membername,
                        "BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
                        exten, context,
                        (long) (queue_data->starttime - queue_data->holdstart),
@@ -6301,9 +6302,9 @@ static void handle_local_optimization_begin(void *userdata, struct stasis_subscr
                return;
        }
 
-       if (!strcmp(local_one->uniqueid, queue_data->member_uniqueid)) {
+       if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
                optimization = &queue_data->member_optimize;
-       } else if (!strcmp(local_two->uniqueid, queue_data->caller_uniqueid)) {
+       } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
                optimization = &queue_data->caller_optimize;
        } else {
                return;
@@ -6312,9 +6313,9 @@ static void handle_local_optimization_begin(void *userdata, struct stasis_subscr
        /* We only allow move-swap optimizations, so there had BETTER be a source */
        ast_assert(source != NULL);
 
-       optimization->source_chan_uniqueid = ast_strdup(source->uniqueid);
+       optimization->source_chan_uniqueid = ast_strdup(source->base->uniqueid);
        if (!optimization->source_chan_uniqueid) {
-               ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->name);
+               ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->base->name);
                return;
        }
        id = ast_json_integer_get(ast_json_object_get(ast_multi_channel_blob_get_json(optimization_blob), "id"));
@@ -6353,10 +6354,10 @@ static void handle_local_optimization_end(void *userdata, struct stasis_subscrip
                return;
        }
 
-       if (!strcmp(local_one->uniqueid, queue_data->member_uniqueid)) {
+       if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
                optimization = &queue_data->member_optimize;
                is_caller = 0;
-       } else if (!strcmp(local_two->uniqueid, queue_data->caller_uniqueid)) {
+       } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
                optimization = &queue_data->caller_optimize;
                is_caller = 1;
        } else {
@@ -6419,16 +6420,16 @@ static void handle_hangup(void *userdata, struct stasis_subscription *sub,
                return;
        }
 
-       if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->caller_uniqueid)) {
+       if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
                reason = CALLER;
-       } else if (!strcmp(channel_blob->snapshot->uniqueid, queue_data->member_uniqueid)) {
+       } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
                reason = AGENT;
        } else {
                ao2_unlock(queue_data);
                return;
        }
 
-       chan = ast_channel_get_by_name(channel_blob->snapshot->name);
+       chan = ast_channel_get_by_name(channel_blob->snapshot->base->name);
        if (chan && (ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME) ||
                     !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER")) ||
                     !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER")))) {
@@ -6445,9 +6446,9 @@ static void handle_hangup(void *userdata, struct stasis_subscription *sub,
        ao2_unlock(queue_data);
 
        ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
-                       channel_blob->snapshot->name);
+                       channel_blob->snapshot->base->name);
 
-       ast_queue_log(queue_data->queue->name, caller_snapshot->uniqueid, queue_data->member->membername,
+       ast_queue_log(queue_data->queue->name, caller_snapshot->base->uniqueid, queue_data->member->membername,
                        reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
                (long) (queue_data->starttime - queue_data->holdstart),
                (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
@@ -11240,13 +11241,14 @@ static int load_module(void)
        struct stasis_topic *queue_topic;
        struct stasis_topic *manager_topic;
 
-       queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
+       queues = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAX_QUEUE_BUCKETS,
+               queue_hash_cb, NULL, queue_cmp_cb);
        if (!queues) {
                return AST_MODULE_LOAD_DECLINE;
        }
 
-       pending_members = ao2_container_alloc(
-               MAX_CALL_ATTEMPT_BUCKETS, pending_members_hash, pending_members_cmp);
+       pending_members = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               MAX_CALL_ATTEMPT_BUCKETS, pending_members_hash, NULL, pending_members_cmp);
        if (!pending_members) {
                unload_module();
                return AST_MODULE_LOAD_DECLINE;
index e58f625..e0b8bca 100644 (file)
@@ -580,7 +580,9 @@ static void *skel_config_alloc(void)
                goto error;
        }
 
-       if (!(cfg->levels = ao2_container_alloc(LEVEL_BUCKETS, skel_level_hash, skel_level_cmp))) {
+       cfg->levels = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, LEVEL_BUCKETS,
+               skel_level_hash, NULL, skel_level_cmp);
+       if (!cfg->levels) {
                goto error;
        }
 
@@ -725,7 +727,9 @@ static int load_module(void)
        if (aco_info_init(&cfg_info)) {
                goto error;
        }
-       if (!(games = ao2_container_alloc(1, NULL, NULL))) {
+
+       games = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
+       if (!games) {
                goto error;
        }
 
index 554363a..595c2dc 100644 (file)
@@ -15066,11 +15066,14 @@ static int load_module(void)
        my_umask = umask(0);
        umask(my_umask);
 
-       if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
+       inprocess_container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 573,
+               inprocess_hash_fn, NULL, inprocess_cmp_fn);
+       if (!inprocess_container) {
                return AST_MODULE_LOAD_DECLINE;
        }
 
-       poll_list = ao2_container_alloc(POLL_LIST_BUCKETS, poll_state_hash_fn, poll_state_cmp_fn);
+       poll_list = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, POLL_LIST_BUCKETS,
+               poll_state_hash_fn, NULL, poll_state_cmp_fn);
        if (!poll_list) {
                ast_log(LOG_ERROR, "Unable to create poll_list container\n");
                ao2_cleanup(inprocess_container);
index 9e56b36..53061ba 100644 (file)
@@ -1987,15 +1987,21 @@ void *confbridge_cfg_alloc(void)
                return NULL;
        }
 
-       if (!(cfg->user_profiles = ao2_container_alloc(283, user_hash_cb, user_cmp_cb))) {
+       cfg->user_profiles = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 283,
+               user_hash_cb, NULL, user_cmp_cb);
+       if (!cfg->user_profiles) {
                goto error;
        }
 
-       if (!(cfg->bridge_profiles = ao2_container_alloc(283, bridge_hash_cb, bridge_cmp_cb))) {
+       cfg->bridge_profiles = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 283,
+               bridge_hash_cb, NULL, bridge_cmp_cb);
+       if (!cfg->bridge_profiles) {
                goto error;
        }
 
-       if (!(cfg->menus = ao2_container_alloc(283, menu_hash_cb, menu_cmp_cb))) {
+       cfg->menus = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 283,
+               menu_hash_cb, NULL, menu_cmp_cb);
+       if (!cfg->menus) {
                goto error;
        }
 
index e88bbc2..2d85033 100644 (file)
@@ -783,7 +783,7 @@ int manager_confbridge_init(void)
        }
 
        channel_state_router = stasis_message_router_create(
-               ast_channel_topic_all_cached());
+               ast_channel_topic_all());
 
        if (!channel_state_router) {
                manager_confbridge_shutdown();
index 7692b26..9113ffa 100644 (file)
@@ -1534,7 +1534,9 @@ static int load_module(void)
 
        init_pvt(&globals, NULL);
 
-       if (!(pvts = ao2_container_alloc(NUM_PVT_BUCKETS, pvt_hash_cb, pvt_cmp_cb)))
+       pvts = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NUM_PVT_BUCKETS,
+               pvt_hash_cb, NULL, pvt_cmp_cb);
+       if (!pvts)
                goto return_error;
 
        if (load_config(0))
index 0ca4234..6f88d09 100644 (file)
@@ -14714,23 +14714,54 @@ static int load_objects(void)
        peers = users = iax_peercallno_pvts = iax_transfercallno_pvts = NULL;
        peercnts = callno_limits = calltoken_ignores = NULL;
 
-       if (!(peers = ao2_container_alloc(MAX_PEER_BUCKETS, peer_hash_cb, peer_cmp_cb))) {
+       peers = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAX_PEER_BUCKETS,
+               peer_hash_cb, NULL, peer_cmp_cb);
+       if (!peers) {
                goto container_fail;
-       } else if (!(users = ao2_container_alloc(MAX_USER_BUCKETS, user_hash_cb, user_cmp_cb))) {
+       }
+
+       users = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAX_USER_BUCKETS,
+               user_hash_cb, NULL, user_cmp_cb);
+       if (!users) {
                goto container_fail;
-       } else if (!(iax_peercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, pvt_hash_cb, pvt_cmp_cb))) {
+       }
+
+       iax_peercallno_pvts = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               IAX_MAX_CALLS, pvt_hash_cb, NULL, pvt_cmp_cb);
+       if (!iax_peercallno_pvts) {
                goto container_fail;
-       } else if (!(iax_transfercallno_pvts = ao2_container_alloc(IAX_MAX_CALLS, transfercallno_pvt_hash_cb, transfercallno_pvt_cmp_cb))) {
+       }
+
+       iax_transfercallno_pvts = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               IAX_MAX_CALLS, transfercallno_pvt_hash_cb, NULL, transfercallno_pvt_cmp_cb);
+       if (!iax_transfercallno_pvts) {
                goto container_fail;
-       } else if (!(peercnts = ao2_container_alloc(MAX_PEER_BUCKETS, peercnt_hash_cb, peercnt_cmp_cb))) {
+       }
+
+       peercnts = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAX_PEER_BUCKETS,
+               peercnt_hash_cb, NULL, peercnt_cmp_cb);
+       if (!peercnts) {
                goto container_fail;
-       } else if (!(callno_limits = ao2_container_alloc(MAX_PEER_BUCKETS, addr_range_hash_cb, addr_range_cmp_cb))) {
+       }
+
+       callno_limits = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               MAX_PEER_BUCKETS, addr_range_hash_cb, NULL, addr_range_cmp_cb);
+       if (!callno_limits) {
                goto container_fail;
-       } else if (!(calltoken_ignores = ao2_container_alloc(MAX_PEER_BUCKETS, addr_range_hash_cb, addr_range_cmp_cb))) {
+       }
+
+       calltoken_ignores = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               MAX_PEER_BUCKETS, addr_range_hash_cb, NULL, addr_range_cmp_cb);
+       if (!calltoken_ignores) {
                goto container_fail;
-       } else if (create_callno_pools()) {
+       }
+
+       if (create_callno_pools()) {
                goto container_fail;
-       } else if  (!(transmit_processor = ast_taskprocessor_get("iax2_transmit", TPS_REF_DEFAULT))) {
+       }
+
+       transmit_processor = ast_taskprocessor_get("iax2_transmit", TPS_REF_DEFAULT);
+       if (!transmit_processor) {
                goto container_fail;
        }
 
index 05184ca..a9dd2af 100644 (file)
@@ -471,7 +471,9 @@ static struct jingle_endpoint_state *jingle_endpoint_state_create(void)
                return NULL;
        }
 
-       if (!(state->sessions = ao2_container_alloc(SESSION_BUCKETS, jingle_session_hash, jingle_session_cmp))) {
+       state->sessions = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               SESSION_BUCKETS, jingle_session_hash, NULL, jingle_session_cmp);
+       if (!state->sessions) {
                ao2_ref(state, -1);
                return NULL;
        }
@@ -601,7 +603,9 @@ static void *jingle_config_alloc(void)
                return NULL;
        }
 
-       if (!(cfg->endpoints = ao2_container_alloc(ENDPOINT_BUCKETS, jingle_endpoint_hash, jingle_endpoint_cmp))) {
+       cfg->endpoints = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               ENDPOINT_BUCKETS, jingle_endpoint_hash, NULL, jingle_endpoint_cmp);
+       if (!cfg->endpoints) {
                ao2_ref(cfg, -1);
                return NULL;
        }
index 9edd989..e44f328 100644 (file)
@@ -1135,7 +1135,6 @@ static int chan_pjsip_devicestate(const char *data)
        RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", data), ao2_cleanup);
        enum ast_device_state state = AST_DEVICE_UNKNOWN;
        RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, NULL, ao2_cleanup);
-       RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
        struct ast_devstate_aggregate aggregate;
        int num, inuse = 0;
 
@@ -1156,28 +1155,21 @@ static int chan_pjsip_devicestate(const char *data)
                state = AST_DEVICE_NOT_INUSE;
        }
 
-       if (!endpoint_snapshot->num_channels || !(cache = ast_channel_cache())) {
+       if (!endpoint_snapshot->num_channels) {
                return state;
        }
 
        ast_devstate_aggregate_init(&aggregate);
 
-       ao2_ref(cache, +1);
-
        for (num = 0; num < endpoint_snapshot->num_channels; num++) {
-               RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
                struct ast_channel_snapshot *snapshot;
 
-               msg = stasis_cache_get(cache, ast_channel_snapshot_type(),
-                       endpoint_snapshot->channel_ids[num]);
-
-               if (!msg) {
+               snapshot = ast_channel_snapshot_get_latest(endpoint_snapshot->channel_ids[num]);
+               if (!snapshot) {
                        continue;
                }
 
-               snapshot = stasis_message_data(msg);
-
-               if (chan_pjsip_get_hold(snapshot->uniqueid)) {
+               if (chan_pjsip_get_hold(snapshot->base->uniqueid)) {
                        ast_devstate_aggregate_add(&aggregate, AST_DEVICE_ONHOLD);
                } else {
                        ast_devstate_aggregate_add(&aggregate, ast_state_chan2dev(snapshot->state));
@@ -1187,6 +1179,8 @@ static int chan_pjsip_devicestate(const char *data)
                        (snapshot->state == AST_STATE_BUSY)) {
                        inuse++;
                }
+
+               ao2_ref(snapshot, -1);
        }
 
        if (endpoint->devicestate_busy_at && (inuse == endpoint->devicestate_busy_at)) {
index cb81901..ac68f3d 100644 (file)
@@ -1815,8 +1815,9 @@ static int initialize_escs(void)
 {
        int i, res = 0;
        for (i = 0; i < ARRAY_LEN(event_state_compositors); i++) {
-               if (!((event_state_compositors[i].compositor) =
-                                       ao2_container_alloc(ESC_MAX_BUCKETS, esc_hash_fn, esc_cmp_fn))) {
+               event_state_compositors[i].compositor = ao2_container_alloc_hash(
+                       AO2_ALLOC_OPT_LOCK_MUTEX, 0, ESC_MAX_BUCKETS, esc_hash_fn, NULL, esc_cmp_fn);
+               if (!event_state_compositors[i].compositor) {
                        res = -1;
                }
        }
@@ -35548,7 +35549,9 @@ static int load_module(void)
                unload_module();
                return AST_MODULE_LOAD_DECLINE;
        }
-       if (!(sip_monitor_instances = ao2_container_alloc(37, sip_monitor_instance_hash_fn, sip_monitor_instance_cmp_fn))) {
+       sip_monitor_instances = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 37,
+               sip_monitor_instance_hash_fn, NULL, sip_monitor_instance_cmp_fn);
+       if (!sip_monitor_instances) {
                unload_module();
                return AST_MODULE_LOAD_DECLINE;
        }
index 28d84ee..7051961 100644 (file)
@@ -813,7 +813,9 @@ static const char *ustmtext(const char *str, struct unistimsession *pte)
                char tmp[1024], *p, *p_orig = NULL, *p_trans = NULL;
                FILE *f;
 
-               if (!(lang->trans = ao2_container_alloc(8, lang_hash_fn, lang_cmp_fn))) {
+               lang->trans = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 8,
+                       lang_hash_fn, NULL, lang_cmp_fn);
+               if (!lang->trans) {
                        ast_log(LOG_ERROR, "Unable to allocate container for translation!\n");
                        return str;
                }
index 33d0e02..2ce2369 100644 (file)
@@ -61,13 +61,13 @@ static int cli_channel_sort(const void *obj, const void *arg, int flags)
 
        switch (flags & OBJ_SEARCH_MASK) {
        case OBJ_SEARCH_OBJECT:
-               right_key = right_obj->name;
+               right_key = right_obj->base->name;
                /* Fall through */
        case OBJ_SEARCH_KEY:
-               cmp = strcmp(left_obj->name, right_key);
+               cmp = strcmp(left_obj->base->name, right_key);
                break;
        case OBJ_SEARCH_PARTIAL_KEY:
-               cmp = strncmp(left_obj->name, right_key, strlen(right_key));
+               cmp = strncmp(left_obj->base->name, right_key, strlen(right_key));
                break;
        default:
                cmp = 0;
@@ -86,17 +86,17 @@ static int cli_channelstats_sort(const void *obj, const void *arg, int flags)
 
        switch (flags & OBJ_SEARCH_MASK) {
        case OBJ_SEARCH_OBJECT:
-               cmp = strcmp(left_obj->bridgeid, right_obj->bridgeid);
+               cmp = strcmp(left_obj->bridge->id, right_obj->bridge->id);
                if (cmp) {
                        return cmp;
                }
-               right_key = right_obj->name;
+               right_key = right_obj->base->name;
                /* Fall through */
        case OBJ_SEARCH_KEY:
-               cmp = strcmp(left_obj->name, right_key);
+               cmp = strcmp(left_obj->base->name, right_key);
                break;
        case OBJ_SEARCH_PARTIAL_KEY:
-               cmp = strncmp(left_obj->name, right_key, strlen(right_key));
+               cmp = strncmp(left_obj->base->name, right_key, strlen(right_key));
                break;
        default:
                cmp = 0;
@@ -115,15 +115,15 @@ static int cli_channel_compare(void *obj, void *arg, int flags)
 
        switch (flags & OBJ_SEARCH_MASK) {
        case OBJ_SEARCH_OBJECT:
-               right_key = right_obj->name;
+               right_key = right_obj->base->name;
                /* Fall through */
        case OBJ_SEARCH_KEY:
-               if (strcmp(left_obj->name, right_key) == 0) {
+               if (strcmp(left_obj->base->name, right_key) == 0) {
                        cmp = CMP_MATCH | CMP_STOP;
                }
                break;
        case OBJ_SEARCH_PARTIAL_KEY:
-               if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
+               if (strncmp(left_obj->base->name, right_key, strlen(right_key)) == 0) {
                        cmp = CMP_MATCH;
                }
                break;
@@ -144,18 +144,18 @@ static int cli_channelstats_compare(void *obj, void *arg, int flags)
 
        switch (flags & OBJ_SEARCH_MASK) {
        case OBJ_SEARCH_OBJECT:
-               if (strcmp(left_obj->bridgeid, right_obj->bridgeid) == 0
-                       && strcmp(left_obj->name, right_obj->name) == 0) {
+               if (strcmp(left_obj->bridge->id, right_obj->bridge->id) == 0
+                       && strcmp(left_obj->base->name, right_obj->base->name) == 0) {
                        return CMP_MATCH | CMP_STOP;
                }
                break;
        case OBJ_SEARCH_KEY:
-               if (strcmp(left_obj->name, right_key) == 0) {
+               if (strcmp(left_obj->base->name, right_key) == 0) {
                        cmp = CMP_MATCH | CMP_STOP;
                }
                break;
        case OBJ_SEARCH_PARTIAL_KEY:
-               if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
+               if (strncmp(left_obj->base->name, right_key, strlen(right_key)) == 0) {
                        cmp = CMP_MATCH;
                }
                break;
@@ -169,11 +169,10 @@ static int cli_channelstats_compare(void *obj, void *arg, int flags)
 
 static int cli_message_to_snapshot(void *obj, void *arg, int flags)
 {
-       struct stasis_message *message = obj;
+       struct ast_channel_snapshot *snapshot = obj;
        struct ao2_container *snapshots = arg;
-       struct ast_channel_snapshot *snapshot = stasis_message_data(message);
 
-       if (!strcmp(snapshot->type, "PJSIP")) {
+       if (!strcmp(snapshot->base->type, "PJSIP")) {
                ao2_link(snapshots, snapshot);
                return CMP_MATCH;
        }
@@ -186,8 +185,8 @@ static int cli_filter_channels(void *obj, void *arg, int flags)
        struct ast_channel_snapshot *channel = obj;
        regex_t *regexbuf = arg;
 
-       if (!regexec(regexbuf, channel->name, 0, NULL, 0)
-               || !regexec(regexbuf, channel->appl, 0, NULL, 0)) {
+       if (!regexec(regexbuf, channel->base->name, 0, NULL, 0)
+               || !regexec(regexbuf, channel->dialplan->appl, 0, NULL, 0)) {
                return 0;
        }
 
@@ -198,8 +197,7 @@ static struct ao2_container *get_container(const char *regex, ao2_sort_fn sort_f
 {
        struct ao2_container *child_container;
        regex_t regexbuf;
-       RAII_VAR(struct ao2_container *, parent_container,
-               stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type()), ao2_cleanup);
+       RAII_VAR(struct ao2_container *, parent_container, ast_channel_cache_by_name(), ao2_cleanup);
 
        if (!parent_container) {
                return NULL;
@@ -238,7 +236,7 @@ static const char *cli_channel_get_id(const void *obj)
 {
        const struct ast_channel_snapshot *snapshot = obj;
 
-       return snapshot->name;
+       return snapshot->base->name;
 }
 
 static void *cli_channel_retrieve_by_id(const char *id)
@@ -282,16 +280,16 @@ static int cli_channel_print_body(void *obj, void *arg, int flags)
 
        ast_assert(context->output_buffer != NULL);
 
-       print_name_len = strlen(snapshot->name) + strlen(snapshot->appl) + 2;
+       print_name_len = strlen(snapshot->base->name) + strlen(snapshot->dialplan->appl) + 2;
        print_name = alloca(print_name_len);
 
        /* Append the application */
-       snprintf(print_name, print_name_len, "%s/%s", snapshot->name, snapshot->appl);
+       snprintf(print_name, print_name_len, "%s/%s", snapshot->base->name, snapshot->dialplan->appl);
 
        indent = CLI_INDENT_TO_SPACES(context->indent_level);
        flexwidth = CLI_LAST_TABSTOP - indent;
 
-       ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->creationtime.tv_sec, print_time, 32);
+       ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->base->creationtime.tv_sec, print_time, 32);
 
        ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %-12.12s  %-11.11s\n",
                CLI_INDENT_TO_SPACES(context->indent_level), "Channel",
@@ -309,9 +307,9 @@ static int cli_channel_print_body(void *obj, void *arg, int flags)
                        "%*s: %-*.*s  CLCID: \"%s\" <%s>\n",
                        indent, "Exten",
                        flexwidth, flexwidth,
-                       snapshot->exten,
-                       snapshot->connected_name,
-                       snapshot->connected_number
+                       snapshot->dialplan->exten,
+                       snapshot->connected->name,
+                       snapshot->connected->number
                        );
                context->indent_level--;
                if (context->indent_level == 0) {
@@ -340,7 +338,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
 {
        struct ast_sip_cli_context *context = arg;
        const struct ast_channel_snapshot *snapshot = obj;
-       struct ast_channel *channel = ast_channel_get_by_name(snapshot->name);
+       struct ast_channel *channel = ast_channel_get_by_name(snapshot->base->name);
        struct ast_sip_channel_pvt *cpvt = channel ? ast_channel_tech_pvt(channel) : NULL;
        struct ast_sip_session *session;
        struct ast_sip_session_media *media;
@@ -353,7 +351,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
        ast_assert(context->output_buffer != NULL);
 
        if (!channel) {
-               ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name);
+               ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->base->name);
                return -1;
        }
 
@@ -361,7 +359,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
 
        session = cpvt->session;
        if (!session) {
-               ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name);
+               ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->base->name);
                ast_channel_unlock(channel);
                ao2_cleanup(channel);
                return -1;
@@ -369,7 +367,7 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
 
        media = session->active_media_state->default_session[AST_MEDIA_TYPE_AUDIO];
        if (!media || !media->rtp) {
-               ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->name);
+               ast_str_append(&context->output_buffer, 0, " %s not valid\n", snapshot->base->name);
                ast_channel_unlock(channel);
                ao2_cleanup(channel);
                return -1;
@@ -385,18 +383,18 @@ static int cli_channelstats_print_body(void *obj, void *arg, int flags)
 
        ast_channel_unlock(channel);
 
-       print_name = ast_strdupa(snapshot->name);
+       print_name = ast_strdupa(snapshot->base->name);
        /* Skip the PJSIP/.  We know what channel type it is and we need the space. */
        print_name += 6;
 
-       ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->creationtime.tv_sec, print_time, 32);
+       ast_format_duration_hh_mm_ss(ast_tvnow().tv_sec - snapshot->base->creationtime.tv_sec, print_time, 32);
 
        if (ast_rtp_instance_get_stats(rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) {
-               ast_str_append(&context->output_buffer, 0, "%s direct media\n", snapshot->name);
+               ast_str_append(&context->output_buffer, 0, "%s direct media\n", snapshot->base->name);
        } else {
                ast_str_append(&context->output_buffer, 0,
                        " %8.8s %-18.18s %-8.8s %-6.6s %6u%s %6u%s %3u %7.3f %6u%s %6u%s %3u %7.3f %7.3f\n",
-                       snapshot->bridgeid,
+                       snapshot->bridge->id,
                        print_name,
                        print_time,
                        codec_in_use,
index ec6d666..3675b0e 100644 (file)
@@ -10133,8 +10133,8 @@ int sig_pri_load(const char *cc_type_name)
 
 #if defined(HAVE_PRI_CCSS)
        sig_pri_cc_type_name = cc_type_name;
-       sig_pri_cc_monitors = ao2_container_alloc(37, sig_pri_cc_monitor_instance_hash_fn,
-               sig_pri_cc_monitor_instance_cmp_fn);
+       sig_pri_cc_monitors = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 37,
+               sig_pri_cc_monitor_instance_hash_fn, NULL, sig_pri_cc_monitor_instance_cmp_fn);
        if (!sig_pri_cc_monitors) {
                return -1;
        }
index 8729b1e..5ce3166 100644 (file)
@@ -17,6 +17,8 @@ enabled = yes       ; When set to no, ARI support is disabled.
 ; Display certain channel variables every time a channel-oriented
 ; event is emitted:
 ;
+; Note that this does incur a performance penalty and should be avoided if possible.
+;
 ;channelvars = var1,var2,var3
 
 ;[username]
index 989441a..405e0d3 100644 (file)
@@ -55,6 +55,8 @@ bindaddr = 0.0.0.0
 ; Display certain channel variables every time a channel-oriented
 ; event is emitted:
 ;
+; Note that this does incur a performance penalty and should be avoided if possible.
+;
 ;channelvars = var1,var2,var3
 
 ; debug = on   ; enable some debugging info in AMI messages (default off).
index e578000..9a98b3c 100644 (file)
@@ -221,7 +221,8 @@ static int dialgroup_write(struct ast_channel *chan, const char *cmd, char *data
                grhead = ao2_alloc(sizeof(*grhead), group_destroy);
                if (!grhead)
                        return -1;
-               grhead->entries = ao2_container_alloc(37, entry_hash_fn, entry_cmp_fn);
+               grhead->entries = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 37,
+                       entry_hash_fn, NULL, entry_cmp_fn);
                if (!grhead->entries) {
                        ao2_ref(grhead, -1);
                        return -1;
@@ -236,7 +237,9 @@ static int dialgroup_write(struct ast_channel *chan, const char *cmd, char *data
 
                /* Remove all existing */
                ao2_ref(grhead->entries, -1);
-               if (!(grhead->entries = ao2_container_alloc(37, entry_hash_fn, entry_cmp_fn))) {
+               grhead->entries = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 37,
+                       entry_hash_fn, NULL, entry_cmp_fn);
+               if (!grhead->entries) {
                        ao2_unlink(group_container, grhead);
                        ao2_ref(grhead, -1);
                        return -1;
@@ -297,7 +300,9 @@ static int load_module(void)
        struct ast_db_entry *dbtree, *tmp;
        char groupname[AST_MAX_EXTENSION], *ptr;
 
-       if ((group_container = ao2_container_alloc(37, group_hash_fn, group_cmp_fn))) {
+       group_container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 37,
+               group_hash_fn, NULL, group_cmp_fn);
+       if (group_container) {
                /* Refresh groups from astdb */
                if ((dbtree = ast_db_gettree("dialgroup", NULL))) {
                        for (tmp = dbtree; tmp; tmp = tmp->next) {
index 5cb8310..acb5fc9 100644 (file)
@@ -215,12 +215,6 @@ static void *lock_broker(void *unused)
        return NULL;
 }
 
-static int ast_channel_hash_cb(const void *obj, const int flags)
-{
-       const struct ast_channel *chan = obj;
-       return ast_str_case_hash(ast_channel_name(chan));
-}
-
 static int ast_channel_cmp_cb(void *obj, void *arg, int flags)
 {
        struct ast_channel *chan = obj, *cmp_args = arg;
@@ -296,7 +290,9 @@ static int get_lock(struct ast_channel *chan, char *lockname, int trylock)
                        AST_LIST_UNLOCK(&locklist);
                        return -1;
                }
-               if (!(current->requesters = ao2_container_alloc(1, ast_channel_hash_cb, ast_channel_cmp_cb))) {
+               current->requesters = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+                       NULL, ast_channel_cmp_cb);
+               if (!current->requesters) {
                        ast_mutex_destroy(&current->mutex);
                        ast_cond_destroy(&current->cond);
                        ast_free(current);
index 66722df..9a124c1 100644 (file)
@@ -1793,7 +1793,8 @@ static int load_module(void)
        dsns = NULL;
 
        if (single_db_connection) {
-               dsns = ao2_container_alloc(DSN_BUCKETS, dsn_hash, dsn_cmp);
+               dsns = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, DSN_BUCKETS,
+                       dsn_hash, NULL, dsn_cmp);
                if (!dsns) {
                        ast_log(LOG_ERROR, "Could not initialize DSN container\n");
                        ast_rwlock_unlock(&single_db_connection_lock);
@@ -1891,7 +1892,8 @@ static int reload(void)
        }
 
        if (single_db_connection) {
-               dsns = ao2_container_alloc(DSN_BUCKETS, dsn_hash, dsn_cmp);
+               dsns = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, DSN_BUCKETS,
+                       dsn_hash, NULL, dsn_cmp);
                if (!dsns) {
                        ast_log(LOG_ERROR, "Could not initialize DSN container\n");
                        ast_rwlock_unlock(&single_db_connection_lock);
index cb25385..7afc40e 100644 (file)
@@ -1089,10 +1089,33 @@ static int array(struct ast_channel *chan, const char *cmd, char *var,
        return 0;
 }
 
+static const char *get_key(const struct ast_str *prefix, const struct ast_var_t *var)
+{
+       const char *prefix_name = ast_str_buffer(prefix);
+       const char *var_name = ast_var_name(var);
+       int prefix_len;
+       int var_len;
+
+       if (ast_strlen_zero(var_name)) {
+               return NULL;
+       }
+
+       prefix_len = ast_str_strlen(prefix);
+       var_len = strlen(var_name);
+
+       /*
+        * Make sure we only match on non-empty, hash function created keys. If valid
+        * then return a pointer to the variable that's just after the prefix.
+        */
+       return var_len > (prefix_len + 1) && var_name[var_len - 1] == '~' &&
+               strncmp(prefix_name, var_name, prefix_len) == 0 ? var_name + prefix_len : NULL;
+}
+
 static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 {
        struct ast_var_t *newvar;
        struct ast_str *prefix = ast_str_alloca(80);
+       size_t buf_len;
 
        if (!chan) {
                ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
@@ -1103,15 +1126,19 @@ static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data,
        memset(buf, 0, len);
 
        AST_LIST_TRAVERSE(ast_channel_varshead(chan), newvar, entries) {
-               if (strncmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
-                       /* Copy everything after the prefix */
-                       strncat(buf, ast_var_name(newvar) + ast_str_strlen(prefix), len - strlen(buf) - 1);
-                       /* Trim the trailing ~ */
+               const char *key = get_key(prefix, newvar);
+
+               if (key) {
+                       strncat(buf, key, len - strlen(buf) - 1);
+                       /* Replace the trailing ~ */
                        buf[strlen(buf) - 1] = ',';
                }
        }
        /* Trim the trailing comma */
-       buf[strlen(buf) - 1] = '\0';
+       buf_len = strlen(buf);
+       if (buf_len) {
+               buf[buf_len - 1] = '\0';
+       }
        return 0;
 }
 
@@ -1119,7 +1146,6 @@ static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data,
 {
        struct ast_var_t *newvar;
        struct ast_str *prefix = ast_str_alloca(80);
-       char *tmp;
 
        if (!chan) {
                ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
@@ -1129,17 +1155,19 @@ static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data,
        ast_str_set(&prefix, -1, HASH_PREFIX, data);
 
        AST_LIST_TRAVERSE(ast_channel_varshead(chan), newvar, entries) {
-               if (strncmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
-                       /* Copy everything after the prefix */
-                       ast_str_append(buf, len, "%s", ast_var_name(newvar) + ast_str_strlen(prefix));
-                       /* Trim the trailing ~ */
+               const char *key = get_key(prefix, newvar);
+
+               if (key) {
+                       char *tmp;
+
+                       ast_str_append(buf, len, "%s", key);
+                       /* Replace the trailing ~ */
                        tmp = ast_str_buffer(*buf);
                        tmp[ast_str_strlen(*buf) - 1] = ',';
                }
        }
-       /* Trim the trailing comma */
-       tmp = ast_str_buffer(*buf);
-       tmp[ast_str_strlen(*buf) - 1] = '\0';
+
+       ast_str_truncate(*buf, -1);
        return 0;
 }
 
index 39933c7..e540e46 100644 (file)
@@ -93,7 +93,8 @@ parameters. At the moment, this is done as follows:
 
     struct ao2_container *c;
 
-    c = ao2_container_alloc(MAX_BUCKETS, my_hash_fn, my_cmp_fn);
+    c = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, MAX_BUCKETS,
+        my_hash_fn, NULL, my_cmp_fn);
     \endcode
 
 where
@@ -109,7 +110,7 @@ A container knows little or nothing about the objects it stores,
 other than the fact that they have been created by ao2_alloc().
 All knowledge of the (user-defined) internals of the objects
 is left to the (user-supplied) functions passed as arguments
-to ao2_container_alloc().
+to ao2_container_alloc_hash().
 
 If we want to insert an object in a container, we should
 initialize its fields -- especially, those used by my_hash_fn() --
@@ -936,20 +937,8 @@ and perform various operations on them.
 Internally, objects are stored in lists, hash tables or other
 data structures depending on the needs.
 
-\note NOTA BENE: at the moment the only container we support is the
-    hash table and its degenerate form, the list.
-
 Operations on container include:
 
-  -  c = \b ao2_container_alloc(size, hash_fn, cmp_fn)
-    allocate a container with desired size and default compare
-    and hash function
-         -The compare function returns an int, which
-         can be 0 for not found, CMP_STOP to stop end a traversal,
-         or CMP_MATCH if they are equal
-         -The hash function returns an int. The hash function
-         takes two argument, the object pointer and a flags field,
-
   -  \b ao2_find(c, arg, flags)
     returns zero or more elements matching a given criteria
     (specified as arg). 'c' is the container pointer. Flags
@@ -1298,26 +1287,6 @@ typedef int (ao2_sort_fn)(const void *obj_left, const void *obj_right, int flags
 struct ao2_container;
 
 /*!
- * \deprecated
- * \brief Allocate and initialize a hash container with the desired number of buckets.
- *
- * \details
- * We allocate space for a struct astobj_container, struct container
- * and the buckets[] array.
- *
- * \param n_buckets Number of buckets for hash
- * \param hash_fn Pointer to a function computing a hash value. (NULL if everyting goes in first bucket.)
- * \param cmp_fn Pointer to a compare function used by ao2_find. (NULL to match everything)
- *
- * \return A pointer to a struct container.
- *
- * \note Destructor is set implicitly.
- * \note This is legacy container creation that is mapped to the new method.
- */
-#define ao2_container_alloc(n_buckets, hash_fn, cmp_fn) \
-       ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, (n_buckets), (hash_fn), NULL, (cmp_fn))
-
-/*!
  * \brief Allocate and initialize a hash container with the desired number of buckets.
  *
  * \details
@@ -1420,6 +1389,28 @@ int ao2_container_count(struct ao2_container *c);
 int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags);
 
 /*!
+ * \brief Copy object references associated with src container weakproxies into the dest container.
+ *
+ * \param dest Container to copy src strong object references into.
+ * \param src Container to copy all weak object references from.
+ * \param flags OBJ_NOLOCK if a lock is already held on both containers.
+ *    Otherwise, the src container is locked first.
+ *
+ * \pre The dest container must be empty.  If the duplication fails, the
+ * dest container will be returned empty.
+ *
+ * \note This can potentially be expensive because a malloc is
+ * needed for every object in the src container.
+ *
+ * \note Every object inside the container is locked by \ref ao2_weakproxy_get_object.
+ *       Any weakproxy in \ref src with no associated object is ignored.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int ao2_container_dup_weakproxy_objs(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags);
+
+/*!
  * \brief Create a clone/copy of the given container.
  * \since 11.0
  *
index 3f22cdd..58a4879 100644 (file)
@@ -148,6 +148,15 @@ extern "C" {
 #define AST_MAX_PUBLIC_UNIQUEID 149
 
 /*!
+ * The number of buckets to store channels or channel information
+ */
+#ifdef LOW_MEMORY
+#define AST_NUM_CHANNEL_BUCKETS 61
+#else
+#define AST_NUM_CHANNEL_BUCKETS 1567
+#endif
+
+/*!
  * Maximum size of an internal Asterisk channel unique ID.
  *
  * \details
@@ -2650,6 +2659,17 @@ void ast_channel_internal_swap_uniqueid_and_linkedid(struct ast_channel *a, stru
 void ast_channel_internal_swap_topics(struct ast_channel *a, struct ast_channel *b);
 
 /*!
+ * \brief Swap snapshots beteween two channels
+ * \param a First channel
+ * \param b Second channel
+ * \return void
+ *
+ * \note
+ * This is used in masquerade to exchange snapshots
+ */
+void ast_channel_internal_swap_snapshots(struct ast_channel *a, struct ast_channel *b);
+
+/*!
  * \brief Set uniqueid and linkedid string value only (not time)
  * \param chan The channel to set the uniqueid to
  * \param uniqueid The uniqueid to set
@@ -4236,6 +4256,9 @@ enum ast_channel_adsicpe ast_channel_adsicpe(const struct ast_channel *chan);
 void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value);
 enum ast_channel_state ast_channel_state(const struct ast_channel *chan);
 ast_callid ast_channel_callid(const struct ast_channel *chan);
+struct ast_channel_snapshot *ast_channel_snapshot(const struct ast_channel *chan);
+void ast_channel_snapshot_set(struct ast_channel *chan, struct ast_channel_snapshot *snapshot);
+struct ast_flags *ast_channel_snapshot_segment_flags(struct ast_channel *chan);
 
 /*!
  * \pre chan is locked
@@ -4562,21 +4585,6 @@ struct varshead *ast_channel_get_vars(struct ast_channel *chan);
 struct stasis_topic *ast_channel_topic(struct ast_channel *chan);
 
 /*!
- * \since 12
- * \brief A topic which publishes the events for a particular channel.
- *
- * \ref ast_channel_snapshot messages are replaced with \ref stasis_cache_update
- *
- * If the given \a chan is \c NULL, ast_channel_topic_all_cached() is returned.
- *
- * \param chan Channel, or \c NULL.
- *
- * \retval Topic for channel's events.
- * \retval ast_channel_topic_all() if \a chan is \c NULL.
- */
-struct stasis_topic *ast_channel_topic_cached(struct ast_channel *chan);
-
-/*!
  * \brief Get the bridge associated with a channel
  * \since 12.0.0
  *
index 4843617..c90470a 100644 (file)
  */
 
 /*!
+ * \since 17
+ * \brief Channel snapshot invalidation flags, used to force generation of segments
+ */
+enum ast_channel_snapshot_segment_invalidation {
+       /*! Invalidate the bridge segment */
+       AST_CHANNEL_SNAPSHOT_INVALIDATE_BRIDGE = (1 << 1),
+       /*! Invalidate the dialplan segment */
+       AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN = (1 << 2),
+       /*! Invalidate the connected segment */
+       AST_CHANNEL_SNAPSHOT_INVALIDATE_CONNECTED = (1 << 3),
+       /*! Invalidate the caller segment */
+       AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER = (1 << 4),
+       /*! Invalidate the hangup segment */
+       AST_CHANNEL_SNAPSHOT_INVALIDATE_HANGUP = (1 << 5),
+       /*! Invalidate the peer segment */
+       AST_CHANNEL_SNAPSHOT_INVALIDATE_PEER = (1 << 6),
+       /*! Invalidate the base segment */
+       AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE = (1 << 7),
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing bridge information for a channel snapshot.
+ */
+struct ast_channel_snapshot_bridge {
+       char id[0]; /*!< Unique Bridge Identifier */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing dialplan information for a channel snapshot.
+ */
+struct ast_channel_snapshot_dialplan {
+       AST_DECLARE_STRING_FIELDS(
+               AST_STRING_FIELD(appl);             /*!< Current application */
+               AST_STRING_FIELD(data);             /*!< Data passed to current application */
+               AST_STRING_FIELD(context);          /*!< Current extension context */
+               AST_STRING_FIELD(exten);            /*!< Current extension number */
+       );
+       int priority; /*!< Current extension priority */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing caller information for a channel snapshot.
+ */
+struct ast_channel_snapshot_caller {
+       AST_DECLARE_STRING_FIELDS(
+               AST_STRING_FIELD(name);           /*!< Caller ID Name */
+               AST_STRING_FIELD(number);         /*!< Caller ID Number */
+               AST_STRING_FIELD(dnid);           /*!< Dialed ID Number */
+               AST_STRING_FIELD(dialed_subaddr); /*!< Dialed subaddress */
+               AST_STRING_FIELD(ani);            /*!< Caller ID ANI Number */
+               AST_STRING_FIELD(rdnis);          /*!< Caller ID RDNIS Number */
+               AST_STRING_FIELD(subaddr);        /*!< Caller subaddress */
+       );
+       int pres; /*!< Caller ID presentation. */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing connected information for a channel snapshot.
+ */
+struct ast_channel_snapshot_connected {
+       char *number; /*!< Connected Line Number */
+       char name[0]; /*!< Connected Line Name */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing base information for a channel snapshot.
+ */
+struct ast_channel_snapshot_base {
+       AST_DECLARE_STRING_FIELDS(
+               AST_STRING_FIELD(name);        /*!< ASCII unique channel name */
+               AST_STRING_FIELD(uniqueid);    /*!< Unique Channel Identifier */
+               AST_STRING_FIELD(accountcode); /*!< Account code for billing */
+               AST_STRING_FIELD(userfield);   /*!< Userfield for CEL billing */
+               AST_STRING_FIELD(language);    /*!< The default spoken language for the channel */
+               AST_STRING_FIELD(type);        /*!< Type of channel technology */
+       );
+       struct timeval creationtime; /*!< The time of channel creation */
+       int tech_properties;         /*!< Properties of the channel's technology */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing peer information for a channel snapshot.
+ */
+struct ast_channel_snapshot_peer {
+       char *linkedid;   /*!< Linked Channel Identifier -- gets propagated by linkage */
+       char account[0]; /*!< Peer account code for billing */
+};
+
+/*!
+ * \since 17
+ * \brief Structure containing hangup information for a channel snapshot.
+ */
+struct ast_channel_snapshot_hangup {
+       int cause;      /*!< Why is the channel hanged up. See causes.h */
+       char source[0]; /*!< Who is responsible for hanging up this channel */
+};
+
+/*!
  * \since 12
  * \brief Structure representing a snapshot of channel state.
  *
  * While not enforced programmatically, this object is shared across multiple
  * threads, and should be treated as an immutable object.
+ *
+ * It is guaranteed that the segments of this snapshot will always exist
+ * when accessing the snapshot.
  */
 struct ast_channel_snapshot {
-       AST_DECLARE_STRING_FIELDS(
-               AST_STRING_FIELD(name);             /*!< ASCII unique channel name */
-               AST_STRING_FIELD(uniqueid);         /*!< Unique Channel Identifier */
-               AST_STRING_FIELD(linkedid);         /*!< Linked Channel Identifier -- gets propagated by linkage */
-               AST_STRING_FIELD(appl);             /*!< Current application */
-               AST_STRING_FIELD(data);             /*!< Data passed to current application */
-               AST_STRING_FIELD(context);          /*!< Dialplan: Current extension context */
-               AST_STRING_FIELD(exten);            /*!< Dialplan: Current extension number */
-               AST_STRING_FIELD(accountcode);      /*!< Account code for billing */
-               AST_STRING_FIELD(peeraccount);      /*!< Peer account code for billing */
-               AST_STRING_FIELD(userfield);        /*!< Userfield for CEL billing */
-               AST_STRING_FIELD(hangupsource);     /*!< Who is responsible for hanging up this channel */
-               AST_STRING_FIELD(caller_name);      /*!< Caller ID Name */
-               AST_STRING_FIELD(caller_number);    /*!< Caller ID Number */
-               AST_STRING_FIELD(caller_dnid);      /*!< Dialed ID Number */
-               AST_STRING_FIELD(caller_ani);       /*!< Caller ID ANI Number */
-               AST_STRING_FIELD(caller_rdnis);     /*!< Caller ID RDNIS Number */
-               AST_STRING_FIELD(caller_subaddr);   /*!< Caller subaddress */
-               AST_STRING_FIELD(dialed_subaddr);   /*!< Dialed subaddress */
-               AST_STRING_FIELD(connected_name);   /*!< Connected Line Name */
-               AST_STRING_FIELD(connected_number); /*!< Connected Line Number */
-               AST_STRING_FIELD(language);         /*!< The default spoken language for the channel */
-               AST_STRING_FIELD(bridgeid);         /*!< Unique Bridge Identifier */
-               AST_STRING_FIELD(type);             /*!< Type of channel technology */
-       );
+       struct ast_channel_snapshot_base *base;           /*!< Base information about the channel */
+       struct ast_channel_snapshot_peer *peer;           /*!< Peer information */
+       struct ast_channel_snapshot_caller *caller;       /*!< Information about the caller */
+       struct ast_channel_snapshot_connected *connected; /*!< Information about who this channel is connected to */
+       struct ast_channel_snapshot_bridge *bridge;       /*!< Information about the bridge */
+       struct ast_channel_snapshot_dialplan *dialplan;   /*!< Information about the dialplan */
+       struct ast_channel_snapshot_hangup *hangup;       /*!< Hangup information */
+       enum ast_channel_state state;                     /*!< State of line */
+       int amaflags;                                     /*!< AMA flags for billing */
+       struct ast_flags flags;                           /*!< channel flags of AST_FLAG_ type */
+       struct ast_flags softhangup_flags;                /*!< softhangup channel flags */
+       struct varshead *manager_vars;                    /*!< Variables to be appended to manager events */
+       struct varshead *ari_vars;                        /*!< Variables to be appended to ARI events */
+};
 
-       struct timeval creationtime;            /*!< The time of channel creation */
-       enum ast_channel_state state;           /*!< State of line */
-       int priority;                           /*!< Dialplan: Current extension priority */
-       int amaflags;                           /*!< AMA flags for billing */
-       int hangupcause;                        /*!< Why is the channel hanged up. See causes.h */
-       int caller_pres;                        /*!< Caller ID presentation. */
-       struct ast_flags flags;                 /*!< channel flags of AST_FLAG_ type */
-       struct ast_flags softhangup_flags;      /*!< softhangup channel flags */
-       struct varshead *manager_vars;          /*!< Variables to be appended to manager events */
-       int tech_properties;                    /*!< Properties of the channel's technology */
-       struct varshead *ari_vars;              /*!< Variables to be appended to ARI events */
+/*!
+ * \since 17
+ * \brief Structure representing a change of snapshot of channel state.
+ *
+ * While not enforced programmatically, this object is shared across multiple
+ * threads, and should be treated as an immutable object.
+ *
+ * \note This structure will not have a transition of an old snapshot with no
+ * new snapshot to indicate that a channel has gone away. A new snapshot will
+ * always exist and a channel going away can be determined by checking for the
+ * AST_FLAG_DEAD flag on the new snapshot.
+ */
+struct ast_channel_snapshot_update {
+       struct ast_channel_snapshot *old_snapshot; /*!< The old channel snapshot */
+       struct ast_channel_snapshot *new_snapshot; /*!< The new channel snapshot */
 };
 
 /*!
@@ -94,7 +194,7 @@ struct ast_channel_blob {
  */
 struct ast_multi_channel_blob;
 
-struct stasis_cp_all *ast_channel_cache_all(void);
+struct ao2_container *ast_channel_cache_all(void);
 
 /*!
  * \since 12
@@ -105,34 +205,17 @@ struct stasis_topic *ast_channel_topic_all(void);
 
 /*!
  * \since 12
- * \brief A caching topic which caches \ref ast_channel_snapshot messages from
- * ast_channel_events_all(void).
- *
- * \retval Topic for all channel events.
- */
-struct stasis_topic *ast_channel_topic_all_cached(void);
-
-/*!
- * \since 12
- * \brief Primary channel cache, indexed by Uniqueid.
- *
- * \retval Cache of \ref ast_channel_snapshot.
- */
-struct stasis_cache *ast_channel_cache(void);
-
-/*!
- * \since 12
  * \brief Secondary channel cache, indexed by name.
  *
  * \retval Cache of \ref ast_channel_snapshot.
  */
-struct stasis_cache *ast_channel_cache_by_name(void);
+struct ao2_container *ast_channel_cache_by_name(void);
 
 /*!
  * \since 12
- * \brief Message type for \ref ast_channel_snapshot.
+ * \brief Message type for \ref ast_channel_snapshot_update.
  *
- * \retval Message type for \ref ast_channel_snapshot.
+ * \retval Message type for \ref ast_channel_snapshot_update.
  */
 struct stasis_message_type *ast_channel_snapshot_type(void);
 
@@ -176,6 +259,18 @@ struct ast_channel_snapshot *ast_channel_snapshot_get_latest(const char *uniquei
 struct ast_channel_snapshot *ast_channel_snapshot_get_latest_by_name(const char *name);
 
 /*!
+ * \since 17
+ * \brief Send the final channel snapshot for a channel, thus removing it from cache
+ *
+ * \pre chan is locked
+ *
+ * \param chan The channel to send the final channel snapshot for
+ *
+ * \note This will also remove the cached snapshot from the channel itself
+ */
+void ast_channel_publish_final_snapshot(struct ast_channel *chan);
+
+/*!
  * \since 12
  * \brief Creates a \ref ast_channel_blob message.
  *
@@ -303,6 +398,8 @@ void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj,
  * \param type Type of stasis message.
  * \param blob The blob being published. (NULL if no blob)
  *
+ * \note This will use the current snapshot on the channel and will not generate a new one.
+ *
  * \return Nothing
  */
 void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_type *type,
@@ -346,6 +443,18 @@ void ast_channel_stage_snapshot(struct ast_channel *chan);
 void ast_channel_stage_snapshot_done(struct ast_channel *chan);
 
 /*!
+ * \since 17
+ * \brief Invalidate a channel snapshot segment from being reused
+ *
+ * \pre chan is locked
+ *
+ * \param chan Channel to invalidate the segment on.
+ * \param segment The segment to invalidate.
+ */
+void ast_channel_snapshot_invalidate_segment(struct ast_channel *chan,
+       enum ast_channel_snapshot_segment_invalidation segment);
+
+/*!
  * \since 12
  * \brief Publish a \ref ast_channel_snapshot for a channel.
  *
@@ -557,17 +666,6 @@ void ast_channel_publish_dial_forward(struct ast_channel *caller,
                const char *dialstatus,
                const char *forward);
 
-/*!
- * \since 12
- * \brief Publish in the \ref ast_channel_topic a \ref ast_channel_snapshot
- * message indicating a change in channel state
- *
- * \pre chan is locked
- *
- * \param chan The channel whose state has changed
- */
-void ast_publish_channel_state(struct ast_channel *chan);
-
 /*! @} */
 
 /*!
index 253c745..b8cf301 100644 (file)
@@ -1849,7 +1849,9 @@ static void aoc_publish_blob(struct ast_channel *chan, struct stasis_message_typ
        }
 
        if (chan) {
-               aoc_event->snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
+               ast_channel_lock(chan);
+               aoc_event->snapshot = ao2_bump(ast_channel_snapshot(chan));
+               ast_channel_unlock(chan);
                if (!aoc_event->snapshot) {
                        ao2_ref(aoc_event, -1);
                        return;
index 953b77d..ec74490 100644 (file)
@@ -3244,15 +3244,7 @@ static struct stasis_message *mwi_state_create_message(
        mwi_state->old_msgs = old_msgs;
 
        if (!ast_strlen_zero(channel_id)) {
-               struct stasis_message *chan_message;
-
-               chan_message = stasis_cache_get(ast_channel_cache(), ast_channel_snapshot_type(),
-                       channel_id);
-               if (chan_message) {
-                       mwi_state->snapshot = stasis_message_data(chan_message);
-                       ao2_ref(mwi_state->snapshot, +1);
-               }
-               ao2_cleanup(chan_message);
+               mwi_state->snapshot = ast_channel_snapshot_get_latest(channel_id);
        }
 
        if (eid) {
index 5197867..9a837bd 100644 (file)
@@ -697,6 +697,59 @@ int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enu
        return res;
 }
 
+/*!
+ * \brief Copy obj associated with a weakproxy into the arg container.
+ *
+ * \param proxy pointer to the weakproxy.
+ * \param arg callback argument from ao2_callback()
+ * \param flags flags from ao2_callback()
+ *
+ * \retval 0 on success.
+ * \retval CMP_STOP|CMP_MATCH on error.
+ */
+static int dup_weakproxy_cb(void *proxy, void *arg, int flags)
+{
+       void *obj = ao2_weakproxy_get_object(proxy, 0);
+       struct ao2_container *dest = arg;
+       int ret;
+
+       if (!obj) {
+               return 0;
+       }
+
+       ret = ao2_t_link_flags(dest, obj, OBJ_NOLOCK, NULL) ? 0 : (CMP_MATCH | CMP_STOP);
+       ao2_ref(obj, -1);
+
+       return ret;
+}
+
+int ao2_container_dup_weakproxy_objs(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
+{
+       void *obj;
+       int res = 0;
+
+       if (!(flags & OBJ_NOLOCK)) {
+               ao2_rdlock(src);
+               ao2_wrlock(dest);
+       }
+       obj = ao2_callback(src, OBJ_NOLOCK, dup_weakproxy_cb, dest);
+       if (obj) {
+               /* Failed to put this obj into the dest container. */
+               ao2_t_ref(obj, -1, "Failed to put this object into the dest container.");
+
+               /* Remove all items from the dest container. */
+               ao2_t_callback(dest, OBJ_NOLOCK | OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL,
+                       NULL, NULL);
+               res = -1;
+       }
+       if (!(flags & OBJ_NOLOCK)) {
+               ao2_unlock(dest);
+               ao2_unlock(src);
+       }
+
+       return res;
+}
+
 struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum search_flags flags, const char *tag, const char *file, int line, const char *func)
 {
        struct ao2_container *clone;
index d6e7a51..a65927d 100644 (file)
@@ -5150,16 +5150,15 @@ static int bridge_show_specific_print_channel(void *obj, void *arg, int flags)
 {
        const char *uniqueid = obj;
        struct ast_cli_args *a = arg;
-       RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
        struct ast_channel_snapshot *snapshot;
 
-       msg = stasis_cache_get(ast_channel_cache(), ast_channel_snapshot_type(), uniqueid);
-       if (!msg) {
+       snapshot = ast_channel_snapshot_get_latest(uniqueid);
+       if (!snapshot) {
                return 0;
        }
-       snapshot = stasis_message_data(msg);
 
-       ast_cli(a->fd, "Channel: %s\n", snapshot->name);
+       ast_cli(a->fd, "Channel: %s\n", snapshot->base->name);
+       ao2_ref(snapshot, -1);
 
        return 0;
 }
index 1c47e24..2e3b205 100644 (file)
        </configInfo>
  ***/
 
-
-/* The prime here should be similar in size to the channel container. */
-#ifdef LOW_MEMORY
-#define NUM_CDR_BUCKETS 61
-#else
-#define NUM_CDR_BUCKETS 769
-#endif
-
 #define DEFAULT_ENABLED "1"
 #define DEFAULT_BATCHMODE "0"
 #define DEFAULT_UNANSWERED "0"
@@ -811,7 +803,7 @@ static void cdr_object_snapshot_copy(struct cdr_object_snapshot *dst, struct cdr
 static void cdr_object_transition_state(struct cdr_object *cdr, struct cdr_object_fn_table *fn_table)
 {
        CDR_DEBUG("%p - Transitioning CDR for %s from state %s to %s\n",
-               cdr, cdr->party_a.snapshot->name,
+               cdr, cdr->party_a.snapshot->base->name,
                cdr->fn_table ? cdr->fn_table->name : "NONE", fn_table->name);
        cdr->fn_table = fn_table;
        if (cdr->fn_table->init_function) {
@@ -946,9 +938,9 @@ static void cdr_all_relink(struct cdr_object *cdr)
 {
        ao2_lock(active_cdrs_all);
        if (cdr->party_b.snapshot) {
-               if (strcasecmp(cdr->party_b_name, cdr->party_b.snapshot->name)) {
+               if (strcasecmp(cdr->party_b_name, cdr->party_b.snapshot->base->name)) {
                        ao2_unlink_flags(active_cdrs_all, cdr, OBJ_NOLOCK);
-                       ast_string_field_set(cdr, party_b_name, cdr->party_b.snapshot->name);
+                       ast_string_field_set(cdr, party_b_name, cdr->party_b.snapshot->base->name);
                        ao2_link_flags(active_cdrs_all, cdr, OBJ_NOLOCK);
                }
        } else {
@@ -1047,16 +1039,16 @@ static struct cdr_object *cdr_object_alloc(struct ast_channel_snapshot *chan)
                ao2_cleanup(cdr);
                return NULL;
        }
-       ast_string_field_set(cdr, uniqueid, chan->uniqueid);
-       ast_string_field_set(cdr, name, chan->name);
-       ast_string_field_set(cdr, linkedid, chan->linkedid);
+       ast_string_field_set(cdr, uniqueid, chan->base->uniqueid);
+       ast_string_field_set(cdr, name, chan->base->name);
+       ast_string_field_set(cdr, linkedid, chan->peer->linkedid);
        cdr->disposition = AST_CDR_NULL;
        cdr->sequence = ast_atomic_fetchadd_int(&global_cdr_sequence, +1);
 
        cdr->party_a.snapshot = chan;
        ao2_t_ref(cdr->party_a.snapshot, +1, "bump snapshot during CDR creation");
 
-       CDR_DEBUG("%p - Created CDR for channel %s\n", cdr, chan->name);
+       CDR_DEBUG("%p - Created CDR for channel %s\n", cdr, chan->base->name);
 
        cdr_object_transition_state(cdr, &single_state_fn_table);
 
@@ -1153,11 +1145,11 @@ static int snapshot_cep_changed(struct ast_channel_snapshot *old_snapshot,
         * will attempt to clear the application and restore the dummy originate application
         * of "AppDialX". Ignore application changes to AppDialX as a result.
         */
-       if (strcmp(new_snapshot->appl, old_snapshot->appl)
-               && strncasecmp(new_snapshot->appl, "appdial", 7)
-               && (strcmp(new_snapshot->context, old_snapshot->context)
-                       || strcmp(new_snapshot->exten, old_snapshot->exten)
-                       || new_snapshot->priority != old_snapshot->priority)) {
+       if (strcmp(new_snapshot->dialplan->appl, old_snapshot->dialplan->appl)
+               && strncasecmp(new_snapshot->dialplan->appl, "appdial", 7)
+               && (strcmp(new_snapshot->dialplan->context, old_snapshot->dialplan->context)
+                       || strcmp(new_snapshot->dialplan->exten, old_snapshot->dialplan->exten)
+                       || new_snapshot->dialplan->priority != old_snapshot->dialplan->priority)) {
                return 1;
        }
 
@@ -1204,11 +1196,11 @@ static struct cdr_object_snapshot *cdr_object_pick_party_a(struct cdr_object_sna
 
        /* Neither party is dialed and neither has the Party A flag - defer to
         * creation time */
-       if (left->snapshot->creationtime.tv_sec < right->snapshot->creationtime.tv_sec) {
+       if (left->snapshot->base->creationtime.tv_sec < right->snapshot->base->creationtime.tv_sec) {
                return left;
-       } else if (left->snapshot->creationtime.tv_sec > right->snapshot->creationtime.tv_sec) {
+       } else if (left->snapshot->base->creationtime.tv_sec > right->snapshot->base->creationtime.tv_sec) {
                return right;
-       } else if (left->snapshot->creationtime.tv_usec > right->snapshot->creationtime.tv_usec) {
+       } else if (left->snapshot->base->creationtime.tv_usec > right->snapshot->base->creationtime.tv_usec) {
                return right;
        } else {
                /* Okay, fine, take the left one */
@@ -1293,7 +1285,7 @@ static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr)
                /* Don't create records for CDRs where the party A was a dialed channel */
                if (snapshot_is_dialed(it_cdr->party_a.snapshot) && !it_cdr->party_b.snapshot) {
                        ast_debug(1, "CDR for %s is dialed and has no Party B; discarding\n",
-                               it_cdr->party_a.snapshot->name);
+                               it_cdr->party_a.snapshot->base->name);
                        continue;
                }
 
@@ -1308,12 +1300,12 @@ static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr)
 
                /* Party A */
                ast_assert(party_a != NULL);
-               ast_copy_string(cdr_copy->accountcode, party_a->accountcode, sizeof(cdr_copy->accountcode));
+               ast_copy_string(cdr_copy->accountcode, party_a->base->accountcode, sizeof(cdr_copy->accountcode));
                cdr_copy->amaflags = party_a->amaflags;
-               ast_copy_string(cdr_copy->channel, party_a->name, sizeof(cdr_copy->channel));
-               ast_callerid_merge(cdr_copy->clid, sizeof(cdr_copy->clid), party_a->caller_name, party_a->caller_number, "");
-               ast_copy_string(cdr_copy->src, party_a->caller_number, sizeof(cdr_copy->src));
-               ast_copy_string(cdr_copy->uniqueid, party_a->uniqueid, sizeof(cdr_copy->uniqueid));
+               ast_copy_string(cdr_copy->channel, party_a->base->name, sizeof(cdr_copy->channel));
+               ast_callerid_merge(cdr_copy->clid, sizeof(cdr_copy->clid), party_a->caller->name, party_a->caller->number, "");
+               ast_copy_string(cdr_copy->src, party_a->caller->number, sizeof(cdr_copy->src));
+               ast_copy_string(cdr_copy->uniqueid, party_a->base->uniqueid, sizeof(cdr_copy->uniqueid));
                ast_copy_string(cdr_copy->lastapp, it_cdr->appl, sizeof(cdr_copy->lastapp));
                ast_copy_string(cdr_copy->lastdata, it_cdr->data, sizeof(cdr_copy->lastdata));
                ast_copy_string(cdr_copy->dst, it_cdr->exten, sizeof(cdr_copy->dst));
@@ -1321,8 +1313,8 @@ static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr)
 
                /* Party B */
                if (party_b) {
-                       ast_copy_string(cdr_copy->dstchannel, party_b->name, sizeof(cdr_copy->dstchannel));
-                       ast_copy_string(cdr_copy->peeraccount, party_b->accountcode, sizeof(cdr_copy->peeraccount));
+                       ast_copy_string(cdr_copy->dstchannel, party_b->base->name, sizeof(cdr_copy->dstchannel));
+                       ast_copy_string(cdr_copy->peeraccount, party_b->base->accountcode, sizeof(cdr_copy->peeraccount));
                        if (!ast_strlen_zero(it_cdr->party_b.userfield)) {
                                snprintf(cdr_copy->userfield, sizeof(cdr_copy->userfield), "%s;%s", it_cdr->party_a.userfield, it_cdr->party_b.userfield);
                        }
@@ -1383,8 +1375,8 @@ static void cdr_object_dispatch(struct cdr_object *cdr)
        struct ast_cdr *pub_cdr;
 
        CDR_DEBUG("%p - Dispatching CDR for Party A %s, Party B %s\n", cdr,
-               cdr->party_a.snapshot->name,
-               cdr->party_b.snapshot ? cdr->party_b.snapshot->name : "<none>");
+               cdr->party_a.snapshot->base->name,
+               cdr->party_b.snapshot ? cdr->party_b.snapshot->base->name : "<none>");
        pub_cdr = cdr_object_create_public_records(cdr);
        cdr_detach(pub_cdr);
 }
@@ -1442,10 +1434,10 @@ static void cdr_object_finalize(struct cdr_object *cdr)
        if (cdr->disposition == AST_CDR_NULL) {
                if (!ast_tvzero(cdr->answer)) {
                        cdr->disposition = AST_CDR_ANSWERED;
-               } else if (cdr->party_a.snapshot->hangupcause) {
-                       cdr_object_set_disposition(cdr, cdr->party_a.snapshot->hangupcause);
-               } else if (cdr->party_b.snapshot && cdr->party_b.snapshot->hangupcause) {
-                       cdr_object_set_disposition(cdr, cdr->party_b.snapshot->hangupcause);
+               } else if (cdr->party_a.snapshot->hangup->cause) {
+                       cdr_object_set_disposition(cdr, cdr->party_a.snapshot->hangup->cause);
+               } else if (cdr->party_b.snapshot && cdr->party_b.snapshot->hangup->cause) {
+                       cdr_object_set_disposition(cdr, cdr->party_b.snapshot->hangup->cause);
                } else {
                        cdr->disposition = AST_CDR_FAILED;
                }
@@ -1453,7 +1445,7 @@ static void cdr_object_finalize(struct cdr_object *cdr)
 
        /* tv_usec is suseconds_t, which could be int or long */
        ast_debug(1, "Finalized CDR for %s - start %ld.%06ld answer %ld.%06ld end %ld.%06ld dispo %s\n",
-                       cdr->party_a.snapshot->name,
+                       cdr->party_a.snapshot->base->name,
                        (long)cdr->start.tv_sec,
                        (long)cdr->start.tv_usec,
                        (long)cdr->answer.tv_sec,
@@ -1499,19 +1491,19 @@ static void cdr_object_check_party_a_answer(struct cdr_object *cdr)
 static void cdr_object_update_cid(struct cdr_object_snapshot *old_snapshot, struct ast_channel_snapshot *new_snapshot)
 {
        if (!old_snapshot->snapshot) {
-               set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller_dnid);
-               set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller_subaddr);
-               set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->dialed_subaddr);
+               set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller->dnid);
+               set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller->subaddr);
+               set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->caller->dialed_subaddr);
                return;
        }
-       if (strcmp(old_snapshot->snapshot->caller_dnid, new_snapshot->caller_dnid)) {
-               set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller_dnid);
+       if (strcmp(old_snapshot->snapshot->caller->dnid, new_snapshot->caller->dnid)) {
+               set_variable(&old_snapshot->variables, "dnid", new_snapshot->caller->dnid);
        }
-       if (strcmp(old_snapshot->snapshot->caller_subaddr, new_snapshot->caller_subaddr)) {
-               set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller_subaddr);
+       if (strcmp(old_snapshot->snapshot->caller->subaddr, new_snapshot->caller->subaddr)) {
+               set_variable(&old_snapshot->variables, "callingsubaddr", new_snapshot->caller->subaddr);
        }
-       if (strcmp(old_snapshot->snapshot->dialed_subaddr, new_snapshot->dialed_subaddr)) {
-               set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->dialed_subaddr);
+       if (strcmp(old_snapshot->snapshot->caller->dialed_subaddr, new_snapshot->caller->dialed_subaddr)) {
+               set_variable(&old_snapshot->variables, "calledsubaddr", new_snapshot->caller->dialed_subaddr);
        }
 }
 
@@ -1532,7 +1524,7 @@ static void cdr_object_swap_snapshot(struct cdr_object_snapshot *old_snapshot,
 
 static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
 {
-       ast_assert(strcasecmp(snapshot->name, cdr->party_a.snapshot->name) == 0);
+       ast_assert(strcasecmp(snapshot->base->name, cdr->party_a.snapshot->base->name) == 0);
 
        /* Finalize the CDR if we're in hangup logic and we're set to do so */
        if (ast_test_flag(&snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)
@@ -1547,11 +1539,11 @@ static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snaps
         */
        if (!ast_test_flag(&snapshot->flags, AST_FLAG_SUBROUTINE_EXEC)
                || ast_test_flag(&snapshot->softhangup_flags, AST_SOFTHANGUP_HANGUP_EXEC)) {
-               if (strcmp(cdr->context, snapshot->context)) {
-                       ast_string_field_set(cdr, context, snapshot->context);
+               if (strcmp(cdr->context, snapshot->dialplan->context)) {
+                       ast_string_field_set(cdr, context, snapshot->dialplan->context);
                }
-               if (strcmp(cdr->exten, snapshot->exten)) {
-                       ast_string_field_set(cdr, exten, snapshot->exten);
+               if (strcmp(cdr->exten, snapshot->dialplan->exten)) {
+                       ast_string_field_set(cdr, exten, snapshot->dialplan->exten);
                }
        }
 
@@ -1563,13 +1555,13 @@ static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snaps
         * here.
         */
        if (!ast_test_flag(&cdr->flags, AST_CDR_LOCK_APP)
-               && !ast_strlen_zero(snapshot->appl)
-               && (strncasecmp(snapshot->appl, "appdial", 7) || ast_strlen_zero(cdr->appl))) {
-               if (strcmp(cdr->appl, snapshot->appl)) {
-                       ast_string_field_set(cdr, appl, snapshot->appl);
+               && !ast_strlen_zero(snapshot->dialplan->appl)
+               && (strncasecmp(snapshot->dialplan->appl, "appdial", 7) || ast_strlen_zero(cdr->appl))) {
+               if (strcmp(cdr->appl, snapshot->dialplan->appl)) {
+                       ast_string_field_set(cdr, appl, snapshot->dialplan->appl);
                }
-               if (strcmp(cdr->data, snapshot->data)) {
-                       ast_string_field_set(cdr, data, snapshot->data);
+               if (strcmp(cdr->data, snapshot->dialplan->data)) {
+                       ast_string_field_set(cdr, data, snapshot->dialplan->data);
                }
 
                /* Dial (app_dial) is a special case. Because pre-dial handlers, which
@@ -1577,13 +1569,13 @@ static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snaps
                 * something people typically don't want to see, if we see a channel enter
                 * into Dial here, we set the appl/data accordingly and lock it.
                 */
-               if (!strcmp(snapshot->appl, "Dial")) {
+               if (!strcmp(snapshot->dialplan->appl, "Dial")) {
                        ast_set_flag(&cdr->flags, AST_CDR_LOCK_APP);
                }
        }
 
-       if (strcmp(cdr->linkedid, snapshot->linkedid)) {
-               ast_string_field_set(cdr, linkedid, snapshot->linkedid);
+       if (strcmp(cdr->linkedid, snapshot->peer->linkedid)) {
+               ast_string_field_set(cdr, linkedid, snapshot->peer->linkedid);
        }
        cdr_object_check_party_a_answer(cdr);
        cdr_object_check_party_a_hangup(cdr);
@@ -1611,7 +1603,7 @@ static int base_process_parked_channel(struct cdr_object *cdr, struct ast_parked
 {
        char park_info[128];
 
-       ast_assert(!strcasecmp(parking_info->parkee->name, cdr->party_a.snapshot->name));
+       ast_assert(!strcasecmp(parking_info->parkee->base->name, cdr->party_a.snapshot->base->name));
 
        /* Update Party A information regardless */
        cdr->fn_table->process_party_a(cdr, parking_info->parkee);
@@ -1645,25 +1637,25 @@ static void single_state_process_party_b(struct cdr_object *cdr, struct ast_chan
 
 static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
 {
-       if (caller && !strcasecmp(cdr->party_a.snapshot->name, caller->name)) {
+       if (caller && !strcasecmp(cdr->party_a.snapshot->base->name, caller->base->name)) {
                base_process_party_a(cdr, caller);
                CDR_DEBUG("%p - Updated Party A %s snapshot\n", cdr,
-                       cdr->party_a.snapshot->name);
+                       cdr->party_a.snapshot->base->name);
                cdr_object_swap_snapshot(&cdr->party_b, peer);
                cdr_all_relink(cdr);
                CDR_DEBUG("%p - Updated Party B %s snapshot\n", cdr,
-                       cdr->party_b.snapshot->name);
+                       cdr->party_b.snapshot->base->name);
 
                /* If we have two parties, lock the application that caused the
                 * two parties to be associated. This prevents mid-call event
                 * macros/gosubs from perturbing the CDR application/data
                 */
                ast_set_flag(&cdr->flags, AST_CDR_LOCK_APP);
-       } else if (!strcasecmp(cdr->party_a.snapshot->name, peer->name)) {
+       } else if (!strcasecmp(cdr->party_a.snapshot->base->name, peer->base->name)) {
                /* We're the entity being dialed, i.e., outbound origination */
                base_process_party_a(cdr, peer);
                CDR_DEBUG("%p - Updated Party A %s snapshot\n", cdr,
-                       cdr->party_a.snapshot->name);
+                       cdr->party_a.snapshot->base->name);
        }
 
        cdr_object_transition_state(cdr, &dial_state_fn_table);
@@ -1688,15 +1680,15 @@ static int single_state_bridge_enter_comparison(struct cdr_object *cdr,
        struct cdr_object_snapshot *party_a;
 
        /* Don't match on ourselves */
-       if (!strcasecmp(cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name)) {
+       if (!strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)) {
                return 1;
        }
 
        /* Try the candidate CDR's Party A first */
        party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
-       if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
+       if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
                CDR_DEBUG("%p - Party A %s has new Party B %s\n",
-                       cdr, cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name);
+                       cdr, cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name);
                cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
                cdr_all_relink(cdr);
                if (!cand_cdr->party_b.snapshot) {
@@ -1711,13 +1703,13 @@ static int single_state_bridge_enter_comparison(struct cdr_object *cdr,
 
        /* Try their Party B, unless it's us */
        if (!cand_cdr->party_b.snapshot
-               || !strcasecmp(cdr->party_a.snapshot->name, cand_cdr->party_b.snapshot->name)) {
+               || !strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_b.snapshot->base->name)) {
                return 1;
        }
        party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_b);
-       if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
+       if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
                CDR_DEBUG("%p - Party A %s has new Party B %s\n",
-                       cdr, cdr->party_a.snapshot->name, cand_cdr->party_b.snapshot->name);
+                       cdr, cdr->party_a.snapshot->base->name, cand_cdr->party_b.snapshot->base->name);
                cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_b);
                cdr_all_relink(cdr);
                return 0;
@@ -1796,7 +1788,7 @@ static void dial_state_process_party_b(struct cdr_object *cdr, struct ast_channe
 {
        ast_assert(snapshot != NULL);
        ast_assert(cdr->party_b.snapshot
-               && !strcasecmp(cdr->party_b.snapshot->name, snapshot->name));
+               && !strcasecmp(cdr->party_b.snapshot->base->name, snapshot->base->name));
 
        cdr_object_swap_snapshot(&cdr->party_b, snapshot);
 
@@ -1847,11 +1839,11 @@ static int dial_state_process_dial_end(struct cdr_object *cdr, struct ast_channe
        } else {
                party_a = peer;
        }
-       ast_assert(!strcasecmp(cdr->party_a.snapshot->name, party_a->name));
+       ast_assert(!strcasecmp(cdr->party_a.snapshot->base->name, party_a->base->name));
        cdr_object_swap_snapshot(&cdr->party_a, party_a);
 
        if (cdr->party_b.snapshot) {
-               if (strcasecmp(cdr->party_b.snapshot->name, peer->name)) {
+               if (strcasecmp(cdr->party_b.snapshot->base->name, peer->base->name)) {
                        /* Not the status for this CDR - defer back to the message router */
                        return 1;
                }
@@ -1909,7 +1901,7 @@ static enum process_bridge_enter_results dial_state_process_bridge_enter(struct
                                }
 
                                /* Skip any records that aren't our Party B */
-                               if (strcasecmp(cdr->party_b.snapshot->name, cand_cdr->party_a.snapshot->name)) {
+                               if (strcasecmp(cdr->party_b.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)) {
                                        continue;
                                }
                                cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
@@ -1990,7 +1982,7 @@ static int dialed_pending_state_process_dial_begin(struct cdr_object *cdr, struc
 static void bridge_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
 {
        ast_assert(cdr->party_b.snapshot
-               && !strcasecmp(cdr->party_b.snapshot->name, snapshot->name));
+               && !strcasecmp(cdr->party_b.snapshot->base->name, snapshot->base->name));
 
        cdr_object_swap_snapshot(&cdr->party_b, snapshot);
 
@@ -2005,9 +1997,9 @@ static int bridge_state_process_bridge_leave(struct cdr_object *cdr, struct ast_
        if (strcmp(cdr->bridge, bridge->uniqueid)) {
                return 1;
        }
-       if (strcasecmp(cdr->party_a.snapshot->name, channel->name)
+       if (strcasecmp(cdr->party_a.snapshot->base->name, channel->base->name)
                && cdr->party_b.snapshot
-               && strcasecmp(cdr->party_b.snapshot->name, channel->name)) {
+               && strcasecmp(cdr->party_b.snapshot->base->name, channel->base->name)) {
                return 1;
        }
        cdr_object_transition_state(cdr, &finalized_state_fn_table);
@@ -2019,7 +2011,7 @@ static int bridge_state_process_bridge_leave(struct cdr_object *cdr, struct ast_
 
 static int parked_state_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
 {
-       if (strcasecmp(cdr->party_a.snapshot->name, channel->name)) {
+       if (strcasecmp(cdr->party_a.snapshot->base->name, channel->base->name)) {
                return 1;
        }
        cdr_object_transition_state(cdr, &finalized_state_fn_table);
@@ -2051,14 +2043,14 @@ static int finalized_state_process_party_a(struct cdr_object *cdr, struct ast_ch
  */
 static int filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
 {
-       return snapshot->tech_properties & AST_CHAN_TP_INTERNAL;
+       return snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL;
 }
 
 /*!
  * \internal
- * \brief Filter a channel cache update
+ * \brief Filter a channel snapshot update
  */
-static int filter_channel_cache_message(struct ast_channel_snapshot *old_snapshot,
+static int filter_channel_snapshot_message(struct ast_channel_snapshot *old_snapshot,
                struct ast_channel_snapshot *new_snapshot)
 {
        int ret = 0;
@@ -2122,19 +2114,19 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str
 
        CDR_DEBUG("Dial %s message for %s, %s: %u.%08u\n",
                ast_strlen_zero(dial_status) ? "Begin" : "End",
-               caller ? caller->name : "(none)",
-               peer ? peer->name : "(none)",
+               caller ? caller->base->name : "(none)",
+               peer ? peer->base->name : "(none)",
                (unsigned int)stasis_message_timestamp(message)->tv_sec,
                (unsigned int)stasis_message_timestamp(message)->tv_usec);
 
        /* Figure out who is running this show */
        if (caller) {
-               cdr = ao2_find(active_cdrs_master, caller->uniqueid, OBJ_SEARCH_KEY);
+               cdr = ao2_find(active_cdrs_master, caller->base->uniqueid, OBJ_SEARCH_KEY);
        } else {
-               cdr = ao2_find(active_cdrs_master, peer->uniqueid, OBJ_SEARCH_KEY);
+               cdr = ao2_find(active_cdrs_master, peer->base->uniqueid, OBJ_SEARCH_KEY);
        }
        if (!cdr) {
-               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", caller ? caller->name : peer->name);
+               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", caller ? caller->base->name : peer->base->name);
                ast_assert(0);
                return;
        }
@@ -2147,8 +2139,8 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str
                        }
                        CDR_DEBUG("%p - Processing Dial Begin message for channel %s, peer %s\n",
                                it_cdr,
-                               caller ? caller->name : "(none)",
-                               peer ? peer->name : "(none)");
+                               caller ? caller->base->name : "(none)",
+                               peer ? peer->base->name : "(none)");
                        res &= it_cdr->fn_table->process_dial_begin(it_cdr,
                                        caller,
                                        peer);
@@ -2158,8 +2150,8 @@ static void handle_dial_message(void *data, struct stasis_subscription *sub, str
                        }
                        CDR_DEBUG("%p - Processing Dial End message for channel %s, peer %s\n",
                                it_cdr,
-                               caller ? caller->name : "(none)",
-                               peer ? peer->name : "(none)");
+                               caller ? caller->base->name : "(none)",
+                               peer ? peer->base->name : "(none)");
                        it_cdr->fn_table->process_dial_end(it_cdr,
                                        caller,
                                        peer,
@@ -2193,7 +2185,7 @@ static int cdr_object_finalize_party_b(void *obj, void *arg, void *data, int fla
                 * is consistent with the key.
                 */
                ast_assert(cdr->party_b.snapshot
-                       && !strcasecmp(cdr->party_b.snapshot->name, party_b->name));
+                       && !strcasecmp(cdr->party_b.snapshot->base->name, party_b->base->name));
 #endif
 
                /* Don't transition to the finalized state - let the Party A do
@@ -2218,11 +2210,11 @@ static int cdr_object_update_party_b(void *obj, void *arg, void *data, int flags
                 * asserts the snapshot to be this way.
                 */
                if (!cdr->party_b.snapshot
-                       || strcasecmp(cdr->party_b.snapshot->name, party_b->name)) {
+                       || strcasecmp(cdr->party_b.snapshot->base->name, party_b->base->name)) {
                        ast_log(LOG_NOTICE,
                                "CDR for Party A %s(%s) has inconsistent Party B %s name.  Message can be ignored but this shouldn't happen.\n",
                                cdr->linkedid,
-                               cdr->party_a.snapshot->name,
+                               cdr->party_a.snapshot->base->name,
                                cdr->party_b_name);
                        return 0;
                }
@@ -2244,7 +2236,7 @@ static int check_new_cdr_needed(struct ast_channel_snapshot *old_snapshot,
        }
 
        /* Auto-fall through will increment the priority but have no application */
-       if (ast_strlen_zero(new_snapshot->appl)) {
+       if (ast_strlen_zero(new_snapshot->dialplan->appl)) {
                return 0;
        }
 
@@ -2256,52 +2248,38 @@ static int check_new_cdr_needed(struct ast_channel_snapshot *old_snapshot,
 }
 
 /*!
- * \brief Handler for Stasis-Core channel cache update messages
+ * \brief Handler for channel snapshot update messages
  * \param data Passed on
  * \param sub The stasis subscription for this message callback
  * \param topic The topic this message was published for
  * \param message The message
  */
-static void handle_channel_cache_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
+static void handle_channel_snapshot_update_message(void *data, struct stasis_subscription *sub, struct stasis_message *message)
 {
        struct cdr_object *cdr;
-       struct stasis_cache_update *update = stasis_message_data(message);
-       struct ast_channel_snapshot *old_snapshot;
-       struct ast_channel_snapshot *new_snapshot;
+       struct ast_channel_snapshot_update *update = stasis_message_data(message);
        struct cdr_object *it_cdr;
 
-       ast_assert(update != NULL);
-       ast_assert(ast_channel_snapshot_type() == update->type);
-
-       old_snapshot = stasis_message_data(update->old_snapshot);
-       new_snapshot = stasis_message_data(update->new_snapshot);
-
-       if (filter_channel_cache_message(old_snapshot, new_snapshot)) {
+       if (filter_channel_snapshot_message(update->old_snapshot, update->new_snapshot)) {
                return;
        }
 
-       if (new_snapshot && !old_snapshot) {
-               cdr = cdr_object_alloc(new_snapshot);
+       if (update->new_snapshot && !update->old_snapshot) {
+               cdr = cdr_object_alloc(update->new_snapshot);
                if (!cdr) {
                        return;
                }
                cdr->is_root = 1;
                ao2_link(active_cdrs_master, cdr);
        } else {
-               const char *uniqueid;
-
-               uniqueid = new_snapshot ? new_snapshot->uniqueid : old_snapshot->uniqueid;
-               cdr = ao2_find(active_cdrs_master, uniqueid, OBJ_SEARCH_KEY);
+               cdr = ao2_find(active_cdrs_master, update->new_snapshot->base->uniqueid, OBJ_SEARCH_KEY);
        }
 
        /* Handle Party A */
        if (!cdr) {
-               const char *name;
-
-               name = new_snapshot ? new_snapshot->name : old_snapshot->name;
-               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", name);
+               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", update->new_snapshot->base->name);
                ast_assert(0);
-       } else if (new_snapshot) {
+       } else {
                int all_reject = 1;
 
                ao2_lock(cdr);
@@ -2309,21 +2287,23 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription
                        if (!it_cdr->fn_table->process_party_a) {
                                continue;
                        }
-                       all_reject &= it_cdr->fn_table->process_party_a(it_cdr, new_snapshot);
+                       all_reject &= it_cdr->fn_table->process_party_a(it_cdr, update->new_snapshot);
                }
-               if (all_reject && check_new_cdr_needed(old_snapshot, new_snapshot)) {
+               if (all_reject && check_new_cdr_needed(update->old_snapshot, update->new_snapshot)) {
                        /* We're not hung up and we have a new snapshot - we need a new CDR */
                        struct cdr_object *new_cdr;
 
                        new_cdr = cdr_object_create_and_append(cdr);
                        if (new_cdr) {
-                               new_cdr->fn_table->process_party_a(new_cdr, new_snapshot);
+                               new_cdr->fn_table->process_party_a(new_cdr, update->new_snapshot);
                        }
                }
                ao2_unlock(cdr);
-       } else {
+       }
+
+       if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
                ao2_lock(cdr);
-               CDR_DEBUG("%p - Beginning finalize/dispatch for %s\n", cdr, old_snapshot->name);
+               CDR_DEBUG("%p - Beginning finalize/dispatch for %s\n", cdr, update->old_snapshot->base->name);
                for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
                        cdr_object_finalize(it_cdr);
                }
@@ -2335,12 +2315,14 @@ static void handle_channel_cache_message(void *data, struct stasis_subscription
        }
 
        /* Handle Party B */
-       if (new_snapshot) {
+       if (update->new_snapshot) {
                ao2_callback_data(active_cdrs_all, OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY,
-                       cdr_object_update_party_b, (char *) new_snapshot->name, new_snapshot);
-       } else {
+                       cdr_object_update_party_b, (char *) update->new_snapshot->base->name, update->new_snapshot);
+       }
+
+       if (ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
                ao2_callback_data(active_cdrs_all, OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY,
-                       cdr_object_finalize_party_b, (char *) old_snapshot->name, old_snapshot);
+                       cdr_object_finalize_party_b, (char *) update->new_snapshot->base->name, update->new_snapshot);
        }
 
        ao2_cleanup(cdr);
@@ -2365,7 +2347,7 @@ static int cdr_object_party_b_left_bridge_cb(void *obj, void *arg, void *data, i
                 * is consistent with the key.
                 */
                ast_assert(cdr->party_b.snapshot
-                       && !strcasecmp(cdr->party_b.snapshot->name, leave_data->channel->name));
+                       && !strcasecmp(cdr->party_b.snapshot->base->name, leave_data->channel->base->name));
 
                /* It is our Party B, in our bridge. Set the end time and let the handler
                 * transition our CDR appropriately when we leave the bridge.
@@ -2417,13 +2399,13 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription *
        }
 
        CDR_DEBUG("Bridge Leave message for %s: %u.%08u\n",
-               channel->name,
+               channel->base->name,
                (unsigned int)stasis_message_timestamp(message)->tv_sec,
                (unsigned int)stasis_message_timestamp(message)->tv_usec);
 
-       cdr = ao2_find(active_cdrs_master, channel->uniqueid, OBJ_SEARCH_KEY);
+       cdr = ao2_find(active_cdrs_master, channel->base->uniqueid, OBJ_SEARCH_KEY);
        if (!cdr) {
-               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
+               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
                ast_assert(0);
                return;
        }
@@ -2435,7 +2417,7 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription *
                        continue;
                }
                CDR_DEBUG("%p - Processing Bridge Leave for %s\n",
-                       it_cdr, channel->name);
+                       it_cdr, channel->base->name);
                if (!it_cdr->fn_table->process_bridge_leave(it_cdr, bridge, channel)) {
                        ast_string_field_set(it_cdr, bridge, "");
                        left_bridge = 1;
@@ -2447,7 +2429,7 @@ static void handle_bridge_leave_message(void *data, struct stasis_subscription *
        if (left_bridge
                && strcmp(bridge->subclass, "parking")) {
                ao2_callback_data(active_cdrs_all, OBJ_NODATA | OBJ_MULTIPLE | OBJ_SEARCH_KEY,
-                       cdr_object_party_b_left_bridge_cb, (char *) leave_data.channel->name,
+                       cdr_object_party_b_left_bridge_cb, (char *) leave_data.channel->base->name,
                        &leave_data);
        }
 
@@ -2475,8 +2457,8 @@ static void bridge_candidate_add_to_cdr(struct cdr_object *cdr,
        ast_string_field_set(new_cdr, bridge, cdr->bridge);
        cdr_object_transition_state(new_cdr, &bridge_state_fn_table);
        CDR_DEBUG("%p - Party A %s has new Party B %s\n",
-               new_cdr, new_cdr->party_a.snapshot->name,
-               party_b->snapshot->name);
+               new_cdr, new_cdr->party_a.snapshot->base->name,
+               party_b->snapshot->base->name);
 }
 
 /*!
@@ -2505,16 +2487,16 @@ static void bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *
                }
 
                /* If the candidate is us or someone we've taken on, pass on by */
-               if (!strcasecmp(cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name)
+               if (!strcasecmp(cdr->party_a.snapshot->base->name, cand_cdr->party_a.snapshot->base->name)
                        || (cdr->party_b.snapshot
-                               && !strcasecmp(cdr->party_b.snapshot->name, cand_cdr->party_a.snapshot->name))) {
+                               && !strcasecmp(cdr->party_b.snapshot->base->name, cand_cdr->party_a.snapshot->base->name))) {
                        break;
                }
 
                party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
                /* We're party A - make a new CDR, append it to us, and set the candidate as
                 * Party B */
-               if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
+               if (!strcasecmp(party_a->snapshot->base->name, cdr->party_a.snapshot->base->name)) {
                        bridge_candidate_add_to_cdr(cdr, &cand_cdr->party_a);
                        break;
                }
@@ -2522,12 +2504,12 @@ static void bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *
                /* We're Party B. Check if we can add ourselves immediately or if we need
                 * a new CDR for them (they already have a Party B) */
                if (cand_cdr->party_b.snapshot
-                       && strcasecmp(cand_cdr->party_b.snapshot->name, cdr->party_a.snapshot->name)) {
+                       && strcasecmp(cand_cdr->party_b.snapshot->base->name, cdr->party_a.snapshot->base->name)) {
                        bridge_candidate_add_to_cdr(cand_cdr, &cdr->party_a);
                } else {
                        CDR_DEBUG("%p - Party A %s has new Party B %s\n",
-                               cand_cdr, cand_cdr->party_a.snapshot->name,
-                               cdr->party_a.snapshot->name);
+                               cand_cdr, cand_cdr->party_a.snapshot->base->name,
+                               cdr->party_a.snapshot->base->name);
                        cdr_object_snapshot_copy(&cand_cdr->party_b, &cdr->party_a);
                        cdr_all_relink(cand_cdr);
                        /* It's possible that this joined at one point and was never chosen
@@ -2590,7 +2572,7 @@ static void handle_parking_bridge_enter_message(struct cdr_object *cdr,
                }
                if (it_cdr->fn_table->process_party_a) {
                        CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr,
-                               channel->name);
+                               channel->base->name);
                        it_cdr->fn_table->process_party_a(it_cdr, channel);
                }
        }
@@ -2627,14 +2609,14 @@ try_again:
        for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
                if (it_cdr->fn_table->process_party_a) {
                        CDR_DEBUG("%p - Updating Party A %s snapshot\n", it_cdr,
-                               channel->name);
+                               channel->base->name);
                        it_cdr->fn_table->process_party_a(it_cdr, channel);
                }
 
                /* Notify all states that they have entered a bridge */
                if (it_cdr->fn_table->process_bridge_enter) {
                        CDR_DEBUG("%p - Processing bridge enter for %s\n", it_cdr,
-                               channel->name);
+                               channel->base->name);
                        result = it_cdr->fn_table->process_bridge_enter(it_cdr, bridge, channel);
                        switch (result) {
                        case BRIDGE_ENTER_ONLY_PARTY:
@@ -2707,13 +2689,13 @@ static void handle_bridge_enter_message(void *data, struct stasis_subscription *
        }
 
        CDR_DEBUG("Bridge Enter message for channel %s: %u.%08u\n",
-               channel->name,
+               channel->base->name,
                (unsigned int)stasis_message_timestamp(message)->tv_sec,
                (unsigned int)stasis_message_timestamp(message)->tv_usec);
 
-       cdr = ao2_find(active_cdrs_master, channel->uniqueid, OBJ_SEARCH_KEY);
+       cdr = ao2_find(active_cdrs_master, channel->base->uniqueid, OBJ_SEARCH_KEY);
        if (!cdr) {
-               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
+               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
                ast_assert(0);
                return;
        }
@@ -2757,13 +2739,13 @@ static void handle_parked_call_message(void *data, struct stasis_subscription *s
        }
 
        CDR_DEBUG("Parked Call message for channel %s: %u.%08u\n",
-               channel->name,
+               channel->base->name,
                (unsigned int)stasis_message_timestamp(message)->tv_sec,
                (unsigned int)stasis_message_timestamp(message)->tv_usec);
 
-       cdr = ao2_find(active_cdrs_master, channel->uniqueid, OBJ_SEARCH_KEY);
+       cdr = ao2_find(active_cdrs_master, channel->base->uniqueid, OBJ_SEARCH_KEY);
        if (!cdr) {
-               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->name);
+               ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", channel->base->name);
                ast_assert(0);
                return;
        }
@@ -3112,8 +3094,8 @@ static int cdr_object_select_all_by_name_cb(void *obj, void *arg, int flags)
        struct cdr_object *cdr = obj;
        const char *name = arg;
 
-       if (!strcasecmp(cdr->party_a.snapshot->name, name) ||
-                       (cdr->party_b.snapshot && !strcasecmp(cdr->party_b.snapshot->name, name))) {
+       if (!strcasecmp(cdr->party_a.snapshot->base->name, name) ||
+                       (cdr->party_b.snapshot && !strcasecmp(cdr->party_b.snapshot->base->name, name))) {
                return CMP_MATCH;
        }
        return 0;
@@ -3128,7 +3110,7 @@ static int cdr_object_get_by_name_cb(void *obj, void *arg, int flags)
        struct cdr_object *cdr = obj;
        const char *name = arg;
 
-       if (!strcasecmp(cdr->party_a.snapshot->name, name)) {
+       if (!strcasecmp(cdr->party_a.snapshot->base->name, name)) {
                return CMP_MATCH;
        }
        return 0;
@@ -3188,10 +3170,10 @@ int ast_cdr_setvar(const char *channel_name, const char *name, const char *value
                        if (it_cdr->fn_table == &finalized_state_fn_table && it_cdr->next != NULL) {
                                continue;
                        }
-                       if (!strcasecmp(channel_name, it_cdr->party_a.snapshot->name)) {
+                       if (!strcasecmp(channel_name, it_cdr->party_a.snapshot->base->name)) {
                                headp = &it_cdr->party_a.variables;
                        } else if (it_cdr->party_b.snapshot
-                               && !strcasecmp(channel_name, it_cdr->party_b.snapshot->name)) {
+                               && !strcasecmp(channel_name, it_cdr->party_b.snapshot->base->name)) {
                                headp = &it_cdr->party_b.variables;
                        }
                        if (headp) {
@@ -3230,25 +3212,25 @@ static int cdr_object_format_property(struct cdr_object *cdr_obj, const char *na
        struct ast_channel_snapshot *party_b = cdr_obj->party_b.snapshot;
 
        if (!strcasecmp(name, "clid")) {
-               ast_callerid_merge(value, length, party_a->caller_name, party_a->caller_number, "");
+               ast_callerid_merge(value, length, party_a->caller->name, party_a->caller->number, "");
        } else if (!strcasecmp(name, "src")) {
-               ast_copy_string(value, party_a->caller_number, length);
+               ast_copy_string(value, party_a->caller->number, length);
        } else if (!strcasecmp(name, "dst")) {
-               ast_copy_string(value, party_a->exten, length);
+               ast_copy_string(value, party_a->dialplan->exten, length);
        } else if (!strcasecmp(name, "dcontext")) {
-               ast_copy_string(value, party_a->context, length);
+               ast_copy_string(value, party_a->dialplan->context, length);
        } else if (!strcasecmp(name, "channel")) {
-               ast_copy_string(value, party_a->name, length);
+               ast_copy_string(value, party_a->base->name, length);
        } else if (!strcasecmp(name, "dstchannel")) {
                if (party_b) {
-                       ast_copy_string(value, party_b->name, length);
+                       ast_copy_string(value, party_b->base->name, length);
                } else {
                        ast_copy_string(value, "", length);
                }
        } else if (!strcasecmp(name, "lastapp")) {
-               ast_copy_string(value, party_a->appl, length);
+               ast_copy_string(value, party_a->dialplan->appl, length);
        } else if (!strcasecmp(name, "lastdata")) {
-               ast_copy_string(value, party_a->data, length);
+               ast_copy_string(value, party_a->dialplan->data, length);
        } else if (!strcasecmp(name, "start")) {
                cdr_get_tv(cdr_obj->start, NULL, value, length);
        } else if (!strcasecmp(name, "answer")) {
@@ -3264,15 +3246,15 @@ static int cdr_object_format_property(struct cdr_object *cdr_obj, const char *na
        } else if (!strcasecmp(name, "amaflags")) {
                snprintf(value, length, "%d", party_a->amaflags);
        } else if (!strcasecmp(name, "accountcode")) {
-               ast_copy_string(value, party_a->accountcode, length);
+               ast_copy_string(value, party_a->base->accountcode, length);
        } else if (!strcasecmp(name, "peeraccount")) {
                if (party_b) {
-                       ast_copy_string(value, party_b->accountcode, length);
+                       ast_copy_string(value, party_b->base->accountcode, length);
                } else {
                        ast_copy_string(value, "", length);
                }
        } else if (!strcasecmp(name, "uniqueid")) {
-               ast_copy_string(value, party_a->uniqueid, length);
+               ast_copy_string(value, party_a->base->uniqueid, length);
        } else if (!strcasecmp(name, "linkedid")) {
                ast_copy_string(value, cdr_obj->linkedid, length);
        } else if (!strcasecmp(name, "userfield")) {
@@ -3449,7 +3431,7 @@ static int cdr_object_update_party_b_userfield_cb(void *obj, void *arg, void *da
                 * is consistent with the key.
                 */
                ast_assert(cdr->party_b.snapshot
-                       && !strcasecmp(cdr->party_b.snapshot->name, info->channel_name));
+                       && !strcasecmp(cdr->party_b.snapshot->base->name, info->channel_name));
 
                ast_copy_string(cdr->party_b.userfield, info->userfield,
                        sizeof(cdr->party_b.userfield));
@@ -3642,7 +3624,7 @@ int ast_cdr_fork(const char *channel_name, struct ast_flags *options)
                /* Copy over the basic CDR information. The Party A information is
                 * copied over automatically as part of the append
                 */
-               ast_debug(1, "Forking CDR for channel %s\n", cdr->party_a.snapshot->name);
+               ast_debug(1, "Forking CDR for channel %s\n", cdr->party_a.snapshot->base->name);
                new_cdr = cdr_object_create_and_append(cdr);
                if (!new_cdr) {
                        return -1;
@@ -3956,8 +3938,8 @@ static char *cli_complete_show(struct ast_cli_args *a)
 
        it_cdrs = ao2_iterator_init(active_cdrs_master, 0);
        while ((cdr = ao2_iterator_next(&it_cdrs))) {
-               if (!strncasecmp(a->word, cdr->party_a.snapshot->name, wordlen)) {
-                       if (ast_cli_completion_add(ast_strdup(cdr->party_a.snapshot->name))) {
+               if (!strncasecmp(a->word, cdr->party_a.snapshot->base->name, wordlen)) {
+                       if (ast_cli_completion_add(ast_strdup(cdr->party_a.snapshot->base->name))) {
                                ao2_ref(cdr, -1);
                                break;
                        }
@@ -4019,8 +4001,8 @@ static void cli_show_channels(struct ast_cli_args *a)
                cdr_get_tv(start_time, "%T", start_time_buffer, sizeof(start_time_buffer));
                cdr_get_tv(answer_time, "%T", answer_time_buffer, sizeof(answer_time_buffer));
                cdr_get_tv(end_time, "%T", end_time_buffer, sizeof(end_time_buffer));
-               ast_cli(a->fd, FORMAT_STRING, it_cdr->party_a.snapshot->name,
-                               it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "<none>",
+               ast_cli(a->fd, FORMAT_STRING, it_cdr->party_a.snapshot->base->name,
+                               it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<none>",
                                it_cdr->appl,
                                start_time_buffer,
                                answer_time_buffer,
@@ -4064,7 +4046,7 @@ static void cli_show_channel(struct ast_cli_args *a)
                if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
                        continue;
                }
-               ast_callerid_merge(clid, sizeof(clid), it_cdr->party_a.snapshot->caller_name, it_cdr->party_a.snapshot->caller_number, "");
+               ast_callerid_merge(clid, sizeof(clid), it_cdr->party_a.snapshot->caller->name, it_cdr->party_a.snapshot->caller->number, "");
                if (ast_tvzero(it_cdr->end)) {
                        end = ast_tvnow();
                } else {
@@ -4074,9 +4056,9 @@ static void cli_show_channel(struct ast_cli_args *a)
                cdr_get_tv(it_cdr->answer, "%T", answer_time_buffer, sizeof(answer_time_buffer));
                cdr_get_tv(end, "%T", end_time_buffer, sizeof(end_time_buffer));
                ast_cli(a->fd, FORMAT_STRING,
-                               it_cdr->party_a.snapshot->accountcode,
+                               it_cdr->party_a.snapshot->base->accountcode,
                                clid,
-                               it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "<none>",
+                               it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<none>",
                                it_cdr->appl,
                                it_cdr->data,
                                start_time_buffer,
@@ -4302,7 +4284,7 @@ static int create_subscriptions(void)
                return 0;
        }
 
-       channel_subscription = stasis_forward_all(ast_channel_topic_all_cached(), cdr_topic);
+       channel_subscription = stasis_forward_all(ast_channel_topic_all(), cdr_topic);
        if (!channel_subscription) {
                return -1;
        }
@@ -4433,8 +4415,8 @@ static void cdr_master_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
        }
        for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
                prnt(where, "Party A: %s; Party B: %s; Bridge %s\n",
-                       it_cdr->party_a.snapshot->name,
-                       it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->name : "<unknown>",
+                       it_cdr->party_a.snapshot->base->name,
+                       it_cdr->party_b.snapshot ? it_cdr->party_b.snapshot->base->name : "<unknown>",
                        it_cdr->bridge);
        }
 }
@@ -4458,8 +4440,8 @@ static void cdr_all_print_fn(void *v_obj, void *where, ao2_prnt_fn *prnt)
                return;
        }
        prnt(where, "Party A: %s; Party B: %s; Bridge %s",
-               cdr->party_a.snapshot->name,
-               cdr->party_b.snapshot ? cdr->party_b.snapshot->name : "<unknown>",
+               cdr->party_a.snapshot->base->name,
+               cdr->party_b.snapshot ? cdr->party_b.snapshot->base->name : "<unknown>",
                cdr->bridge);
 }
 
@@ -4522,7 +4504,7 @@ static int load_module(void)
                return AST_MODULE_LOAD_FAILURE;
        }
 
-       stasis_message_router_add_cache_update(stasis_router, ast_channel_snapshot_type(), handle_channel_cache_message, NULL);
+       stasis_message_router_add(stasis_router, ast_channel_snapshot_type(), handle_channel_snapshot_update_message, NULL);
        stasis_message_router_add(stasis_router, ast_channel_dial_type(), handle_dial_message, NULL);
        stasis_message_router_add(stasis_router, ast_channel_entered_bridge_type(), handle_bridge_enter_message, NULL);
        stasis_message_router_add(stasis_router, ast_channel_left_bridge_type(), handle_bridge_leave_message, NULL);
@@ -4530,14 +4512,14 @@ static int load_module(void)
        stasis_message_router_add(stasis_router, cdr_sync_message_type(), handle_cdr_sync_message, NULL);
 
        active_cdrs_master = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
-               NUM_CDR_BUCKETS, cdr_master_hash_fn, NULL, cdr_master_cmp_fn);
+               AST_NUM_CHANNEL_BUCKETS, cdr_master_hash_fn, NULL, cdr_master_cmp_fn);
        if (!active_cdrs_master) {
                return AST_MODULE_LOAD_FAILURE;
        }
        ao2_container_register("cdrs_master", active_cdrs_master, cdr_master_print_fn);
 
        active_cdrs_all = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
-               NUM_CDR_BUCKETS, cdr_all_hash_fn, NULL, cdr_all_cmp_fn);
+               AST_NUM_CHANNEL_BUCKETS, cdr_all_hash_fn, NULL, cdr_all_cmp_fn);
        if (!active_cdrs_all) {
                return AST_MODULE_LOAD_FAILURE;
        }
index 0ec728e..242aeff 100644 (file)
@@ -528,22 +528,22 @@ struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
                AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
                AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
                AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, S_OR(userdefevname, ""),
-               AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_name,
-               AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_number,
-               AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_ani,
-               AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_rdnis,
-               AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR, snapshot->caller_dnid,
-               AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, snapshot->exten,
-               AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, snapshot->context,
-               AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->name,
-               AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->appl,
-               AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, snapshot->data,
+               AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->name,
+               AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->number,
+               AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->ani,
+               AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->rdnis,
+               AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR, snapshot->caller->dnid,
+               AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, snapshot->dialplan->exten,
+               AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, snapshot->dialplan->context,
+               AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->base->name,
+               AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, snapshot->dialplan->appl,
+               AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, snapshot->dialplan->data,
                AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, snapshot->amaflags,
-               AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, snapshot->accountcode,
-               AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, snapshot->peeraccount,
-               AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, snapshot->uniqueid,
-               AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, snapshot->linkedid,
-               AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, snapshot->userfield,
+               AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, snapshot->base->accountcode,
+               AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, snapshot->peer->account,
+               AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, snapshot->base->uniqueid,
+               AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, snapshot->peer->linkedid,
+               AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, snapshot->base->userfield,
                AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, S_OR(extra_txt, ""),
                AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, S_OR(peer, ""),
                AST_EVENT_IE_END);
@@ -573,7 +573,7 @@ static int cel_report_event(struct ast_channel_snapshot *snapshot,
         * reporting on CHANNEL_START so we can track when to send LINKEDID_END */
        if (event_type == AST_CEL_CHANNEL_START
                && ast_cel_track_event(AST_CEL_LINKEDID_END)) {
-               if (cel_linkedid_ref(snapshot->linkedid)) {
+               if (cel_linkedid_ref(snapshot->peer->linkedid)) {
                        return -1;
                }
        }
@@ -583,7 +583,7 @@ static int cel_report_event(struct ast_channel_snapshot *snapshot,
        }
 
        if ((event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END)
-               && !cel_track_app(snapshot->appl)) {
+               && !cel_track_app(snapshot->dialplan->appl)) {
                return 0;
        }
 
@@ -606,14 +606,14 @@ static void check_retire_linkedid(struct ast_channel_snapshot *snapshot)
        RAII_VAR(struct ao2_container *, linkedids, ao2_global_obj_ref(cel_linkedids), ao2_cleanup);
        struct cel_linkedid *lid;
 
-       if (!linkedids || ast_strlen_zero(snapshot->linkedid)) {
+       if (!linkedids || ast_strlen_zero(snapshot->peer->linkedid)) {
                /* The CEL module is shutdown.  Abort. */
                return;
        }
 
        ao2_lock(linkedids);
 
-       lid = ao2_find(linkedids, (void *) snapshot->linkedid, OBJ_SEARCH_KEY);
+       lid = ao2_find(linkedids, (void *) snapshot->peer->linkedid, OBJ_SEARCH_KEY);
        if (!lid) {
                ao2_unlock(linkedids);
 
@@ -623,7 +623,7 @@ static void check_retire_linkedid(struct ast_channel_snapshot *snapshot)
                 * of change to make after starting Asterisk.
                 */
                ast_log(LOG_ERROR, "Something weird happened, couldn't find linkedid %s\n",
-                       snapshot->linkedid);
+                       snapshot->peer->linkedid);
                return;
        }
 
@@ -888,14 +888,6 @@ static void cel_channel_state_change(
 {
        int is_hungup, was_hungup;
 
-       if (!new_snapshot) {
-               cel_report_event(old_snapshot, AST_CEL_CHANNEL_END, NULL, NULL, NULL);
-               if (ast_cel_track_event(AST_CEL_LINKEDID_END)) {
-                       check_retire_linkedid(old_snapshot);
-               }
-               return;
-       }
-
        if (!old_snapshot) {
                cel_report_event(new_snapshot, AST_CEL_CHANNEL_START, NULL, NULL, NULL);
                return;
@@ -906,15 +898,20 @@ static void cel_channel_state_change(
 
        if (!was_hungup && is_hungup) {
                struct ast_json *extra;
-               struct cel_dialstatus *dialstatus = get_dialstatus(new_snapshot->uniqueid);
+               struct cel_dialstatus *dialstatus = get_dialstatus(new_snapshot->base->uniqueid);
 
                extra = ast_json_pack("{s: i, s: s, s: s}",
-                       "hangupcause", new_snapshot->hangupcause,
-                       "hangupsource", new_snapshot->hangupsource,
+                       "hangupcause", new_snapshot->hangup->cause,
+                       "hangupsource", new_snapshot->hangup->source,
                        "dialstatus", dialstatus ? dialstatus->dialstatus : "");
                cel_report_event(new_snapshot, AST_CEL_HANGUP, NULL, extra, NULL);
                ast_json_unref(extra);
                ao2_cleanup(dialstatus);
+
+               cel_report_event(new_snapshot, AST_CEL_CHANNEL_END, NULL, NULL, NULL);
+               if (ast_cel_track_event(AST_CEL_LINKEDID_END)) {
+                       check_retire_linkedid(new_snapshot);
+               }
                return;
        }
 
@@ -928,16 +925,16 @@ static void cel_channel_linkedid_change(
        struct ast_channel_snapshot *old_snapshot,
        struct ast_channel_snapshot *new_snapshot)
 {
-       if (!old_snapshot || !new_snapshot) {
+       if (!old_snapshot) {
                return;
        }
 
-       ast_assert(!ast_strlen_zero(new_snapshot->linkedid));
-       ast_assert(!ast_strlen_zero(old_snapshot->linkedid));
+       ast_assert(!ast_strlen_zero(new_snapshot->peer->linkedid));
+       ast_assert(!ast_strlen_zero(old_snapshot->peer->linkedid));
 
        if (ast_cel_track_event(AST_CEL_LINKEDID_END)
-               && strcmp(old_snapshot->linkedid, new_snapshot->linkedid)) {
-               cel_linkedid_ref(new_snapshot->linkedid);
+               && strcmp(old_snapshot->peer->linkedid, new_snapshot->peer->linkedid)) {
+               cel_linkedid_ref(new_snapshot->peer->linkedid);
                check_retire_linkedid(old_snapshot);
        }
 }
@@ -946,18 +943,17 @@ static void cel_channel_app_change(
        struct ast_channel_snapshot *old_snapshot,
        struct ast_channel_snapshot *new_snapshot)
 {
-       if (new_snapshot && old_snapshot
-               && !strcmp(old_snapshot->appl, new_snapshot->appl)) {
+       if (old_snapshot && !strcmp(old_snapshot->dialplan->appl, new_snapshot->dialplan->appl)) {
                return;
        }
 
        /* old snapshot has an application, end it */
-       if (old_snapshot && !ast_strlen_zero(old_snapshot->appl)) {
+       if (old_snapshot && !ast_strlen_zero(old_snapshot->dialplan->appl)) {
                cel_report_event(old_snapshot, AST_CEL_APP_END, NULL, NULL, NULL);
        }
 
        /* new snapshot has an application, start it */
-       if (new_snapshot && !ast_strlen_zero(new_snapshot->appl)) {
+       if (!ast_strlen_zero(new_snapshot->dialplan->appl)) {
                cel_report_event(new_snapshot, AST_CEL_APP_START, NULL, NULL, NULL);
        }
 }
@@ -978,28 +974,21 @@ static int cel_filter_channel_snapshot(struct ast_channel_snapshot *snapshot)
        if (!snapshot) {
                return 0;
        }
-       return snapshot->tech_properties & AST_CHAN_TP_INTERNAL;
+       return snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL;
 }
 
 static void cel_snapshot_update_cb(void *data, struct stasis_subscription *sub,
        struct stasis_message *message)
 {
-       struct stasis_cache_update *update = stasis_message_data(message);
-       if (ast_channel_snapshot_type() == update->type) {
-               struct ast_channel_snapshot *old_snapshot;
-               struct ast_channel_snapshot *new_snapshot;
-               size_t i;
-
-               old_snapshot = stasis_message_data(update->old_snapshot);
-               new_snapshot = stasis_message_data(update->new_snapshot);
+       struct ast_channel_snapshot_update *update = stasis_message_data(message);
+       size_t i;
 
-               if (cel_filter_channel_snapshot(old_snapshot) || cel_filter_channel_snapshot(new_snapshot)) {
-                       return;
-               }
+       if (cel_filter_channel_snapshot(update->old_snapshot) || cel_filter_channel_snapshot(update->new_snapshot)) {
+               return;
+       }
 
-               for (i = 0; i < ARRAY_LEN(cel_channel_monitors); ++i) {
-                       cel_channel_monitors[i](old_snapshot, new_snapshot);
-               }
+       for (i = 0; i < ARRAY_LEN(cel_channel_monitors); ++i) {
+               cel_channel_monitors[i](update->old_snapshot, update->new_snapshot);
        }
 }
 
@@ -1021,7 +1010,7 @@ static struct ast_str *cel_generate_peer_str(
                struct ast_channel_snapshot *current_snapshot;
 
                /* Don't add the channel for which this message is being generated */
-               if (!strcmp(current_chan, chan->uniqueid)) {
+               if (!strcmp(current_chan, chan->base->uniqueid)) {
                        continue;
                }
 
@@ -1030,7 +1019,7 @@ static struct ast_str *cel_generate_peer_str(
                        continue;
                }
 
-               ast_str_append(&peer_str, 0, "%s,", current_snapshot->name);
+               ast_str_append(&peer_str, 0, "%s,", current_snapshot->base->name);
                ao2_cleanup(current_snapshot);
        }
        ao2_iterator_destroy(&i);
@@ -1136,7 +1125,7 @@ static void cel_parking_cb(
        if (parked_payload->retriever) {
                extra = ast_json_pack("{s: s, s: s}",
                        "reason", reason ?: "",
-                       "retriever", parked_payload->retriever->name);
+                       "retriever", parked_payload->retriever->base->name);
        } else {
                extra = ast_json_pack("{s: s}", "reason", reason ?: "");
        }
@@ -1158,7 +1147,7 @@ static void save_dialstatus(struct ast_multi_channel_blob *blob, struct ast_chan
                return;
        }
 
-       dialstatus = ao2_find(dial_statuses, snapshot->uniqueid, OBJ_SEARCH_KEY);
+       dialstatus = ao2_find(dial_statuses, snapshot->base->uniqueid, OBJ_SEARCH_KEY);
        if (dialstatus) {
                if (!strcasecmp(dialstatus_string, "ANSWER") && strcasecmp(dialstatus->dialstatus, "ANSWER")) {
                        /* In the case of an answer after we already have a dial status we give
@@ -1182,7 +1171,7 @@ static void save_dialstatus(struct ast_multi_channel_blob *blob, struct ast_chan
                return;
        }
 
-       ast_copy_string(dialstatus->uniqueid, snapshot->uniqueid, sizeof(dialstatus->uniqueid));
+       ast_copy_string(dialstatus->uniqueid, snapshot->base->uniqueid, sizeof(dialstatus->uniqueid));
        ast_copy_string(dialstatus->dialstatus, dialstatus_string, dialstatus_string_len);
 
        ao2_link(dial_statuses, dialstatus);
@@ -1284,8 +1273,8 @@ static void cel_blind_transfer_cb(
                "extension", transfer_msg->exten,
                "context", transfer_msg->context,
                "bridge_id", bridge_snapshot->uniqueid,
-               "transferee_channel_name", transfer_msg->transferee ? transfer_msg->transferee->name : "N/A",
-               "transferee_channel_uniqueid", transfer_msg->transferee ? transfer_msg->transferee->uniqueid  : "N/A");
+               "transferee_channel_name", transfer_msg->transferee ? transfer_msg->transferee->base->name : "N/A",
+               "transferee_channel_uniqueid", transfer_msg->transferee ? transfer_msg->transferee->base->uniqueid  : "N/A");
        if (extra) {
                cel_report_event(chan_snapshot, AST_CEL_BLINDTRANSFER, NULL, extra, NULL);
                ast_json_unref(extra);
@@ -1323,13 +1312,13 @@ static void cel_attended_transfer_cb(
        case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
                extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}",
                        "bridge1_id", bridge1->uniqueid,
-                       "channel2_name", channel2->name,
-                       "channel2_uniqueid", channel2->uniqueid,
+                       "channel2_name", channel2->base->name,
+                       "channel2_uniqueid", channel2->base->uniqueid,
                        "bridge2_id", bridge2->uniqueid,
-                       "transferee_channel_name", xfer->transferee ? xfer->transferee->name : "N/A",
-                       "transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->uniqueid : "N/A",
-                       "transfer_target_channel_name", xfer->target ? xfer->target->name : "N/A",
-                       "transfer_target_channel_uniqueid", xfer->target ? xfer->target->uniqueid : "N/A");
+                       "transferee_channel_name", xfer->transferee ? xfer->transferee->base->name : "N/A",
+                       "transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->base->uniqueid : "N/A",
+                       "transfer_target_channel_name", xfer->target ? xfer->target->base->name : "N/A",
+                       "transfer_target_channel_uniqueid", xfer->target ? xfer->target->base->uniqueid : "N/A");
                if (!extra) {
                        return;
                }
@@ -1338,13 +1327,13 @@ static void cel_attended_transfer_cb(
        case AST_ATTENDED_TRANSFER_DEST_LOCAL_APP:
                extra = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: s, s: s}",
                        "bridge1_id", bridge1->uniqueid,
-                       "channel2_name", channel2->name,
-                       "channel2_uniqueid", channel2->uniqueid,
+                       "channel2_name", channel2->base->name,
+                       "channel2_uniqueid", channel2->base->uniqueid,
                        "app", xfer->dest.app,
-                       "transferee_channel_name", xfer->transferee ? xfer->transferee->name : "N/A",
-                       "transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->uniqueid : "N/A",
-                       "transfer_target_channel_name", xfer->target ? xfer->target->name : "N/A",
-                       "transfer_target_channel_uniqueid", xfer->target ? xfer->target->uniqueid : "N/A");
+                       "transferee_channel_name", xfer->transferee ? xfer->transferee->base->name : "N/A",
+                       "transferee_channel_uniqueid", xfer->transferee ? xfer->transferee->base->uniqueid : "N/A",
+                       "transfer_target_channel_name", xfer->target ? xfer->target->base->name : "N/A",
+                       "transfer_target_channel_uniqueid", xfer->target ? xfer->target->base->uniqueid : "N/A");
                if (!extra) {
                        return;
                }
@@ -1368,8 +1357,8 @@ static void cel_pickup_cb(
        }
 
        extra = ast_json_pack("{s: s, s: s}",
-               "pickup_channel", channel->name,
-               "pickup_channel_uniqueid", channel->uniqueid);
+               "pickup_channel", channel->base->name,
+               "pickup_channel_uniqueid", channel->base->uniqueid);
        if (!extra) {
                return;
        }
@@ -1392,8 +1381,8 @@ static void cel_local_cb(
        }
 
        extra = ast_json_pack("{s: s, s: s}",
-               "local_two", localtwo->name,
-               "local_two_uniqueid", localtwo->uniqueid);
+               "local_two", localtwo->base->name,
+               "local_two_uniqueid", localtwo->base->uniqueid);
        if (!extra) {
                return;
        }
@@ -1453,7 +1442,7 @@ static int create_subscriptions(void)
        }
 
        cel_channel_forwarder = stasis_forward_all(
-               ast_channel_topic_all_cached(),
+               ast_channel_topic_all(),
                cel_aggregation_topic);
        if (!cel_channel_forwarder) {
                return -1;
@@ -1498,7 +1487,7 @@ static int create_routes(void)
                6 * AST_TASKPROCESSOR_HIGH_WATER_LEVEL);
 
        ret |= stasis_message_router_add(cel_state_router,
-               stasis_cache_update_type(),
+               ast_channel_snapshot_type(),
                cel_snapshot_update_cb,
                NULL);
 
@@ -1561,15 +1550,16 @@ static int load_module(void)
 {
        struct ao2_container *container;
 
-       container = ao2_container_alloc(NUM_APP_BUCKETS, cel_linkedid_hash_fn, cel_linkedid_cmp_fn);
+       container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               NUM_APP_BUCKETS, cel_linkedid_hash_fn, NULL, cel_linkedid_cmp_fn);
        ao2_global_obj_replace_unref(cel_linkedids, container);
        ao2_cleanup(container);
        if (!container) {
                return AST_MODULE_LOAD_FAILURE;
        }
 
-       container = ao2_container_alloc(NUM_DIALSTATUS_BUCKETS,
-               cel_dialstatus_hash_fn, cel_dialstatus_cmp_fn);
+       container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               NUM_DIALSTATUS_BUCKETS, cel_dialstatus_hash_fn, NULL, cel_dialstatus_cmp_fn);
        ao2_global_obj_replace_unref(cel_dialstatus_store, container);
        ao2_cleanup(container);
        if (!container) {
@@ -1584,7 +1574,8 @@ static int load_module(void)
                return AST_MODULE_LOAD_FAILURE;
        }
 
-       container = ao2_container_alloc(BACKEND_BUCKETS, cel_backend_hash_fn, cel_backend_cmp_fn);
+       container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, BACKEND_BUCKETS,
+               cel_backend_hash_fn, NULL, cel_backend_cmp_fn);
        ao2_global_obj_replace_unref(cel_backends, container);
        ao2_cleanup(container);
        if (!container) {
index a72439c..7e12f30 100644 (file)
@@ -116,12 +116,6 @@ struct chanlist {
 /*! \brief the list of registered channel types */
 static AST_RWLIST_HEAD_STATIC(backends, chanlist);
 
-#ifdef LOW_MEMORY
-#define NUM_CHANNEL_BUCKETS 61
-#else
-#define NUM_CHANNEL_BUCKETS 1567
-#endif
-
 /*! \brief All active channels on the system */
 static struct ao2_container *channels;
 
@@ -635,38 +629,6 @@ int ast_str2cause(const char *name)
        return -1;
 }
 
-static struct stasis_message *create_channel_snapshot_message(struct ast_channel *channel)
-{
-       RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
-
-       if (!ast_channel_snapshot_type()) {
-               return NULL;
-       }
-
-       ast_channel_lock(channel);
-       snapshot = ast_channel_snapshot_create(channel);
-       ast_channel_unlock(channel);
-       if (!snapshot) {
-               return NULL;
-       }
-
-       return stasis_message_create(ast_channel_snapshot_type(), snapshot);
-}
-
-static void publish_cache_clear(struct ast_channel *chan)
-{
-       RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
-       RAII_VAR(struct stasis_message *, clear_msg, NULL, ao2_cleanup);
-
-       clear_msg = create_channel_snapshot_message(chan);
-       if (!clear_msg) {
-               return;
-       }
-
-       message = stasis_cache_clear_create(clear_msg);
-       stasis_publish(ast_channel_topic(chan), message);
-}
-
 /*! \brief Gives the string form of a given channel state.
  *
  * \note This function is not reentrant.
@@ -1236,7 +1198,9 @@ int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
                                     "musicclass", musicclass);
        }
 
-       ast_channel_publish_cached_blob(chan, ast_channel_hold_type(), blob);
+       ast_channel_lock(chan);
+       ast_channel_publish_blob(chan, ast_channel_hold_type(), blob);
+       ast_channel_unlock(chan);
 
        res = ast_queue_frame(chan, &f);
 
@@ -1250,7 +1214,9 @@ int ast_queue_unhold(struct ast_channel *chan)
        struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_UNHOLD };
        int res;
 
-       ast_channel_publish_cached_blob(chan, ast_channel_unhold_type(), NULL);
+       ast_channel_lock(chan);
+       ast_channel_publish_blob(chan, ast_channel_unhold_type(), NULL);
+       ast_channel_unlock(chan);
 
        res = ast_queue_frame(chan, &f);
 
@@ -2230,9 +2196,8 @@ static void ast_channel_destructor(void *obj)
                ast_assert(!ast_test_flag(ast_channel_flags(chan), AST_FLAG_SNAPSHOT_STAGE));
 
                ast_channel_lock(chan);
-               ast_channel_publish_snapshot(chan);
+               ast_channel_publish_final_snapshot(chan);
                ast_channel_unlock(chan);
-               publish_cache_clear(chan);
        }
 
        ast_channel_lock(chan);
@@ -3344,7 +3309,7 @@ static void send_dtmf_begin_event(struct ast_channel *chan,
                return;
        }
 
-       ast_channel_publish_cached_blob(chan, ast_channel_dtmf_begin_type(), blob);
+       ast_channel_publish_blob(chan, ast_channel_dtmf_begin_type(), blob);
 }
 
 static void send_dtmf_end_event(struct ast_channel *chan,
@@ -3361,7 +3326,7 @@ static void send_dtmf_end_event(struct ast_channel *chan,
                return;
        }
 
-       ast_channel_publish_cached_blob(chan, ast_channel_dtmf_end_type(), blob);
+       ast_channel_publish_blob(chan, ast_channel_dtmf_end_type(), blob);
 }
 
 static void ast_read_generator_actions(struct ast_channel *chan, struct ast_frame *f)
@@ -6796,6 +6761,12 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
                ast_channel_name(clonechan), ast_channel_state(clonechan),
                ast_channel_name(original), ast_channel_state(original));
 
+       /* When all is said and done force new snapshot segments so they are
+        * up to date.
+        */
+       ast_set_flag(ast_channel_snapshot_segment_flags(original), AST_FLAGS_ALL);
+       ast_set_flag(ast_channel_snapshot_segment_flags(clonechan), AST_FLAGS_ALL);
+
        /*
         * Remember the original read/write formats.  We turn off any
         * translation on either one
@@ -6819,6 +6790,9 @@ static void channel_do_masquerade(struct ast_channel *original, struct ast_chann
        /* Make sure the Stasis topic on the channel is updated appropriately */
        ast_channel_internal_swap_topics(clonechan, original);
 
+       /* The old snapshots need to follow the channels so the snapshot update is correct */
+       ast_channel_internal_swap_snapshots(clonechan, original);
+
        /* Swap channel names. This uses ast_channel_name_set directly, so we
         * don't get any spurious rename events.
         */
@@ -7215,6 +7189,7 @@ void ast_channel_set_caller(struct ast_channel *chan, const struct ast_party_cal
 
        ast_channel_lock(chan);
        ast_party_caller_set(ast_channel_caller(chan), caller, update);
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
        ast_channel_unlock(chan);
 }
 
@@ -7227,6 +7202,7 @@ void ast_channel_set_caller_event(struct ast_channel *chan, const struct ast_par
 
        ast_channel_lock(chan);
        ast_party_caller_set(ast_channel_caller(chan), caller, update);
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
        ast_channel_publish_snapshot(chan);
        ast_channel_unlock(chan);
 }
@@ -7246,7 +7222,7 @@ int ast_setstate(struct ast_channel *chan, enum ast_channel_state state)
 
        ast_channel_state_set(chan, state);
 
-       ast_publish_channel_state(chan);
+       ast_channel_publish_snapshot(chan);
 
        /* We have to pass AST_DEVICE_UNKNOWN here because it is entirely possible that the channel driver
         * for this channel is using the callback method for device state. If we pass in an actual state here
@@ -7856,8 +7832,8 @@ static void channels_shutdown(void)
 
 int ast_channels_init(void)
 {
-       channels = ao2_container_alloc(NUM_CHANNEL_BUCKETS,
-                       ast_channel_hash_cb, ast_channel_cmp_cb);
+       channels = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, AST_NUM_CHANNEL_BUCKETS,
+               ast_channel_hash_cb, NULL, ast_channel_cmp_cb);
        if (!channels) {
                return -1;
        }
@@ -8152,6 +8128,7 @@ void ast_channel_set_connected_line(struct ast_channel *chan, const struct ast_p
 
        ast_channel_lock(chan);
        ast_party_connected_line_set(ast_channel_connected(chan), connected, update);
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CONNECTED);
        ast_channel_publish_snapshot(chan);
        ast_channel_unlock(chan);
 }
@@ -8962,6 +8939,7 @@ void ast_channel_set_redirecting(struct ast_channel *chan, const struct ast_part
 
        ast_channel_lock(chan);
        ast_party_redirecting_set(ast_channel_redirecting(chan), redirecting, update);
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
        ast_channel_unlock(chan);
 }
 
index b926514..30d3909 100644 (file)
@@ -42,7 +42,6 @@
 #include "asterisk/channel_internal.h"
 #include "asterisk/endpoints.h"
 #include "asterisk/indications.h"
-#include "asterisk/stasis_cache_pattern.h"
 #include "asterisk/stasis_channels.h"
 #include "asterisk/stasis_endpoints.h"
 #include "asterisk/stringfields.h"
@@ -215,12 +214,14 @@ struct ast_channel {
        char dtmf_digit_to_emulate;                     /*!< Digit being emulated */
        char sending_dtmf_digit;                        /*!< Digit this channel is currently sending out. (zero if not sending) */
        struct timeval sending_dtmf_tv;         /*!< The time this channel started sending the current digit. (Invalid if sending_dtmf_digit is zero.) */
-       struct stasis_cp_single *topics;                /*!< Topic for all channel's events */
+       struct stasis_topic *topic;             /*!< Topic for trhis channel */
+       struct stasis_forward *channel_forward; /*!< Subscription for event forwarding to all channel topic */
        struct stasis_forward *endpoint_forward;        /*!< Subscription for event forwarding to endpoint's topic */
-       struct stasis_forward *endpoint_cache_forward; /*!< Subscription for cache updates to endpoint's topic */
        struct ast_stream_topology *stream_topology; /*!< Stream topology */
        void *stream_topology_change_source; /*!< Source that initiated a stream topology change */
        struct ast_stream *default_streams[AST_MEDIA_TYPE_END]; /*!< Default streams indexed by media type */
+       struct ast_channel_snapshot *snapshot; /*!< The current up to date snapshot of the channel */
+       struct ast_flags snapshot_segment_flags; /*!< Flags regarding the segments of the snapshot */
 };
 
 /*! \brief The monotonically increasing integer counter for channel uniqueids */
@@ -228,18 +229,40 @@ static int uniqueint;
 
 /* ACCESSORS */
 
-#define DEFINE_STRINGFIELD_SETTERS_FOR(field, publish, assert_on_null) \
+#define DEFINE_STRINGFIELD_SETTERS_FOR(field, assert_on_null) \
 void ast_channel_##field##_set(struct ast_channel *chan, const char *value) \
 { \
        if ((assert_on_null)) ast_assert(!ast_strlen_zero(value)); \
        if (!strcmp(value, chan->field)) return; \
        ast_string_field_set(chan, field, value); \
+} \
+  \
+void ast_channel_##field##_build_va(struct ast_channel *chan, const char *fmt, va_list ap) \
+{ \
+       ast_string_field_build_va(chan, field, fmt, ap); \
+} \
+void ast_channel_##field##_build(struct ast_channel *chan, const char *fmt, ...) \
+{ \
+       va_list ap; \
+       va_start(ap, fmt); \
+       ast_channel_##field##_build_va(chan, fmt, ap); \
+       va_end(ap); \
+}
+
+#define DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(field, publish, assert_on_null, invalidate) \
+void ast_channel_##field##_set(struct ast_channel *chan, const char *value) \
+{ \
+       if ((assert_on_null)) ast_assert(!ast_strlen_zero(value)); \
+       if (!strcmp(value, chan->field)) return; \
+       ast_string_field_set(chan, field, value); \
+       ast_channel_snapshot_invalidate_segment(chan, invalidate); \
        if (publish && ast_channel_internal_is_finalized(chan)) ast_channel_publish_snapshot(chan); \
 } \
   \
 void ast_channel_##field##_build_va(struct ast_channel *chan, const char *fmt, va_list ap) \
 { \
        ast_string_field_build_va(chan, field, fmt, ap); \
+       ast_channel_snapshot_invalidate_segment(chan, invalidate); \
        if (publish && ast_channel_internal_is_finalized(chan)) ast_channel_publish_snapshot(chan); \
 } \
 void ast_channel_##field##_build(struct ast_channel *chan, const char *fmt, ...) \
@@ -250,17 +273,17 @@ void ast_channel_##field##_build(struct ast_channel *chan, const char *fmt, ...)
        va_end(ap); \
 }
 
-DEFINE_STRINGFIELD_SETTERS_FOR(name, 0, 1);
-DEFINE_STRINGFIELD_SETTERS_FOR(language, 1, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(musicclass, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(latest_musicclass, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(accountcode, 1, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(peeraccount, 1, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(userfield, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(call_forward, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(parkinglot, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(hangupsource, 0, 0);
-DEFINE_STRINGFIELD_SETTERS_FOR(dialcontext, 0, 0);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(name, 0, 1, AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(language, 1, 0, AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE);
+DEFINE_STRINGFIELD_SETTERS_FOR(musicclass, 0);
+DEFINE_STRINGFIELD_SETTERS_FOR(latest_musicclass, 0);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(accountcode, 1, 0, AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(peeraccount, 1, 0, AST_CHANNEL_SNAPSHOT_INVALIDATE_PEER);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(userfield, 0, 0, AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE);
+DEFINE_STRINGFIELD_SETTERS_FOR(call_forward, 0);
+DEFINE_STRINGFIELD_SETTERS_FOR(parkinglot, 0);
+DEFINE_STRINGFIELD_SETTERS_AND_INVALIDATE_FOR(hangupsource, 0, 0, AST_CHANNEL_SNAPSHOT_INVALIDATE_HANGUP);
+DEFINE_STRINGFIELD_SETTERS_FOR(dialcontext, 0);
 
 #define DEFINE_STRINGFIELD_GETTER_FOR(field) const char *ast_channel_##field(const struct ast_channel *chan) \
 { \
@@ -298,6 +321,7 @@ const char *ast_channel_appl(const struct ast_channel *chan)
 void ast_channel_appl_set(struct ast_channel *chan, const char *value)
 {
        chan->appl = value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
 }
 const char *ast_channel_blockproc(const struct ast_channel *chan)
 {
@@ -314,6 +338,7 @@ const char *ast_channel_data(const struct ast_channel *chan)
 void ast_channel_data_set(struct ast_channel *chan, const char *value)
 {
        chan->data = value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
 }
 
 const char *ast_channel_context(const struct ast_channel *chan)
@@ -323,6 +348,7 @@ const char *ast_channel_context(const struct ast_channel *chan)
 void ast_channel_context_set(struct ast_channel *chan, const char *value)
 {
        ast_copy_string(chan->context, value, sizeof(chan->context));
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
 }
 const char *ast_channel_exten(const struct ast_channel *chan)
 {
@@ -331,6 +357,7 @@ const char *ast_channel_exten(const struct ast_channel *chan)
 void ast_channel_exten_set(struct ast_channel *chan, const char *value)
 {
        ast_copy_string(chan->exten, value, sizeof(chan->exten));
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
 }
 const char *ast_channel_macrocontext(const struct ast_channel *chan)
 {
@@ -404,6 +431,7 @@ int ast_channel_hangupcause(const struct ast_channel *chan)
 void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
 {
        chan->hangupcause = value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_HANGUP);
 }
 int ast_channel_macropriority(const struct ast_channel *chan)
 {
@@ -420,6 +448,7 @@ int ast_channel_priority(const struct ast_channel *chan)
 void ast_channel_priority_set(struct ast_channel *chan, int value)
 {
        chan->priority = value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
 }
 int ast_channel_rings(const struct ast_channel *chan)
 {
@@ -909,18 +938,22 @@ void ast_channel_jb_set(struct ast_channel *chan, struct ast_jb *value)
 void ast_channel_caller_set(struct ast_channel *chan, struct ast_party_caller *value)
 {
        chan->caller = *value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
 }
 void ast_channel_connected_set(struct ast_channel *chan, struct ast_party_connected_line *value)
 {
        chan->connected = *value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CONNECTED);
 }
 void ast_channel_dialed_set(struct ast_channel *chan, struct ast_party_dialed *value)
 {
        chan->dialed = *value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
 }
 void ast_channel_redirecting_set(struct ast_channel *chan, struct ast_party_redirecting *value)
 {
        chan->redirecting = *value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_CALLER);
 }
 void ast_channel_dtmf_tv_set(struct ast_channel *chan, struct timeval *value)
 {
@@ -941,6 +974,7 @@ struct timeval ast_channel_creationtime(struct ast_channel *chan)
 void ast_channel_creationtime_set(struct ast_channel *chan, struct timeval *value)
 {
        chan->creationtime = *value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE);
 }
 
 struct timeval ast_channel_answertime(struct ast_channel *chan)
@@ -1204,6 +1238,7 @@ struct ast_bridge *ast_channel_internal_bridge(const struct ast_channel *chan)
 void ast_channel_internal_bridge_set(struct ast_channel *chan, struct ast_bridge *value)
 {
        chan->bridge = value;
+       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_BRIDGE);
        ast_channel_publish_snapshot(chan);
 }
 
@@ -1302,7 +1337,9 @@ struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj),
                return ast_channel_unref(tmp);
        }
 
-       if (!(tmp->dialed_causes = ao2_container_alloc(DIALED_CAUSES_BUCKETS, pvt_cause_hash_fn, pvt_cause_cmp_fn))) {
+       tmp->dialed_causes = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               DIALED_CAUSES_BUCKETS, pvt_cause_hash_fn, NULL, pvt_cause_cmp_fn);
+       if (!tmp->dialed_causes) {
                return ast_channel_unref(tmp);
        }
 
@@ -1333,6 +1370,11 @@ struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj),
 
        AST_VECTOR_INIT(&tmp->fds, AST_MAX_FDS);
 
+       /* Force all channel snapshot segments to be created on first use, so we don't have to check if
+        * an old snapshot exists.
+        */
+       ast_set_flag(&tmp->snapshot_segment_flags, AST_FLAGS_ALL);
+
        return tmp;
 }
 
@@ -1361,6 +1403,7 @@ void ast_channel_internal_copy_linkedid(struct ast_channel *dest, struct ast_cha
                return;
        }
        dest->linkedid = source->linkedid;
+       ast_channel_snapshot_invalidate_segment(dest, AST_CHANNEL_SNAPSHOT_INVALIDATE_PEER);
        ast_channel_publish_snapshot(dest);
 }
 
@@ -1368,6 +1411,10 @@ void ast_channel_internal_swap_uniqueid_and_linkedid(struct ast_channel *a, stru
 {
        struct ast_channel_id temp;
 
+       /* This operation is used as part of masquerading and so does not invalidate the peer
+        * segment. This is due to the masquerade process invalidating all segments.
+        */
+
        temp = a->uniqueid;
        a->uniqueid = b->uniqueid;
        b->uniqueid = temp;
@@ -1379,11 +1426,25 @@ void ast_channel_internal_swap_uniqueid_and_linkedid(struct ast_channel *a, stru
 
 void ast_channel_internal_swap_topics(struct ast_channel *a, struct ast_channel *b)
 {
-       struct stasis_cp_single *temp;
+       struct stasis_topic *topic;
+       struct stasis_forward *forward;
+
+       topic = a->topic;
+       a->topic = b->topic;
+       b->topic = topic;
 
-       temp = a->topics;
-       a->topics = b->topics;
-       b->topics = temp;
+       forward = a->channel_forward;
+       a->channel_forward = b->channel_forward;
+       b->channel_forward = forward;
+}
+
+void ast_channel_internal_swap_snapshots(struct ast_channel *a, struct ast_channel *b)
+{
+       struct ast_channel_snapshot *snapshot;
+
+       snapshot = a->snapshot;
+       a->snapshot = b->snapshot;
+       b->snapshot = snapshot;
 }
 
 void ast_channel_internal_set_fake_ids(struct ast_channel *chan, const char *uniqueid, const char *linkedid)
@@ -1402,11 +1463,11 @@ void ast_channel_internal_cleanup(struct ast_channel *chan)
 
        ast_string_field_free_memory(chan);
 
+       chan->channel_forward = stasis_forward_cancel(chan->channel_forward);
        chan->endpoint_forward = stasis_forward_cancel(chan->endpoint_forward);
-       chan->endpoint_cache_forward = stasis_forward_cancel(chan->endpoint_cache_forward);
 
-       stasis_cp_single_unsubscribe(chan->topics);
-       chan->topics = NULL;
+       ao2_cleanup(chan->topic);
+       chan->topic = NULL;
 
        ast_channel_internal_set_stream_topology(chan, NULL);
 
@@ -1429,16 +1490,7 @@ struct stasis_topic *ast_channel_topic(struct ast_channel *chan)
                return ast_channel_topic_all();
        }
 
-       return stasis_cp_single_topic(chan->topics);
-}
-
-struct stasis_topic *ast_channel_topic_cached(struct ast_channel *chan)
-{
-       if (!chan) {
-               return ast_channel_topic_all_cached();
-       }
-
-       return stasis_cp_single_topic_cached(chan->topics);
+       return chan->topic;
 }
 
 int ast_channel_forward_endpoint(struct ast_channel *chan,
@@ -1454,28 +1506,28 @@ int ast_channel_forward_endpoint(struct ast_channel *chan,
                return -1;
        }
 
-       chan->endpoint_cache_forward = stasis_forward_all(ast_channel_topic_cached(chan),
-               ast_endpoint_topic(endpoint));
-       if (!chan->endpoint_cache_forward) {
-               chan->endpoint_forward = stasis_forward_cancel(chan->endpoint_forward);
-               return -1;
-       }
-
        return 0;
 }
 
 int ast_channel_internal_setup_topics(struct ast_channel *chan)
 {
        const char *topic_name = chan->uniqueid.unique_id;
-       ast_assert(chan->topics == NULL);
+       ast_assert(chan->topic == NULL);
 
        if (ast_strlen_zero(topic_name)) {
                topic_name = "<dummy-channel>";
        }
 
-       chan->topics = stasis_cp_single_create(
-               ast_channel_cache_all(), topic_name);
-       if (!chan->topics) {
+       chan->topic = stasis_topic_create(topic_name);
+       if (!chan->topic) {
+               return -1;
+       }
+
+       chan->channel_forward = stasis_forward_all(ast_channel_topic(chan),
+               ast_channel_topic_all());
+       if (!chan->channel_forward) {
+               ao2_ref(chan->topic, -1);
+               chan->topic = NULL;
                return -1;
        }
 
@@ -1566,3 +1618,19 @@ int ast_channel_is_multistream(struct ast_channel *chan)
 {
        return (chan->tech && chan->tech->read_stream && chan->tech->write_stream);
 }
+
+struct ast_channel_snapshot *ast_channel_snapshot(const struct ast_channel *chan)
+{
+       return chan->snapshot;
+}
+
+void ast_channel_snapshot_set(struct ast_channel *chan, struct ast_channel_snapshot *snapshot)
+{
+       ao2_cleanup(chan->snapshot);
+       chan->snapshot = ao2_bump(snapshot);
+}
+
+struct ast_flags *ast_channel_snapshot_segment_flags(struct ast_channel *chan)
+{
+       return &chan->snapshot_segment_flags;
+}
index cf51d0d..e2224f7 100644 (file)
@@ -956,7 +956,7 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 
        struct ao2_container *channels;
        struct ao2_iterator it_chans;
-       struct stasis_message *msg;
+       struct ast_channel_snapshot *cs;
        int numchans = 0, concise = 0, verbose = 0, count = 0;
 
        switch (cmd) {
@@ -989,11 +989,7 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
        } else if (a->argc != e->args - 1)
                return CLI_SHOWUSAGE;
 
-
-       if (!(channels = stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type()))) {
-               ast_cli(a->fd, "Failed to retrieve cached channels\n");
-               return CLI_SUCCESS;
-       }
+       channels = ast_channel_cache_by_name();
 
        if (!count) {
                if (!concise && !verbose)
@@ -1004,13 +1000,12 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
        }
 
        it_chans = ao2_iterator_init(channels, 0);
-       for (; (msg = ao2_iterator_next(&it_chans)); ao2_ref(msg, -1)) {
-               struct ast_channel_snapshot *cs = stasis_message_data(msg);
+       for (; (cs = ao2_iterator_next(&it_chans)); ao2_ref(cs, -1)) {
                char durbuf[16] = "-";
 
                if (!count) {
-                       if ((concise || verbose)  && !ast_tvzero(cs->creationtime)) {
-                               int duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->creationtime) / 1000);
+                       if ((concise || verbose)  && !ast_tvzero(cs->base->creationtime)) {
+                               int duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->base->creationtime) / 1000);
                                if (verbose) {
                                        int durh = duration / 3600;
                                        int durm = (duration % 3600) / 60;
@@ -1021,36 +1016,36 @@ static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
                                }
                        }
                        if (concise) {
-                               ast_cli(a->fd, CONCISE_FORMAT_STRING, cs->name, cs->context, cs->exten, cs->priority, ast_state2str(cs->state),
-                                       S_OR(cs->appl, "(None)"),
-                                       cs->data,
-                                       cs->caller_number,
-                                       cs->accountcode,
-                                       cs->peeraccount,
+                               ast_cli(a->fd, CONCISE_FORMAT_STRING, cs->base->name, cs->dialplan->context, cs->dialplan->exten, cs->dialplan->priority, ast_state2str(cs->state),
+                                       S_OR(cs->dialplan->appl, "(None)"),
+                                       cs->dialplan->data,
+                                       cs->caller->number,
+                                       cs->base->accountcode,
+                                       cs->peer->account,
                                        cs->amaflags,
                                        durbuf,
-                                       cs->bridgeid,
-                                       cs->uniqueid);
+                                       cs->bridge->id,
+                                       cs->base->uniqueid);
                        } else if (verbose) {
-                               ast_cli(a->fd, VERBOSE_FORMAT_STRING, cs->name, cs->context, cs->exten, cs->priority, ast_state2str(cs->state),
-                                       S_OR(cs->appl, "(None)"),
-                                       S_OR(cs->data, "(Empty)"),
-                                       cs->caller_number,
+                               ast_cli(a->fd, VERBOSE_FORMAT_STRING, cs->base->name, cs->dialplan->context, cs->dialplan->exten, cs->dialplan->priority, ast_state2str(cs->state),
+                                       S_OR(cs->dialplan->appl, "(None)"),
+                                       S_OR(cs->dialplan->data, "(Empty)"),
+                                       cs->caller->number,
                                        durbuf,
-                                       cs->accountcode,
-                                       cs->peeraccount,
-                                       cs->bridgeid);
+                                       cs->base->accountcode,
+                                       cs->peer->account,
+                                       cs->bridge->id);
                        } else {
                                char locbuf[40] = "(None)";
                                char appdata[40] = "(None)";
 
-                               if (!ast_strlen_zero(cs->context) && !ast_strlen_zero(cs->exten)) {
-                                       snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", cs->exten, cs->context, cs->priority);
+                               if (!ast_strlen_zero(cs->dialplan->context) && !ast_strlen_zero(cs->dialplan->exten)) {
+                                       snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", cs->dialplan->exten, cs->dialplan->context, cs->dialplan->priority);
                                }
-                               if (!ast_strlen_zero(cs->appl)) {
-                                       snprintf(appdata, sizeof(appdata), "%s(%s)", cs->appl, S_OR(cs->data, ""));
+                               if (!ast_strlen_zero(cs->dialplan->appl)) {
+                                       snprintf(appdata, sizeof(appdata), "%s(%s)", cs->dialplan->appl, S_OR(cs->dialplan->data, ""));
                                }
-                               ast_cli(a->fd, FORMAT_STRING, cs->name, locbuf, ast_state2str(cs->state), appdata);
+                               ast_cli(a->fd, FORMAT_STRING, cs->base->name, locbuf, ast_state2str(cs->state), appdata);
                        }
                }
        }
@@ -1679,29 +1674,25 @@ char *ast_complete_channels(const char *line, const char *word, int pos, int sta
        struct ao2_container *cached_channels;
        char *ret = NULL;
        struct ao2_iterator iter;
-       struct stasis_message *msg;
+       struct ast_channel_snapshot *snapshot;
 
        if (pos != rpos) {
                return NULL;
        }
 
-       if (!(cached_channels = stasis_cache_dump(ast_channel_cache(), ast_channel_snapshot_type()))) {
-               return NULL;
-       }
+       cached_channels = ast_channel_cache_all();
 
        iter = ao2_iterator_init(cached_channels, 0);
-       for (; (msg = ao2_iterator_next(&iter)); ao2_ref(msg, -1)) {
-               struct ast_channel_snapshot *snapshot = stasis_message_data(msg);
-
-               if (!strncasecmp(word, snapshot->name, wordlen) && (++which > state)) {
+       for (; (snapshot = ao2_iterator_next(&iter)); ao2_ref(snapshot, -1)) {
+               if (!strncasecmp(word, snapshot->base->name, wordlen) && (++which > state)) {
                        if (state != -1) {
-                               ret = ast_strdup(snapshot->name);
-                               ao2_ref(msg, -1);
+                               ret = ast_strdup(snapshot->base->name);
+                               ao2_ref(snapshot, -1);
                                break;
                        }
 
-                       if (ast_cli_completion_add(ast_strdup(snapshot->name))) {
-                               ao2_ref(msg, -1);
+                       if (ast_cli_completion_add(ast_strdup(snapshot->base->name))) {
+                               ao2_ref(snapshot, -1);
                                break;
                        }
                }
index 1961b24..f694c2b 100644 (file)
@@ -2536,7 +2536,8 @@ int ast_config_text_file_save2(const char *configfile, const struct ast_config *
        struct ao2_container *fileset;
        struct inclfile *fi;
 
-       fileset = ao2_container_alloc(1023, hash_string, hashtab_compare_strings);
+       fileset = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 1023,
+               hash_string, NULL, hashtab_compare_strings);
        if (!fileset) {
                /* Container creation failed. */
                return -1;
@@ -4104,8 +4105,12 @@ int ast_config_hook_register(const char *name,
                config_hook_cb hook_cb)
 {
        struct cfg_hook *hook;
-       if (!cfg_hooks && !(cfg_hooks = ao2_container_alloc(17, hook_hash, hook_cmp))) {
-               return -1;
+       if (!cfg_hooks) {
+               cfg_hooks = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 17,
+                       hook_hash, NULL, hook_cmp);
+               if (!cfg_hooks) {
+                       return -1;
+               }
        }
 
        if (!(hook = ao2_alloc(sizeof(*hook), hook_destroy))) {
index 2d5e09c..cbd7622 100644 (file)
@@ -405,7 +405,8 @@ static struct aco_option *aco_option_find(struct aco_type *type, const char *nam
 
 struct ao2_container *aco_option_container_alloc(void)
 {
-       return ao2_container_alloc(CONFIG_OPT_BUCKETS, config_opt_hash, config_opt_cmp);
+       return ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, CONFIG_OPT_BUCKETS,
+               config_opt_hash, NULL, config_opt_cmp);
 }
 
 static int internal_aco_type_category_check(struct aco_type *match, const char *category)
index c3fa15f..f56aac7 100644 (file)
@@ -493,7 +493,7 @@ static struct ast_manager_event_blob *local_message_to_ami(struct stasis_message
                }
 
                dest_uniqueid = ast_json_object_get(blob, "dest") == AST_UNREAL_OWNER ?
-                               local_snapshot_one->uniqueid : local_snapshot_two->uniqueid;
+                               local_snapshot_one->base->uniqueid : local_snapshot_two->base->uniqueid;
 
                event = "LocalOptimizationBegin";
                if (source_str) {
index 5edad24..f37ee6c 100644 (file)
@@ -94,7 +94,8 @@ AO2_STRING_FIELD_CMP_FN(ast_datastore, uid);
 
 struct ao2_container *ast_datastores_alloc(void)
 {
-       return ao2_container_alloc(DATASTORE_BUCKETS, ast_datastore_hash_fn, ast_datastore_cmp_fn);
+       return ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               DATASTORE_BUCKETS, ast_datastore_hash_fn, NULL, ast_datastore_cmp_fn);
 }
 
 int ast_datastores_add(struct ao2_container *datastores, struct ast_datastore *datastore)
index 3129fb4..b958932 100644 (file)
@@ -179,25 +179,23 @@ int ast_endpoint_add_channel(struct ast_endpoint *endpoint,
        return 0;
 }
 
-/*! \brief Handler for channel snapshot cache clears */
+/*! \brief Handler for channel snapshot update */
 static void endpoint_cache_clear(void *data,
        struct stasis_subscription *sub,
        struct stasis_message *message)
 {
        struct ast_endpoint *endpoint = data;
-       struct stasis_message *clear_msg = stasis_message_data(message);
-       struct ast_channel_snapshot *clear_snapshot;
+       struct ast_channel_snapshot_update *update = stasis_message_data(message);
 
-       if (stasis_message_type(clear_msg) != ast_channel_snapshot_type()) {
+       /* Only when the channel is dead do we remove it */
+       if (!ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
                return;
        }
 
-       clear_snapshot = stasis_message_data(clear_msg);
-
        ast_assert(endpoint != NULL);
 
        ao2_lock(endpoint);
-       ast_str_container_remove(endpoint->channel_ids, clear_snapshot->uniqueid);
+       ast_str_container_remove(endpoint->channel_ids, update->new_snapshot->base->uniqueid);
        ao2_unlock(endpoint);
        endpoint_publish_snapshot(endpoint);
 }
@@ -271,7 +269,7 @@ static struct ast_endpoint *endpoint_internal_create(const char *tech, const cha
                        return NULL;
                }
                r |= stasis_message_router_add(endpoint->router,
-                       stasis_cache_clear_type(), endpoint_cache_clear,
+                       ast_channel_snapshot_type(), endpoint_cache_clear,
                        endpoint);
                r |= stasis_message_router_add(endpoint->router,
                        stasis_subscription_change_type(), endpoint_subscription_change,
@@ -482,14 +480,14 @@ int ast_endpoint_init(void)
 {
        ast_register_cleanup(endpoint_cleanup);
 
-       endpoints = ao2_container_alloc(ENDPOINT_BUCKETS, ast_endpoint_hash_fn,
-               ast_endpoint_cmp_fn);
+       endpoints = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, ENDPOINT_BUCKETS,
+               ast_endpoint_hash_fn, NULL, ast_endpoint_cmp_fn);
        if (!endpoints) {
                return -1;
        }
 
-       tech_endpoints = ao2_container_alloc(TECH_ENDPOINT_BUCKETS, ast_endpoint_hash_fn,
-               ast_endpoint_cmp_fn);
+       tech_endpoints = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               TECH_ENDPOINT_BUCKETS, ast_endpoint_hash_fn, NULL, ast_endpoint_cmp_fn);
        if (!tech_endpoints) {
                return -1;
        }
index 77755a9..1f77ca1 100644 (file)
@@ -1133,8 +1133,8 @@ static int unload_module(void)
 /*! \brief Load indications module */
 static int load_module(void)
 {
-       ast_tone_zones = ao2_container_alloc(NUM_TONE_ZONE_BUCKETS,
-                       ast_tone_zone_hash, ast_tone_zone_cmp);
+       ast_tone_zones = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               NUM_TONE_ZONE_BUCKETS, ast_tone_zone_hash, NULL, ast_tone_zone_cmp);
        if (!ast_tone_zones) {
                return AST_MODULE_LOAD_FAILURE;
        }
index 0da023a..3e41198 100644 (file)
@@ -2224,8 +2224,8 @@ static struct mansession_session *build_mansession(const struct ast_sockaddr *ad
                return NULL;
        }
 
-       newsession->whitefilters = ao2_container_alloc(1, NULL, NULL);
-       newsession->blackfilters = ao2_container_alloc(1, NULL, NULL);
+       newsession->whitefilters = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
+       newsession->blackfilters = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
        if (!newsession->whitefilters || !newsession->blackfilters) {
                ao2_ref(newsession, -1);
                return NULL;
@@ -6250,7 +6250,7 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
        int numchans = 0;
        struct ao2_container *channels;
        struct ao2_iterator it_chans;
-       struct stasis_message *msg;
+       struct ast_channel_snapshot *cs;
 
        if (!ast_strlen_zero(actionid)) {
                snprintf(idText, sizeof(idText), "ActionID: %s\r\n", actionid);
@@ -6258,17 +6258,12 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
                idText[0] = '\0';
        }
 
-       channels = stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type());
-       if (!channels) {
-               astman_send_error(s, m, "Could not get cached channels");
-               return 0;
-       }
+       channels = ast_channel_cache_by_name();
 
        astman_send_listack(s, m, "Channels will follow", "start");
 
        it_chans = ao2_iterator_init(channels, 0);
-       for (; (msg = ao2_iterator_next(&it_chans)); ao2_ref(msg, -1)) {
-               struct ast_channel_snapshot *cs = stasis_message_data(msg);
+       for (; (cs = ao2_iterator_next(&it_chans)); ao2_ref(cs, -1)) {
                struct ast_str *built = ast_manager_build_channel_state_string_prefix(cs, "");
                char durbuf[16] = "";
 
@@ -6276,10 +6271,10 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
                        continue;
                }
 
-               if (!ast_tvzero(cs->creationtime)) {
+               if (!ast_tvzero(cs->base->creationtime)) {
                        int duration, durh, durm, durs;
 
-                       duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->creationtime) / 1000);
+                       duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->base->creationtime) / 1000);
                        durh = duration / 3600;
                        durm = (duration % 3600) / 60;
                        durs = duration % 60;
@@ -6297,10 +6292,10 @@ static int action_coreshowchannels(struct mansession *s, const struct message *m
                        "\r\n",
                        idText,
                        ast_str_buffer(built),
-                       cs->appl,
-                       cs->data,
+                       cs->dialplan->appl,
+                       cs->dialplan->data,
                        durbuf,
-                       cs->bridgeid);
+                       cs->bridge->id);
 
                numchans++;
 
@@ -7639,7 +7634,8 @@ static void xml_translate(struct ast_str **out, char *in, struct ast_variable *g
                        if (xml) {
                                ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
                        }
-                       vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn);
+                       vco = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 37,
+                               variable_count_hash_fn, NULL, variable_count_cmp_fn);
                        inobj = 1;
                }
 
@@ -9067,7 +9063,7 @@ static int __init_manager(int reload, int by_external_config)
 #endif
 
                /* If you have a NULL hash fn, you only need a single bucket */
-               sessions = ao2_container_alloc(1, NULL, mansession_cmp_fn);
+               sessions = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, mansession_cmp_fn);
                if (!sessions) {
                        return -1;
                }
@@ -9323,8 +9319,8 @@ static int __init_manager(int reload, int by_external_config)
                        /* Default allowmultiplelogin from [general] */
                        user->allowmultiplelogin = allowmultiplelogin;
                        user->writetimeout = 100;
-                       user->whitefilters = ao2_container_alloc(1, NULL, NULL);
-                       user->blackfilters = ao2_container_alloc(1, NULL, NULL);
+                       user->whitefilters = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
+                       user->blackfilters = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, NULL);
                        if (!user->whitefilters || !user->blackfilters) {
                                manager_free_user(user);
                                break;
index b7059f4..4f2cb35 100644 (file)
@@ -528,18 +528,15 @@ static int send_bridge_info_item_cb(void *obj, void *arg, void *data, int flags)
        char *uniqueid = obj;
        struct mansession *s = arg;
        struct bridge_list_data *list_data = data;
-       RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-       struct ast_channel_snapshot *snapshot;
+       RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
        RAII_VAR(struct ast_str *, channel_text, NULL, ast_free);
 
-       msg = stasis_cache_get(ast_channel_cache(),
-               ast_channel_snapshot_type(), uniqueid);
-       if (!msg) {
+       snapshot = ast_channel_snapshot_get_latest(uniqueid);
+       if (!snapshot) {
                return 0;
        }
 
-       snapshot = stasis_message_data(msg);
-       if (snapshot->tech_properties & AST_CHAN_TP_INTERNAL) {
+       if (snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL) {
                return 0;
        }
 
index ac09d42..edbc770 100644 (file)
@@ -493,7 +493,7 @@ struct ast_str *ast_manager_build_channel_state_string_prefix(
        char *connected_name;
        int res;
 
-       if (snapshot->tech_properties & AST_CHAN_TP_INTERNAL) {
+       if (snapshot->base->tech_properties & AST_CHAN_TP_INTERNAL) {
                return NULL;
        }
 
@@ -502,8 +502,8 @@ struct ast_str *ast_manager_build_channel_state_string_prefix(
                return NULL;
        }
 
-       caller_name = ast_escape_c_alloc(snapshot->caller_name);
-       connected_name = ast_escape_c_alloc(snapshot->connected_name);
+       caller_name = ast_escape_c_alloc(snapshot->caller->name);
+       connected_name = ast_escape_c_alloc(snapshot->connected->name);
 
        res = ast_str_set(&out, 0,
                "%sChannel: %s\r\n"
@@ -520,20 +520,20 @@ struct ast_str *ast_manager_build_channel_state_string_prefix(
                "%sPriority: %d\r\n"
                "%sUniqueid: %s\r\n"
                "%sLinkedid: %s\r\n",
-               prefix, snapshot->name,
+               prefix, snapshot->base->name,
                prefix, snapshot->state,
                prefix, ast_state2str(snapshot->state),
-               prefix, S_OR(snapshot->caller_number, "<unknown>"),
+               prefix, S_OR(snapshot->caller->number, "<unknown>"),
                prefix, S_OR(caller_name, "<unknown>"),
-               prefix, S_OR(snapshot->connected_number, "<unknown>"),
+               prefix, S_OR(snapshot->connected->number, "<unknown>"),
                prefix, S_OR(connected_name, "<unknown>"),
-               prefix, snapshot->language,
-               prefix, snapshot->accountcode,
-               prefix, snapshot->context,
-               prefix, snapshot->exten,
-               prefix, snapshot->priority,
-               prefix, snapshot->uniqueid,
-               prefix, snapshot->linkedid);
+               prefix, snapshot->base->language,
+               prefix, snapshot->base->accountcode,
+               prefix, snapshot->dialplan->context,
+               prefix, snapshot->dialplan->exten,
+               prefix, snapshot->dialplan->priority,
+               prefix, snapshot->base->uniqueid,
+               prefix, snapshot->peer->linkedid);
 
        ast_free(caller_name);
        ast_free(connected_name);
@@ -576,11 +576,6 @@ static struct ast_manager_event_blob *channel_state_change(
 {
        int is_hungup, was_hungup;
 
-       if (!new_snapshot) {
-               /* Ignore cache clearing events; we'll see the hangup first */
-               return NULL;
-       }
-
        /* The Newchannel, Newstate and Hangup events are closely related, in
         * in that they are mutually exclusive, basically different flavors
         * of a new channel state event.
@@ -599,8 +594,8 @@ static struct ast_manager_event_blob *channel_state_change(
                        EVENT_FLAG_CALL, "Hangup",
                        "Cause: %d\r\n"
                        "Cause-txt: %s\r\n",
-                       new_snapshot->hangupcause,
-                       ast_cause2str(new_snapshot->hangupcause));
+                       new_snapshot->hangup->cause,
+                       ast_cause2str(new_snapshot->hangup->cause));
        }
 
        if (old_snapshot->state != new_snapshot->state) {
@@ -616,13 +611,8 @@ static struct ast_manager_event_blob *channel_newexten(
        struct ast_channel_snapshot *old_snapshot,
        struct ast_channel_snapshot *new_snapshot)
 {
-       /* No Newexten event on cache clear */
-       if (!new_snapshot) {
-               return NULL;
-       }
-
        /* Empty application is not valid for a Newexten event */
-       if (ast_strlen_zero(new_snapshot->appl)) {
+       if (ast_strlen_zero(new_snapshot->dialplan->appl)) {
                return NULL;
        }
 
@@ -642,9 +632,9 @@ static struct ast_manager_event_blob *channel_newexten(
                "Extension: %s\r\n"
                "Application: %s\r\n"
                "AppData: %s\r\n",
-               new_snapshot->exten,
-               new_snapshot->appl,
-               new_snapshot->data);
+               new_snapshot->dialplan->exten,
+               new_snapshot->dialplan->appl,
+               new_snapshot->dialplan->data);
 }
 
 static struct ast_manager_event_blob *channel_new_callerid(
@@ -654,8 +644,8 @@ static struct ast_manager_event_blob *channel_new_callerid(
        struct ast_manager_event_blob *res;
        char *callerid;
 
-       /* No NewCallerid event on cache clear or first event */
-       if (!old_snapshot || !new_snapshot) {
+       /* No NewCallerid event on first channel snapshot */
+       if (!old_snapshot) {
                return NULL;
        }
 
@@ -664,14 +654,14 @@ static struct ast_manager_event_blob *channel_new_callerid(
        }
 
        if (!(callerid = ast_escape_c_alloc(
-                     ast_describe_caller_presentation(new_snapshot->caller_pres)))) {
+                     ast_describe_caller_presentation(new_snapshot->caller->pres)))) {
                return NULL;
        }
 
        res = ast_manager_event_blob_create(
                EVENT_FLAG_CALL, "NewCallerid",
                "CID-CallingPres: %d (%s)\r\n",
-               new_snapshot->caller_pres,
+               new_snapshot->caller->pres,
                callerid);
 
        ast_free(callerid);
@@ -682,8 +672,8 @@ static struct ast_manager_event_blob *channel_new_connected_line(
        struct ast_channel_snapshot *old_snapshot,
        struct ast_channel_snapshot *new_snapshot)
 {
-       /* No NewConnectedLine event on cache clear or first event */
-       if (!old_snapshot || !new_snapshot) {
+       /* No NewConnectedLine event on first channel snapshot */
+       if (!old_snapshot) {
                return NULL;
        }
 
@@ -699,17 +689,17 @@ static struct ast_manager_event_blob *channel_new_accountcode(
        struct ast_channel_snapshot *old_snapshot,
        struct ast_channel_snapshot *new_snapshot)
 {
-       if (!old_snapshot || !new_snapshot) {
+       if (!old_snapshot) {
                return NULL;
        }
 
-       if (!strcmp(old_snapshot->accountcode, new_snapshot->accountcode)) {
+       if (!strcmp(old_snapshot->base->accountcode, new_snapshot->base->accountcode)) {
                return NULL;
        }
 
        return ast_manager_event_blob_create(
                EVENT_FLAG_CALL, "NewAccountCode",
-               "OldAccountCode: %s\r\n", old_snapshot->accountcode);
+               "OldAccountCode: %s\r\n", old_snapshot->base->accountcode);
 }
 
 channel_snapshot_monitor channel_monitors[] = {
@@ -724,21 +714,14 @@ static void channel_snapshot_update(void *data, struct stasis_subscription *sub,
                                    struct stasis_message *message)
 {
        RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
-       struct stasis_cache_update *update;
-       struct ast_channel_snapshot *old_snapshot;
-       struct ast_channel_snapshot *new_snapshot;
+       struct ast_channel_snapshot_update *update;
        size_t i;
 
        update = stasis_message_data(message);
 
-       ast_assert(ast_channel_snapshot_type() == update->type);
-
-       old_snapshot = stasis_message_data(update->old_snapshot);
-       new_snapshot = stasis_message_data(update->new_snapshot);
-
        for (i = 0; i < ARRAY_LEN(channel_monitors); ++i) {
                RAII_VAR(struct ast_manager_event_blob *, ev, NULL, ao2_cleanup);
-               ev = channel_monitors[i](old_snapshot, new_snapshot);
+               ev = channel_monitors[i](update->old_snapshot, update->new_snapshot);
 
                if (!ev) {
                        continue;
@@ -747,7 +730,7 @@ static void channel_snapshot_update(void *data, struct stasis_subscription *sub,
                /* If we haven't already, build the channel event string */
                if (!channel_event_string) {
                        channel_event_string =
-                               ast_manager_build_channel_state_string(new_snapshot);
+                               ast_manager_build_channel_state_string(update->new_snapshot);
                        if (!channel_event_string) {
                                return;
                        }
@@ -1260,7 +1243,7 @@ int manager_channels_init(void)
        if (!message_router) {
                return -1;
        }
-       channel_topic = ast_channel_topic_all_cached();
+       channel_topic = ast_channel_topic_all();
        if (!channel_topic) {
                return -1;
        }
@@ -1272,7 +1255,7 @@ int manager_channels_init(void)
 
        ast_register_cleanup(manager_channels_shutdown);
 
-       ret |= stasis_message_router_add_cache_update(message_router,
+       ret |= stasis_message_router_add(message_router,
                ast_channel_snapshot_type(), channel_snapshot_update, NULL);
 
        ret |= stasis_message_router_add(message_router,
index bfaa580..2d1bc6b 100644 (file)
@@ -121,7 +121,8 @@ static struct media_info *media_info_alloc(const char *name)
 
        memcpy(info->name, name, name_sz);
 
-       info->variants = ao2_container_alloc(VARIANT_BUCKETS, media_variant_hash, media_variant_cmp);
+       info->variants = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               VARIANT_BUCKETS, media_variant_hash, NULL, media_variant_cmp);
        if (!info->variants) {
                ao2_ref(info, -1);
 
@@ -169,7 +170,8 @@ struct ast_media_index *ast_media_index_create(const char *base_dir)
 
        memcpy(index->base_dir, base_dir, base_dir_sz);
 
-       index->index = ao2_container_alloc(INDEX_BUCKETS, media_info_hash, media_info_cmp);
+       index->index = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, INDEX_BUCKETS,
+               media_info_hash, NULL, media_info_cmp);
        if (!index->index) {
                ao2_ref(index, -1);
 
index b7d14f1..4874162 100644 (file)
@@ -367,12 +367,6 @@ static void msg_ds_destroy(void *data)
        ao2_ref(msg, -1);
 }
 
-static int msg_data_hash_fn(const void *obj, const int flags)
-{
-       const struct msg_data *data = obj;
-       return ast_str_case_hash(data->name);
-}
-
 static int msg_data_cmp_fn(void *obj, void *arg, int flags)
 {
        const struct msg_data *one = obj, *two = arg;
@@ -406,7 +400,9 @@ struct ast_msg *ast_msg_alloc(void)
                return NULL;
        }
 
-       if (!(msg->vars = ao2_container_alloc(1, msg_data_hash_fn, msg_data_cmp_fn))) {
+       msg->vars = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               NULL, msg_data_cmp_fn);
+       if (!msg->vars) {
                ao2_ref(msg, -1);
                return NULL;
        }
index 8cf09c2..8e9da3a 100644 (file)
@@ -131,7 +131,9 @@ static void *named_acl_config_alloc(void)
                return NULL;
        }
 
-       if (!(cfg->named_acl_list = ao2_container_alloc(37, named_acl_hash_fn, named_acl_cmp_fn))) {
+       cfg->named_acl_list = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 37,
+               named_acl_hash_fn, NULL, named_acl_cmp_fn);
+       if (!cfg->named_acl_list) {
                goto error;
        }
 
index 0a23735..9e19f35 100644 (file)
@@ -3953,7 +3953,7 @@ static int ast_add_hint(struct ast_exten *e)
        AST_VECTOR_INIT(&hint_new->devices, 8);
 
        /* Initialize new hint. */
-       hint_new->callbacks = ao2_container_alloc(1, NULL, hint_id_cmp);
+       hint_new->callbacks = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, hint_id_cmp);
        if (!hint_new->callbacks) {
                ao2_ref(hint_new, -1);
                return -1;
@@ -8912,11 +8912,13 @@ static void print_statecbs_key(void *v_obj, void *where, ao2_prnt_fn *prnt)
 
 int ast_pbx_init(void)
 {
-       hints = ao2_container_alloc(HASH_EXTENHINT_SIZE, hint_hash, hint_cmp);
+       hints = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               HASH_EXTENHINT_SIZE, hint_hash, NULL, hint_cmp);
        if (hints) {
                ao2_container_register("hints", hints, print_hints_key);
        }
-       hintdevices = ao2_container_alloc(HASH_EXTENHINT_SIZE, hintdevice_hash_cb, hintdevice_cmp_multiple);
+       hintdevices = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               HASH_EXTENHINT_SIZE, hintdevice_hash_cb, NULL, hintdevice_cmp_multiple);
        if (hintdevices) {
                ao2_container_register("hintdevices", hintdevices, print_hintdevices_key);
        }
@@ -8926,7 +8928,7 @@ int ast_pbx_init(void)
        if (autohints) {
                ao2_container_register("autohints", autohints, print_autohint_key);
        }
-       statecbs = ao2_container_alloc(1, NULL, statecbs_cmp);
+       statecbs = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL, statecbs_cmp);
        if (statecbs) {
                ao2_container_register("statecbs", statecbs, print_statecbs_key);
        }
index 417caaf..0c60b13 100644 (file)
@@ -1284,8 +1284,8 @@ struct stasis_topic_pool *stasis_topic_pool_create(struct stasis_topic *pooled_t
                return NULL;
        }
 
-       pool->pool_container = ao2_container_alloc(TOPIC_POOL_BUCKETS,
-               topic_pool_entry_hash, topic_pool_entry_cmp);
+       pool->pool_container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               TOPIC_POOL_BUCKETS, topic_pool_entry_hash, NULL, topic_pool_entry_cmp);
        if (!pool->pool_container) {
                ao2_cleanup(pool);
                return NULL;
index 59b9685..42bf6bc 100644 (file)
@@ -1069,7 +1069,7 @@ static struct ast_manager_event_blob *attended_transfer_to_ami(struct stasis_mes
        case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
                ast_str_append(&variable_data, 0, "DestType: Threeway\r\n");
                ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.threeway.bridge_snapshot->uniqueid);
-               ast_str_append(&variable_data, 0, "DestTransfererChannel: %s\r\n", transfer_msg->dest.threeway.channel_snapshot->name);
+               ast_str_append(&variable_data, 0, "DestTransfererChannel: %s\r\n", transfer_msg->dest.threeway.channel_snapshot->base->name);
                break;
        case AST_ATTENDED_TRANSFER_DEST_FAIL:
                ast_str_append(&variable_data, 0, "DestType: Fail\r\n");
@@ -1189,7 +1189,7 @@ int ast_attended_transfer_message_add_threeway(struct ast_attended_transfer_mess
 {
        transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_THREEWAY;
 
-       if (!strcmp(ast_channel_uniqueid(survivor_channel), transfer_msg->to_transferee.channel_snapshot->uniqueid)) {
+       if (!strcmp(ast_channel_uniqueid(survivor_channel), transfer_msg->to_transferee.channel_snapshot->base->uniqueid)) {
                transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transferee.channel_snapshot;
        } else {
                transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transfer_target.channel_snapshot;
index 8041c8e..d39fb08 100644 (file)
@@ -36,7 +36,6 @@
 #include "asterisk/bridge.h"
 #include "asterisk/translate.h"
 #include "asterisk/stasis.h"
-#include "asterisk/stasis_cache_pattern.h"
 #include "asterisk/stasis_channels.h"
 #include "asterisk/dial.h"
 #include "asterisk/linkedlists.h"
 
 #define NUM_MULTI_CHANNEL_BLOB_BUCKETS 7
 
-static struct stasis_cp_all *channel_cache_all;
-static struct stasis_cache *channel_cache_by_name;
-static struct stasis_caching_topic *channel_by_name_topic;
+static struct stasis_topic *channel_topic_all;
+static struct ao2_container *channel_cache;
+static struct ao2_container *channel_cache_by_name;
 
-struct stasis_cp_all *ast_channel_cache_all(void)
+struct ao2_container *ast_channel_cache_all(void)
 {
-       return channel_cache_all;
-}
-
-struct stasis_cache *ast_channel_cache(void)
-{
-       return stasis_cp_all_cache(channel_cache_all);
+       return ao2_bump(channel_cache);
 }
 
 struct stasis_topic *ast_channel_topic_all(void)
 {
-       return stasis_cp_all_topic(channel_cache_all);
+       return channel_topic_all;
 }
 
-struct stasis_topic *ast_channel_topic_all_cached(void)
+struct ao2_container *ast_channel_cache_by_name(void)
 {
-       return stasis_cp_all_topic_cached(channel_cache_all);
+       return ao2_bump(channel_cache_by_name);
 }
 
-struct stasis_cache *ast_channel_cache_by_name(void)
+/*!
+ * \internal
+ * \brief Hash function for \ref ast_channel_snapshot objects
+ */
+static int channel_snapshot_hash_cb(const void *obj, const int flags)
 {
-       return channel_cache_by_name;
-}
+       const struct ast_channel_snapshot *object = obj;
+       const char *key;
 
-static const char *channel_snapshot_get_id(struct stasis_message *message)
-{
-       struct ast_channel_snapshot *snapshot;
-       if (ast_channel_snapshot_type() != stasis_message_type(message)) {
-               return NULL;
+       switch (flags & OBJ_SEARCH_MASK) {
+       case OBJ_SEARCH_KEY:
+               key = obj;
+               break;
+       case OBJ_SEARCH_OBJECT:
+               key = object->base->name;
+               break;
+       default:
+               ast_assert(0);
+               return 0;
        }
-       snapshot = stasis_message_data(message);
-       return snapshot->uniqueid;
+       return ast_str_case_hash(key);
 }
 
-static const char *channel_snapshot_get_name(struct stasis_message *message)
+/*!
+ * \internal
+ * \brief Comparison function for \ref ast_channel_snapshot objects
+ */
+static int channel_snapshot_cmp_cb(void *obj, void *arg, int flags)
 {
-       struct ast_channel_snapshot *snapshot;
-       if (ast_channel_snapshot_type() != stasis_message_type(message)) {
-               return NULL;
+       const struct ast_channel_snapshot *object_left = obj;
+       const struct ast_channel_snapshot *object_right = arg;
+       const char *right_key = arg;
+       int cmp;
+
+       switch (flags & OBJ_SEARCH_MASK) {
+       case OBJ_SEARCH_OBJECT:
+               right_key = object_right->base->name;
+       case OBJ_SEARCH_KEY:
+               cmp = strcasecmp(object_left->base->name, right_key);
+               break;
+       case OBJ_SEARCH_PARTIAL_KEY:
+               cmp = strncasecmp(object_left->base->name, right_key, strlen(right_key));
+               break;
+       default:
+               cmp = 0;
+               break;
        }
-       snapshot = stasis_message_data(message);
-       return snapshot->name;
+       if (cmp) {
+               return 0;
+       }
+       return CMP_MATCH;
 }
 
 /*!
  * \internal
- * \brief Hash function for \ref ast_channel_snapshot objects
+ * \brief Hash function (using uniqueid) for \ref ast_channel_snapshot objects
  */
-static int channel_snapshot_hash_cb(const void *obj, const int flags)
+static int channel_snapshot_uniqueid_hash_cb(const void *obj, const int flags)
 {
        const struct ast_channel_snapshot *object = obj;
        const char *key;
@@ -180,7 +202,7 @@ static int channel_snapshot_hash_cb(const void *obj, const int flags)
                key = obj;
                break;
        case OBJ_SEARCH_OBJECT:
-               key = object->name;
+               key = object->base->uniqueid;
                break;
        default:
                ast_assert(0);
@@ -191,9 +213,9 @@ static int channel_snapshot_hash_cb(const void *obj, const int flags)
 
 /*!
  * \internal
- * \brief Comparison function for \ref ast_channel_snapshot objects
+ * \brief Comparison function (using uniqueid) for \ref ast_channel_snapshot objects
  */
-static int channel_snapshot_cmp_cb(void *obj, void *arg, int flags)
+static int channel_snapshot_uniqueid_cmp_cb(void *obj, void *arg, int flags)
 {
        const struct ast_channel_snapshot *object_left = obj;
        const struct ast_channel_snapshot *object_right = arg;
@@ -202,12 +224,12 @@ static int channel_snapshot_cmp_cb(void *obj, void *arg, int flags)
 
        switch (flags & OBJ_SEARCH_MASK) {
        case OBJ_SEARCH_OBJECT:
-               right_key = object_right->name;
+               right_key = object_right->base->uniqueid;
        case OBJ_SEARCH_KEY:
-               cmp = strcasecmp(object_left->name, right_key);
+               cmp = strcasecmp(object_left->base->uniqueid, right_key);
                break;
        case OBJ_SEARCH_PARTIAL_KEY:
-               cmp = strncasecmp(object_left->name, right_key, strlen(right_key));
+               cmp = strncasecmp(object_left->base->uniqueid, right_key, strlen(right_key));
                break;
        default:
                cmp = 0;
@@ -223,92 +245,344 @@ static void channel_snapshot_dtor(void *obj)
 {
        struct ast_channel_snapshot *snapshot = obj;
 
-       ast_string_field_free_memory(snapshot);
+       ao2_cleanup(snapshot->base);
+       ao2_cleanup(snapshot->peer);
+       ao2_cleanup(snapshot->caller);
+       ao2_cleanup(snapshot->connected);
+       ao2_cleanup(snapshot->bridge);
+       ao2_cleanup(snapshot->dialplan);
+       ao2_cleanup(snapshot->hangup);
        ao2_cleanup(snapshot->manager_vars);
        ao2_cleanup(snapshot->ari_vars);
 }
 
-struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan)
+static void channel_snapshot_base_dtor(void *obj)
 {
-       struct ast_channel_snapshot *snapshot;
-       struct ast_bridge *bridge;
+       struct ast_channel_snapshot_base *snapshot = obj;
 
-       /* no snapshots for dummy channels */
-       if (!ast_channel_tech(chan)) {
+       ast_string_field_free_memory(snapshot);
+}
+
+static struct ast_channel_snapshot_base *channel_snapshot_base_create(struct ast_channel *chan)
+{
+       struct ast_channel_snapshot_base *snapshot;
+
+       snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_base_dtor,
+               AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!snapshot) {
                return NULL;
        }
 
-       snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_dtor,
-               AO2_ALLOC_OPT_LOCK_NOLOCK);
-       if (!snapshot || ast_string_field_init(snapshot, 1024)) {
-               ao2_cleanup(snapshot);
+       if (ast_string_field_init(snapshot, 256)) {
+               ao2_ref(snapshot, -1);
                return NULL;
        }
 
        ast_string_field_set(snapshot, name, ast_channel_name(chan));
        ast_string_field_set(snapshot, type, ast_channel_tech(chan)->type);
        ast_string_field_set(snapshot, accountcode, ast_channel_accountcode(chan));
-       ast_string_field_set(snapshot, peeraccount, ast_channel_peeraccount(chan));
        ast_string_field_set(snapshot, userfield, ast_channel_userfield(chan));
        ast_string_field_set(snapshot, uniqueid, ast_channel_uniqueid(chan));
-       ast_string_field_set(snapshot, linkedid, ast_channel_linkedid(chan));
-       ast_string_field_set(snapshot, hangupsource, ast_channel_hangupsource(chan));
-       if (ast_channel_appl(chan)) {
-               ast_string_field_set(snapshot, appl, ast_channel_appl(chan));
+       ast_string_field_set(snapshot, language, ast_channel_language(chan));
+
+       snapshot->creationtime = ast_channel_creationtime(chan);
+       snapshot->tech_properties = ast_channel_tech(chan)->properties;
+
+       return snapshot;
+}
+
+static struct ast_channel_snapshot_peer *channel_snapshot_peer_create(struct ast_channel *chan)
+{
+       const char *linkedid = S_OR(ast_channel_linkedid(chan), "");
+       const char *peeraccount = S_OR(ast_channel_peeraccount(chan), "");
+       size_t linkedid_len = strlen(linkedid) + 1;
+       size_t peeraccount_len = strlen(peeraccount) + 1;
+       struct ast_channel_snapshot_peer *snapshot;
+
+       snapshot = ao2_alloc_options(sizeof(*snapshot) + linkedid_len + peeraccount_len, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!snapshot) {
+               return NULL;
        }
-       if (ast_channel_data(chan)) {
-               ast_string_field_set(snapshot, data, ast_channel_data(chan));
+
+       strcpy(snapshot->account, peeraccount); /* Safe */
+       snapshot->linkedid = snapshot->account + peeraccount_len;
+       strcpy(snapshot->linkedid, linkedid); /* Safe */
+
+       return snapshot;
+}
+
+static void channel_snapshot_caller_dtor(void *obj)
+{
+       struct ast_channel_snapshot_caller *snapshot = obj;
+
+       ast_string_field_free_memory(snapshot);
+}
+
+static struct ast_channel_snapshot_caller *channel_snapshot_caller_create(struct ast_channel *chan)
+{
+       struct ast_channel_snapshot_caller *snapshot;
+
+       snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_caller_dtor,
+               AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!snapshot) {
+               return NULL;
+       }
+
+       if (ast_string_field_init(snapshot, 256)) {
+               ao2_ref(snapshot, -1);
+               return NULL;
        }
-       ast_string_field_set(snapshot, context, ast_channel_context(chan));
-       ast_string_field_set(snapshot, exten, ast_channel_exten(chan));
 
-       ast_string_field_set(snapshot, caller_name,
+       ast_string_field_set(snapshot, name,
                S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""));
-       ast_string_field_set(snapshot, caller_number,
+       ast_string_field_set(snapshot, number,
                S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""));
-       ast_string_field_set(snapshot, caller_subaddr,
+       ast_string_field_set(snapshot, subaddr,
                S_COR(ast_channel_caller(chan)->id.subaddress.valid, ast_channel_caller(chan)->id.subaddress.str, ""));
-       ast_string_field_set(snapshot, caller_ani,
+       ast_string_field_set(snapshot, ani,
                S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""));
 
-       ast_string_field_set(snapshot, caller_rdnis,
+       ast_string_field_set(snapshot, rdnis,
                S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""));
 
-       ast_string_field_set(snapshot, caller_dnid,
+       ast_string_field_set(snapshot, dnid,
                S_OR(ast_channel_dialed(chan)->number.str, ""));
        ast_string_field_set(snapshot, dialed_subaddr,
                S_COR(ast_channel_dialed(chan)->subaddress.valid, ast_channel_dialed(chan)->subaddress.str, ""));
 
-       ast_string_field_set(snapshot, connected_name,
-               S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, ""));
-       ast_string_field_set(snapshot, connected_number,
-               S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, ""));
+       snapshot->pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
 
-       ast_string_field_set(snapshot, language, ast_channel_language(chan));
+       return snapshot;
+}
+
+static struct ast_channel_snapshot_connected *channel_snapshot_connected_create(struct ast_channel *chan)
+{
+       const char *name = S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, "");
+       const char *number = S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, "");
+       size_t name_len = strlen(name) + 1;
+       size_t number_len = strlen(number) + 1;
+       struct ast_channel_snapshot_connected *snapshot;
+
+       snapshot = ao2_alloc_options(sizeof(*snapshot) + name_len + number_len, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!snapshot) {
+               return NULL;
+       }
+
+       strcpy(snapshot->name, name); /* Safe */
+       snapshot->number = snapshot->name + name_len;
+       strcpy(snapshot->number, number); /* Safe */
+
+       return snapshot;
+}
+
+static struct ast_channel_snapshot_bridge *channel_snapshot_bridge_create(struct ast_channel *chan)
+{
+       const char *uniqueid = "";
+       struct ast_bridge *bridge;
+       struct ast_channel_snapshot_bridge *snapshot;
+
+       bridge = ast_channel_get_bridge(chan);
+       if (bridge && !ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
+               uniqueid = bridge->uniqueid;
+       }
+       ao2_cleanup(bridge);
+
+       snapshot = ao2_alloc_options(sizeof(*snapshot) + strlen(uniqueid) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!snapshot) {
+               return NULL;
+       }
+
+       strcpy(snapshot->id, uniqueid); /* Safe */
+
+       return snapshot;
+}
+
+static void channel_snapshot_dialplan_dtor(void *obj)
+{
+       struct ast_channel_snapshot_dialplan *snapshot = obj;
+
+       ast_string_field_free_memory(snapshot);
+}
+
+static struct ast_channel_snapshot_dialplan *channel_snapshot_dialplan_create(struct ast_channel *chan)
+{
+       struct ast_channel_snapshot_dialplan *snapshot;
+
+       snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_dialplan_dtor,
+               AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!snapshot) {
+               return NULL;
+       }
+
+       if (ast_string_field_init(snapshot, 256)) {
+               ao2_ref(snapshot, -1);
+               return NULL;
+       }
+
+       if (ast_channel_appl(chan)) {
+               ast_string_field_set(snapshot, appl, ast_channel_appl(chan));
+       }
+       if (ast_channel_data(chan)) {
+               ast_string_field_set(snapshot, data, ast_channel_data(chan));
+       }
+       ast_string_field_set(snapshot, context, ast_channel_context(chan));
+       ast_string_field_set(snapshot, exten, ast_channel_exten(chan));
+       snapshot->priority = ast_channel_priority(chan);
+
+       return snapshot;
+}
 
-       if ((bridge = ast_channel_get_bridge(chan))) {
-               if (!ast_test_flag(&bridge->feature_flags, AST_BRIDGE_FLAG_INVISIBLE)) {
-                       ast_string_field_set(snapshot, bridgeid, bridge->uniqueid);
+static struct ast_channel_snapshot_hangup *channel_snapshot_hangup_create(struct ast_channel *chan)
+{
+       const char *hangupsource = S_OR(ast_channel_hangupsource(chan), "");
+       struct ast_channel_snapshot_hangup *snapshot;
+
+       snapshot = ao2_alloc_options(sizeof(*snapshot) + strlen(hangupsource) + 1, NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!snapshot) {
+               return NULL;
+       }
+
+       snapshot->cause = ast_channel_hangupcause(chan);
+       strcpy(snapshot->source, hangupsource); /* Safe */
+
+       return snapshot;
+}
+
+struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan)
+{
+       struct ast_channel_snapshot *old_snapshot;
+       struct ast_channel_snapshot *snapshot;
+
+       /* no snapshots for dummy channels */
+       if (!ast_channel_tech(chan)) {
+               return NULL;
+       }
+
+       snapshot = ao2_alloc_options(sizeof(*snapshot), channel_snapshot_dtor,
+               AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!snapshot) {
+               return NULL;
+       }
+
+       old_snapshot = ast_channel_snapshot(chan);
+
+       /* Channels automatically have all segments invalidated on them initially so a check for an old
+        * snapshot existing before usage is not done here, as it can not happen. If the stored snapshot
+        * on the channel is updated as a result of this then all segments marked as invalidated will be
+        * cleared.
+        */
+       if (ast_test_flag(ast_channel_snapshot_segment_flags(chan), AST_CHANNEL_SNAPSHOT_INVALIDATE_BASE)) {
+               /* The base information has changed so update our snapshot */
+               snapshot->base = channel_snapshot_base_create(chan);
+               if (!snapshot->base) {
+                       ao2_ref(snapshot, -1);
+                       return NULL;
                }
-               ao2_cleanup(bridge);
+       } else {
+               snapshot->base = ao2_bump(old_snapshot->base);
+       }
+
+       if (ast_test_flag(ast_channel_snapshot_segment_flags(chan), AST_CHANNEL_SNAPSHOT_INVALIDATE_PEER)) {
+               /* The peer information has changed so update our snapshot */
+               snapshot->peer = channel_snapshot_peer_create(chan);
+               if (!snapshot->peer) {
+                       ao2_ref(snapshot, -1);
+                       return NULL;
+               }
+       } else {
+               snapshot->peer = ao2_bump(old_snapshot->peer);
+       }
+
+       /* Unfortunately both caller and connected information do not have an enforced contract with
+        * the channel API. This has allowed consumers to directly get the caller or connected structure
+        * and manipulate it. Until such time as there is an enforced contract (which is being tracked under
+        * ASTERISK-28164) they are each regenerated every time a channel snapshot is created.
+        */
+       snapshot->caller = channel_snapshot_caller_create(chan);
+       if (!snapshot->caller) {
+               ao2_ref(snapshot, -1);
+               return NULL;
+       }
+
+       snapshot->connected = channel_snapshot_connected_create(chan);
+       if (!snapshot->connected) {
+               ao2_ref(snapshot, -1);
+               return NULL;
+       }
+
+       if (ast_test_flag(ast_channel_snapshot_segment_flags(chan), AST_CHANNEL_SNAPSHOT_INVALIDATE_BRIDGE)) {
+               /* The bridge has changed so update our snapshot */
+               snapshot->bridge = channel_snapshot_bridge_create(chan);
+               if (!snapshot->bridge) {
+                       ao2_ref(snapshot, -1);
+                       return NULL;
+               }
+       } else {
+               snapshot->bridge = ao2_bump(old_snapshot->bridge);
+       }
+
+       if (ast_test_flag(ast_channel_snapshot_segment_flags(chan), AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN)) {
+               /* The dialplan information has changed so update our snapshot */
+               snapshot->dialplan = channel_snapshot_dialplan_create(chan);
+               if (!snapshot->dialplan) {
+                       ao2_ref(snapshot, -1);
+                       return NULL;
+               }
+       } else {
+               snapshot->dialplan = ao2_bump(old_snapshot->dialplan);
+       }
+
+       if (ast_test_flag(ast_channel_snapshot_segment_flags(chan), AST_CHANNEL_SNAPSHOT_INVALIDATE_HANGUP)) {
+               /* The hangup information has changed so update our snapshot */
+               snapshot->hangup = channel_snapshot_hangup_create(chan);
+               if (!snapshot->hangup) {
+                       ao2_ref(snapshot, -1);
+                       return NULL;
+               }
+       } else {
+               snapshot->hangup = ao2_bump(old_snapshot->hangup);
        }
 
-       snapshot->creationtime = ast_channel_creationtime(chan);
        snapshot->state = ast_channel_state(chan);
-       snapshot->priority = ast_channel_priority(chan);
        snapshot->amaflags = ast_channel_amaflags(chan);
-       snapshot->hangupcause = ast_channel_hangupcause(chan);
        ast_copy_flags(&snapshot->flags, ast_channel_flags(chan), 0xFFFFFFFF);
-       snapshot->caller_pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
        ast_set_flag(&snapshot->softhangup_flags, ast_channel_softhangup_internal_flag(chan));
 
+       /* These have to be recreated as they may have changed, unfortunately */
        snapshot->manager_vars = ast_channel_get_manager_vars(chan);
        snapshot->ari_vars = ast_channel_get_ari_vars(chan);
-       snapshot->tech_properties = ast_channel_tech(chan)->properties;
 
        return snapshot;
 }
 
+static void channel_snapshot_update_dtor(void *obj)
+{
+       struct ast_channel_snapshot_update *update = obj;
+
+       ao2_cleanup(update->old_snapshot);
+       ao2_cleanup(update->new_snapshot);
+}
+
+static struct ast_channel_snapshot_update *channel_snapshot_update_create(struct ast_channel *chan)
+{
+       struct ast_channel_snapshot_update *update;
+
+       update = ao2_alloc_options(sizeof(*update), channel_snapshot_update_dtor,
+               AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!update) {
+               return NULL;
+       }
+
+       update->old_snapshot = ao2_bump(ast_channel_snapshot(chan));
+       update->new_snapshot = ast_channel_snapshot_create(chan);
+       if (!update->new_snapshot) {
+               ao2_ref(update, -1);
+               return NULL;
+       }
+
+       return update;
+}
+
 static void publish_message_for_channel_topics(struct stasis_message *message, struct ast_channel *chan)
 {
        if (chan) {
@@ -521,7 +795,7 @@ struct stasis_message *ast_channel_blob_create(struct ast_channel *chan,
                return NULL;
        }
 
-       snapshot = chan ? ast_channel_snapshot_create(chan) : NULL;
+       snapshot = chan ? ao2_bump(ast_channel_snapshot(chan)) : NULL;
        msg = create_channel_blob_message(snapshot, type, blob);
        ao2_cleanup(snapshot);
        return msg;
@@ -615,8 +889,8 @@ struct ast_multi_channel_blob *ast_multi_channel_blob_create(struct ast_json *bl
                return NULL;
        }
 
-       obj->channel_snapshots = ao2_container_alloc(NUM_MULTI_CHANNEL_BLOB_BUCKETS,
-               channel_role_hash_cb, channel_role_cmp_cb);
+       obj->channel_snapshots = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               NUM_MULTI_CHANNEL_BLOB_BUCKETS, channel_role_hash_cb, NULL, channel_role_cmp_cb);
        if (!obj->channel_snapshots) {
                ao2_ref(obj, -1);
                return NULL;
@@ -628,38 +902,48 @@ struct ast_multi_channel_blob *ast_multi_channel_blob_create(struct ast_json *bl
 
 struct ast_channel_snapshot *ast_channel_snapshot_get_latest(const char *uniqueid)
 {
-       struct stasis_message *message;
-       struct ast_channel_snapshot *snapshot;
-
        ast_assert(!ast_strlen_zero(uniqueid));
 
-       message = stasis_cache_get(ast_channel_cache(), ast_channel_snapshot_type(),
-               uniqueid);
-       if (!message) {
-               return NULL;
-       }
-
-       snapshot = ao2_bump(stasis_message_data(message));
-       ao2_ref(message, -1);
-       return snapshot;
+       return ao2_find(channel_cache, uniqueid, OBJ_SEARCH_KEY);
 }
 
 struct ast_channel_snapshot *ast_channel_snapshot_get_latest_by_name(const char *name)
 {
+       ast_assert(!ast_strlen_zero(name));
+
+       return ao2_find(channel_cache_by_name, name, OBJ_SEARCH_KEY);
+}
+
+void ast_channel_publish_final_snapshot(struct ast_channel *chan)
+{
+       struct ast_channel_snapshot_update *update;
        struct stasis_message *message;
-       struct ast_channel_snapshot *snapshot;
 
-       ast_assert(!ast_strlen_zero(name));
+       if (!ast_channel_snapshot_type()) {
+               return;
+       }
+
+       update = channel_snapshot_update_create(chan);
+       if (!update) {
+               return;
+       }
 
-       message = stasis_cache_get(ast_channel_cache_by_name(), ast_channel_snapshot_type(),
-               name);
+       message = stasis_message_create(ast_channel_snapshot_type(), update);
+       /* In the success path message holds a reference to update so it will be valid
+        * for the lifetime of this function until the end.
+        */
+       ao2_ref(update, -1);
        if (!message) {
-               return NULL;
+               return;
        }
 
-       snapshot = ao2_bump(stasis_message_data(message));
+       ao2_unlink(channel_cache, update->old_snapshot);
+       ao2_unlink(channel_cache_by_name, update->old_snapshot);
+
+       ast_channel_snapshot_set(chan, NULL);
+
+       stasis_publish(ast_channel_topic(chan), message);
        ao2_ref(message, -1);
-       return snapshot;
 }
 
 static void channel_role_snapshot_dtor(void *obj)
@@ -719,8 +1003,9 @@ struct ao2_container *ast_multi_channel_blob_get_channels(struct ast_multi_chann
                return NULL;
        }
 
-       ret_container = ao2_container_alloc(NUM_MULTI_CHANNEL_BLOB_BUCKETS,
-               channel_snapshot_hash_cb, channel_snapshot_cmp_cb);
+       ret_container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               NUM_MULTI_CHANNEL_BLOB_BUCKETS,
+               channel_snapshot_hash_cb, NULL, channel_snapshot_cmp_cb);
        if (!ret_container) {
                return NULL;
        }
@@ -761,9 +1046,15 @@ void ast_channel_stage_snapshot_done(struct ast_channel *chan)
        ast_channel_publish_snapshot(chan);
 }
 
+void ast_channel_snapshot_invalidate_segment(struct ast_channel *chan,
+       enum ast_channel_snapshot_segment_invalidation segment)
+{
+       ast_set_flag(ast_channel_snapshot_segment_flags(chan), segment);
+}
+
 void ast_channel_publish_snapshot(struct ast_channel *chan)
 {
-       struct ast_channel_snapshot *snapshot;
+       struct ast_channel_snapshot_update *update;
        struct stasis_message *message;
 
        if (!ast_channel_snapshot_type()) {
@@ -774,17 +1065,53 @@ void ast_channel_publish_snapshot(struct ast_channel *chan)
                return;
        }
 
-       snapshot = ast_channel_snapshot_create(chan);
-       if (!snapshot) {
+       update = channel_snapshot_update_create(chan);
+       if (!update) {
+               return;
+       }
+
+       /* If an old snapshot exists and is the same as this newly created one don't bother
+        * raising a message as it hasn't changed.
+        */
+       if (update->old_snapshot && !memcmp(update->old_snapshot, update->new_snapshot, sizeof(struct ast_channel_snapshot))) {
+               ao2_ref(update, -1);
                return;
        }
 
-       message = stasis_message_create(ast_channel_snapshot_type(), snapshot);
-       ao2_ref(snapshot, -1);
+       message = stasis_message_create(ast_channel_snapshot_type(), update);
+       /* In the success path message holds a reference to update so it will be valid
+        * for the lifetime of this function until the end.
+        */
+       ao2_ref(update, -1);
        if (!message) {
                return;
        }
 
+       /* We lock these ourselves so that the update is atomic and there isn't time where a
+        * snapshot is not in the cache.
+        */
+       ao2_wrlock(channel_cache);
+       if (update->old_snapshot) {
+               ao2_unlink_flags(channel_cache, update->old_snapshot, OBJ_NOLOCK);
+       }
+       ao2_link_flags(channel_cache, update->new_snapshot, OBJ_NOLOCK);
+       ao2_unlock(channel_cache);
+
+       /* The same applies here. */
+       ao2_wrlock(channel_cache_by_name);
+       if (update->old_snapshot) {
+               ao2_unlink_flags(channel_cache_by_name, update->old_snapshot, OBJ_NOLOCK);
+       }
+       ao2_link_flags(channel_cache_by_name, update->new_snapshot, OBJ_NOLOCK);
+       ao2_unlock(channel_cache_by_name);
+
+       ast_channel_snapshot_set(chan, update->new_snapshot);
+
+       /* As this is now the new snapshot any existing invalidated segments have been
+        * created fresh and are up to date.
+        */
+       ast_clear_flag(ast_channel_snapshot_segment_flags(chan), AST_FLAGS_ALL);
+
        ast_assert(ast_channel_topic(chan) != NULL);
        stasis_publish(ast_channel_topic(chan), message);
        ao2_ref(message, -1);
@@ -840,13 +1167,8 @@ void ast_channel_publish_varset(struct ast_channel *chan, const char *name, cons
                ast_channel_publish_snapshot(chan);
        }
 
-       if (chan) {
-               ast_channel_publish_cached_blob(chan, ast_channel_varset_type(), blob);
-       } else {
-               /* This function is NULL safe for global variables */
-               ast_channel_publish_blob(NULL, ast_channel_varset_type(), blob);
-       }
-
+       /* This function is NULL safe for global variables */
+       ast_channel_publish_blob(chan, ast_channel_varset_type(), blob);
        ast_json_unref(blob);
 }
 
@@ -930,36 +1252,6 @@ static struct ast_manager_event_blob *agent_logoff_to_ami(struct stasis_message
        return ev;
 }
 
-void ast_publish_channel_state(struct ast_channel *chan)
-{
-       struct ast_channel_snapshot *snapshot;
-       struct stasis_message *message;
-
-       if (!ast_channel_snapshot_type()) {
-               return;
-       }
-
-       ast_assert(chan != NULL);
-       if (!chan) {
-               return;
-       }
-
-       snapshot = ast_channel_snapshot_create(chan);
-       if (!snapshot) {
-               return;
-       }
-
-       message = stasis_message_create(ast_channel_snapshot_type(), snapshot);
-       ao2_ref(snapshot, -1);
-       if (!message) {
-               return;
-       }
-
-       ast_assert(ast_channel_topic(chan) != NULL);
-       stasis_publish(ast_channel_topic(chan), message);
-       ao2_ref(message, -1);
-}
-
 struct ast_json *ast_channel_snapshot_to_json(
        const struct ast_channel_snapshot *snapshot,
        const struct stasis_message_sanitizer *sanitize)
@@ -979,20 +1271,20 @@ struct ast_json *ast_channel_snapshot_to_json(
                "  s: o, s: o, s: s,"
                "  s: o, s: o, s: s }",
                /* First line */
-               "id", snapshot->uniqueid,
-               "name", snapshot->name,
+               "id", snapshot->base->uniqueid,
+               "name", snapshot->base->name,
                "state", ast_state2str(snapshot->state),
                /* Second line */
                "caller", ast_json_name_number(
-                       snapshot->caller_name, snapshot->caller_number),
+                       snapshot->caller->name, snapshot->caller->number),
                "connected", ast_json_name_number(
-                       snapshot->connected_name, snapshot->connected_number),
-               "accountcode", snapshot->accountcode,
+                       snapshot->connected->name, snapshot->connected->number),
+               "accountcode", snapshot->base->accountcode,
                /* Third line */
                "dialplan", ast_json_dialplan_cep(
-                       snapshot->context, snapshot->exten, snapshot->priority),
-               "creationtime", ast_json_timeval(snapshot->creationtime, NULL),
-               "language", snapshot->language);
+                       snapshot->dialplan->context, snapshot->dialplan->exten, snapshot->dialplan->priority),
+               "creationtime", ast_json_timeval(snapshot->base->creationtime, NULL),
+               "language", snapshot->base->language);
 
        if (snapshot->ari_vars && !AST_LIST_EMPTY(snapshot->ari_vars)) {
                ast_json_object_set(json_chan, "channelvars", ast_json_channel_vars(snapshot->ari_vars));
@@ -1012,14 +1304,14 @@ int ast_channel_snapshot_cep_equal(
         * application is set. Since empty application is invalid, we treat
         * setting the application from nothing as a CEP change.
         */
-       if (ast_strlen_zero(old_snapshot->appl) &&
-           !ast_strlen_zero(new_snapshot->appl)) {
+       if (ast_strlen_zero(old_snapshot->dialplan->appl) &&
+           !ast_strlen_zero(new_snapshot->dialplan->appl)) {
                return 0;
        }
 
-       return old_snapshot->priority == new_snapshot->priority &&
-               strcmp(old_snapshot->context, new_snapshot->context) == 0 &&
-               strcmp(old_snapshot->exten, new_snapshot->exten) == 0;
+       return old_snapshot->dialplan->priority == new_snapshot->dialplan->priority &&
+               strcmp(old_snapshot->dialplan->context, new_snapshot->dialplan->context) == 0 &&
+               strcmp(old_snapshot->dialplan->exten, new_snapshot->dialplan->exten) == 0;
 }
 
 int ast_channel_snapshot_caller_id_equal(
@@ -1028,8 +1320,8 @@ int ast_channel_snapshot_caller_id_equal(
 {
        ast_assert(old_snapshot != NULL);
        ast_assert(new_snapshot != NULL);
-       return strcmp(old_snapshot->caller_number, new_snapshot->caller_number) == 0 &&
-               strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0;
+       return strcmp(old_snapshot->caller->number, new_snapshot->caller->number) == 0 &&
+               strcmp(old_snapshot->caller->name, new_snapshot->caller->name) == 0;
 }
 
 int ast_channel_snapshot_connected_line_equal(
@@ -1038,8 +1330,8 @@ int ast_channel_snapshot_connected_line_equal(
 {
        ast_assert(old_snapshot != NULL);
        ast_assert(new_snapshot != NULL);
-       return strcmp(old_snapshot->connected_number, new_snapshot->connected_number) == 0 &&
-               strcmp(old_snapshot->connected_name, new_snapshot->connected_name) == 0;
+       return strcmp(old_snapshot->connected->number, new_snapshot->connected->number) == 0 &&
+               strcmp(old_snapshot->connected->name, new_snapshot->connected->name) == 0;
 }
 
 static struct ast_json *channel_blob_to_json(
@@ -1331,12 +1623,12 @@ STASIS_MESSAGE_TYPE_DEFN(ast_channel_talking_stop,
 
 static void stasis_channels_cleanup(void)
 {
-       stasis_caching_unsubscribe_and_join(channel_by_name_topic);
-       channel_by_name_topic = NULL;
+       ao2_cleanup(channel_topic_all);
+       channel_topic_all = NULL;
+       ao2_cleanup(channel_cache);
+       channel_cache = NULL;
        ao2_cleanup(channel_cache_by_name);
        channel_cache_by_name = NULL;
-       ao2_cleanup(channel_cache_all);
-       channel_cache_all = NULL;
 
        STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_snapshot_type);
        STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dial_type);
@@ -1366,29 +1658,28 @@ int ast_stasis_channels_init(void)
 
        ast_register_cleanup(stasis_channels_cleanup);
 
-       channel_cache_all = stasis_cp_all_create("ast_channel_topic_all",
-               channel_snapshot_get_id);
-       if (!channel_cache_all) {
+       channel_topic_all = stasis_topic_create("ast_channel_topic_all");
+       if (!channel_topic_all) {
                return -1;
        }
-       res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_agent_login_type);
-       res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_agent_logoff_type);
 
-       channel_cache_by_name = stasis_cache_create(channel_snapshot_get_name);
-       if (!channel_cache_by_name) {
+       channel_cache = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_RWLOCK,
+               0, AST_NUM_CHANNEL_BUCKETS, channel_snapshot_uniqueid_hash_cb,
+               NULL, channel_snapshot_uniqueid_cmp_cb);
+       if (!channel_cache) {
                return -1;
        }
 
-       /* This should be initialized before the caching topic */
-       res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_snapshot_type);
-
-       channel_by_name_topic = stasis_caching_topic_create(
-               stasis_cp_all_topic(channel_cache_all),
-               channel_cache_by_name);
-       if (!channel_by_name_topic) {
+       channel_cache_by_name = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_RWLOCK,
+               0, AST_NUM_CHANNEL_BUCKETS, channel_snapshot_hash_cb,
+               NULL, channel_snapshot_cmp_cb);
+       if (!channel_cache_by_name) {
                return -1;
        }
 
+       res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_agent_login_type);
+       res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_agent_logoff_type);
+       res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_snapshot_type);
        res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_dial_type);
        res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_varset_type);
        res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_hangup_request_type);
index 68bd29c..30aeddb 100644 (file)
@@ -278,7 +278,9 @@ static void tps_shutdown(void)
 /* initialize the taskprocessor container and register CLI operations */
 int ast_tps_init(void)
 {
-       if (!(tps_singletons = ao2_container_alloc(TPS_MAX_BUCKETS, tps_hash_cb, tps_cmp_cb))) {
+       tps_singletons = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               TPS_MAX_BUCKETS, tps_hash_cb, NULL, tps_cmp_cb);
+       if (!tps_singletons) {
                ast_log(LOG_ERROR, "taskprocessor container failed to initialize!\n");
                return -1;
        }
index 7729930..2ab0936 100644 (file)
@@ -420,15 +420,18 @@ static struct ast_threadpool *threadpool_alloc(const char *name, const struct as
        if (!pool->control_tps) {
                return NULL;
        }
-       pool->active_threads = ao2_container_alloc(THREAD_BUCKETS, worker_thread_hash, worker_thread_cmp);
+       pool->active_threads = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               THREAD_BUCKETS, worker_thread_hash, NULL, worker_thread_cmp);
        if (!pool->active_threads) {
                return NULL;
        }
-       pool->idle_threads = ao2_container_alloc(THREAD_BUCKETS, worker_thread_hash, worker_thread_cmp);
+       pool->idle_threads = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               THREAD_BUCKETS, worker_thread_hash, NULL, worker_thread_cmp);
        if (!pool->idle_threads) {
                return NULL;
        }
-       pool->zombie_threads = ao2_container_alloc(THREAD_BUCKETS, worker_thread_hash, worker_thread_cmp);
+       pool->zombie_threads = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               THREAD_BUCKETS, worker_thread_hash, NULL, worker_thread_cmp);
        if (!pool->zombie_threads) {
                return NULL;
        }
index 43ae074..8b273f0 100644 (file)
@@ -2657,7 +2657,9 @@ struct ao2_container *ast_xmldoc_build_documentation(const char *type)
        struct documentation_tree *doctree;
        const char *name;
 
-       if (!(docs = ao2_container_alloc(127, ast_xml_doc_item_hash, ast_xml_doc_item_cmp))) {
+       docs = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 127,
+               ast_xml_doc_item_hash, NULL, ast_xml_doc_item_cmp);
+       if (!docs) {
                ast_log(AST_LOG_ERROR, "Failed to create container for xml document item instances\n");
                return NULL;
        }
index 29d2e08..970bb3c 100644 (file)
@@ -344,6 +344,11 @@ static int realtime_exec(struct ast_channel *chan, const char *context, const ch
                                                 term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)));
                                if (ast_channel_snapshot_type()) {
                                        ast_channel_lock(chan);
+                                       /* Force a new dialplan segment that will be unique to use so we can update it with the
+                                        * information we want. In the future when a channel snapshot is published this will
+                                        * occur again and unset this flag.
+                                        */
+                                       ast_channel_snapshot_invalidate_segment(chan, AST_CHANNEL_SNAPSHOT_INVALIDATE_DIALPLAN);
                                        snapshot = ast_channel_snapshot_create(chan);
                                        ast_channel_unlock(chan);
                                }
@@ -351,8 +356,8 @@ static int realtime_exec(struct ast_channel *chan, const char *context, const ch
                                        /* pbx_exec sets application name and data, but we don't want to log
                                         * every exec. Just update the snapshot here instead.
                                         */
-                                       ast_string_field_set(snapshot, appl, app);
-                                       ast_string_field_set(snapshot, data, !ast_strlen_zero(appdata) ? appdata : "(NULL)");
+                                       ast_string_field_set(snapshot->dialplan, appl, app);
+                                       ast_string_field_set(snapshot->dialplan, data, !ast_strlen_zero(appdata) ? appdata : "(NULL)");
                                        msg = stasis_message_create(ast_channel_snapshot_type(), snapshot);
                                        if (msg) {
                                                stasis_publish(ast_channel_topic(chan), msg);
@@ -401,7 +406,9 @@ static int unload_module(void)
 
 static int load_module(void)
 {
-       if (!(cache = ao2_container_alloc(573, cache_hash, cache_cmp))) {
+       cache = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 573,
+               cache_hash, NULL, cache_cmp);
+       if (!cache) {
                return AST_MODULE_LOAD_FAILURE;
        }
 
index e5fa41c..3c0eeb7 100644 (file)
@@ -377,7 +377,7 @@ static int ari_bridges_play_helper(const char **args_media,
                return -1;
        }
 
-       language = S_OR(args_lang, snapshot->language);
+       language = S_OR(args_lang, snapshot->base->language);
 
        playback = stasis_app_control_play_uri(control, args_media, args_media_count,
                language, bridge->uniqueid, STASIS_PLAYBACK_TARGET_BRIDGE, args_skipms,
index bca32f1..311358e 100644 (file)
@@ -170,8 +170,8 @@ void ast_ari_channels_continue_in_dialplan(
        }
 
        if (ast_strlen_zero(args->context)) {
-               context = snapshot->context;
-               exten = S_OR(args->extension, snapshot->exten);
+               context = snapshot->dialplan->context;
+               exten = S_OR(args->extension, snapshot->dialplan->exten);
        } else {
                context = args->context;
                exten = S_OR(args->extension, "s");
@@ -203,7 +203,7 @@ void ast_ari_channels_continue_in_dialplan(
                ipri = args->priority;
        } else if (ast_strlen_zero(args->context) && ast_strlen_zero(args->extension)) {
                /* Special case. No exten, context, or priority provided, then move on to the next priority */
-               ipri = snapshot->priority + 1;
+               ipri = snapshot->dialplan->priority + 1;
        } else {
                ipri = 1;
        }
@@ -263,10 +263,10 @@ void ast_ari_channels_redirect(struct ast_variable *headers,
                return;
        }
 
-       if (strncasecmp(chan_snapshot->type, tech, tech_len)) {
+       if (strncasecmp(chan_snapshot->base->type, tech, tech_len)) {
                ast_ari_response_error(response, 422, "Unprocessable Entity",
                        "Endpoint technology '%s' does not match channel technology '%s'",
-                       tech, chan_snapshot->type);
+                       tech, chan_snapshot->base->type);
                return;
        }
 
@@ -628,7 +628,7 @@ static void ari_channels_handle_play(
                return;
        }
 
-       language = S_OR(args_lang, snapshot->language);
+       language = S_OR(args_lang, snapshot->base->language);
 
        playback = stasis_app_control_play_uri(control, args_media, args_media_count, language,
                args_channel_id, STASIS_PLAYBACK_TARGET_CHANNEL, args_skipms, args_offsetms, args_playback_id);
@@ -833,32 +833,19 @@ void ast_ari_channels_get(struct ast_variable *headers,
        struct ast_ari_channels_get_args *args,
        struct ast_ari_response *response)
 {
-       RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-       struct stasis_cache *cache;
        struct ast_channel_snapshot *snapshot;
 
-       cache = ast_channel_cache();
-       if (!cache) {
-               ast_ari_response_error(
-                       response, 500, "Internal Server Error",
-                       "Message bus not initialized");
-               return;
-       }
-
-       msg = stasis_cache_get(cache, ast_channel_snapshot_type(),
-                                  args->channel_id);
-       if (!msg) {
+       snapshot = ast_channel_snapshot_get_latest(args->channel_id);
+       if (!snapshot) {
                ast_ari_response_error(
                        response, 404, "Not Found",
                        "Channel not found");
                return;
        }
 
-       snapshot = stasis_message_data(msg);
-       ast_assert(snapshot != NULL);
-
        ast_ari_response_ok(response,
                                ast_channel_snapshot_to_json(snapshot, NULL));
+       ao2_ref(snapshot, -1);
 }
 
 void ast_ari_channels_hangup(struct ast_variable *headers,
@@ -903,27 +890,13 @@ void ast_ari_channels_list(struct ast_variable *headers,
        struct ast_ari_channels_list_args *args,
        struct ast_ari_response *response)
 {
-       RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
        RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
        RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
        struct ao2_iterator i;
        void *obj;
        struct stasis_message_sanitizer *sanitize = stasis_app_get_sanitizer();
 
-       cache = ast_channel_cache();
-       if (!cache) {
-               ast_ari_response_error(
-                       response, 500, "Internal Server Error",
-                       "Message bus not initialized");
-               return;
-       }
-       ao2_ref(cache, +1);
-
-       snapshots = stasis_cache_dump(cache, ast_channel_snapshot_type());
-       if (!snapshots) {
-               ast_ari_response_alloc_failed(response);
-               return;
-       }
+       snapshots = ast_channel_cache_all();
 
        json = ast_json_array_create();
        if (!json) {
@@ -933,12 +906,12 @@ void ast_ari_channels_list(struct ast_variable *headers,
 
        i = ao2_iterator_init(snapshots, 0);
        while ((obj = ao2_iterator_next(&i))) {
-               RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
-               struct ast_channel_snapshot *snapshot = stasis_message_data(msg);
+               struct ast_channel_snapshot *snapshot = obj;
                int r;
 
                if (sanitize && sanitize->channel_snapshot
                        && sanitize->channel_snapshot(snapshot)) {
+                       ao2_ref(snapshot, -1);
                        continue;
                }
 
@@ -947,8 +920,10 @@ void ast_ari_channels_list(struct ast_variable *headers,
                if (r != 0) {
                        ast_ari_response_alloc_failed(response);
                        ao2_iterator_destroy(&i);
+                       ao2_ref(snapshot, -1);
                        return;
                }
+               ao2_ref(snapshot, -1);
        }
        ao2_iterator_destroy(&i);
 
index 5a8e898..5983f7b 100644 (file)
@@ -467,9 +467,8 @@ void ast_ari_websocket_events_event_websocket_dtor(void)
 int ast_ari_websocket_events_event_websocket_init(void)
 {
        /* Try to instantiate the registry */
-       event_session_registry = ao2_container_alloc(EVENT_SESSION_NUM_BUCKETS,
-                                                    event_session_hash,
-                                                    event_session_compare);
+       event_session_registry = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               EVENT_SESSION_NUM_BUCKETS, event_session_hash, NULL, event_session_compare);
        if (!event_session_registry) {
                /* This is bad, bad. */
                ast_log(LOG_WARNING,
index f9b3e85..46dbedf 100644 (file)
@@ -819,12 +819,12 @@ static void announce_to_dial(char *dial_string, char *announce_string, int parki
        snprintf(buf, sizeof(buf), "%d", parkingspace);
        oh.vars = ast_variable_new("_PARKEDAT", buf, "");
 
-       inherit_channel_vars_from_id(&oh, parkee_snapshot->uniqueid);
+       inherit_channel_vars_from_id(&oh, parkee_snapshot->base->uniqueid);
 
        dchan = __ast_request_and_dial(dial_tech, cap_slin, NULL, NULL, dial_string, 30000,
                &outstate,
-               parkee_snapshot->caller_number,
-               parkee_snapshot->caller_name,
+               parkee_snapshot->caller->number,
+               parkee_snapshot->caller->name,
                &oh);
 
        ast_variables_destroy(oh.vars);
@@ -877,7 +877,7 @@ static void park_announce_update_cb(void *data, struct stasis_subscription *sub,
                return;
        }
 
-       if (strcmp(payload->parkee->uniqueid, pa_data->parkee_uuid)) {
+       if (strcmp(payload->parkee->base->uniqueid, pa_data->parkee_uuid)) {
                /* We are only concerned with the parkee we are subscribed for. */
                return;
        }
index 1d3b9e4..d619471 100644 (file)
@@ -111,7 +111,7 @@ static void parker_parked_call_message_response(struct ast_parked_call_payload *
        RAII_VAR(struct ast_channel *, parker, NULL, ast_channel_cleanup);
        RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
 
-       if (strcmp(parkee_to_act_on, parkee_snapshot->uniqueid)) {
+       if (strcmp(parkee_to_act_on, parkee_snapshot->base->uniqueid)) {
                return;
        }
 
index 0931c1a..e322d7f 100644 (file)
@@ -3182,13 +3182,13 @@ static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, co
                ast_agi_send(agi->fd, chan, "200 result=%u\n", ast_channel_state(chan));
                return RESULT_SUCCESS;
        } else if (argc == 3) {
-               RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+               struct ast_channel_snapshot *snapshot;
 
                /* one argument: look for info on the specified channel */
-               if ((msg = stasis_cache_get(ast_channel_cache_by_name(), ast_channel_snapshot_type(), argv[2]))) {
-                       struct ast_channel_snapshot *snapshot = stasis_message_data(msg);
-
+               snapshot = ast_channel_snapshot_get_latest_by_name(argv[2]);
+               if (snapshot) {
                        ast_agi_send(agi->fd, chan, "200 result=%u\n", snapshot->state);
+                       ao2_ref(snapshot, -1);
                        return RESULT_SUCCESS;
                }
                /* if we get this far no channel name matched the argument given */
index c46307f..f629e3d 100644 (file)
@@ -415,7 +415,9 @@ static struct ast_calendar *build_calendar(struct ast_config *cfg, const char *c
                        return NULL;
                }
 
-               if (!(cal->events = ao2_container_alloc(CALENDAR_BUCKETS, event_hash_fn, event_cmp_fn))) {
+               cal->events = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+                       CALENDAR_BUCKETS, event_hash_fn, NULL, event_cmp_fn);
+               if (!cal->events) {
                        ast_log(LOG_ERROR, "Could not allocate events container for %s\n", cat);
                        cal = unref_calendar(cal);
                        return NULL;
@@ -686,7 +688,8 @@ struct ast_calendar_event *ast_calendar_event_alloc(struct ast_calendar *cal)
 
 struct ao2_container *ast_calendar_event_container_alloc(void)
 {
-       return ao2_container_alloc(CALENDAR_BUCKETS, event_hash_fn, event_cmp_fn);
+       return ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, CALENDAR_BUCKETS,
+               event_hash_fn, NULL, event_cmp_fn);
 }
 
 static void event_notification_destroy(void *data)
@@ -1896,7 +1899,9 @@ static int unload_module(void)
  */
 static int load_module(void)
 {
-       if (!(calendars = ao2_container_alloc(CALENDAR_BUCKETS, calendar_hash_fn, calendar_cmp_fn))) {
+       calendars = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, CALENDAR_BUCKETS,
+               calendar_hash_fn, NULL, calendar_cmp_fn);
+       if (!calendars) {
                ast_log(LOG_ERROR, "Unable to allocate calendars container!\n");
                return AST_MODULE_LOAD_DECLINE;
        }
index dbc79f0..e32498b 100644 (file)
@@ -78,7 +78,7 @@ static void statsmaker(void *data, struct stasis_subscription *sub,
 }
 
 /*!
- * \brief Router callback for \ref stasis_cache_update messages.
+ * \brief Router callback for \ref ast_channel_snapshot_update messages.
  * \param data Data pointer given when added to router.
  * \param sub This subscription.
  * \param topic The topic the message was posted to. This is not necessarily the
@@ -92,34 +92,25 @@ static void updates(void *data, struct stasis_subscription *sub,
        /* Since this came from a message router, we know the type of the
         * message. We can cast the data without checking its type.
         */
-       struct stasis_cache_update *update = stasis_message_data(message);
+       struct ast_channel_snapshot_update *update = stasis_message_data(message);
 
-       /* We're only interested in channel snapshots, so check the type
-        * of the underlying message.
-        */
-       if (ast_channel_snapshot_type() != update->type) {
-               return;
-       }
-
-       /* There are three types of cache updates.
-        * !old && new -> Initial cache entry
-        * old && new -> Updated cache entry
-        * old && !new -> Cache entry removed.
+       /* There are three types of channel snapshot updates.
+        * !old && new -> Initial channel creation
+        * old && new -> Updated channel snapshot
+        * old && dead -> Final channel snapshot
         */
 
        if (!update->old_snapshot && update->new_snapshot) {
-               /* Initial cache entry; count a channel creation */
+               /* Initial channel snapshot; count a channel creation */
                ast_statsd_log_string("channels.count", AST_STATSD_GAUGE, "+1", 1.0);
-       } else if (update->old_snapshot && !update->new_snapshot) {
-               /* Cache entry removed. Compute the age of the channel and post
+       } else if (update->old_snapshot && ast_test_flag(&update->new_snapshot->flags, AST_FLAG_DEAD)) {
+               /* Channel is gone. Compute the age of the channel and post
                 * that, as well as decrementing the channel count.
                 */
-               struct ast_channel_snapshot *last;
                int64_t age;
 
-               last = stasis_message_data(update->old_snapshot);
                age = ast_tvdiff_ms(*stasis_message_timestamp(message),
-                       last->creationtime);
+                       update->new_snapshot->base->creationtime);
                ast_statsd_log("channels.calltime", AST_STATSD_TIMER, age);
 
                /* And decrement the channel count */
@@ -161,11 +152,11 @@ static int load_module(void)
 {
        /* You can create a message router to route messages by type */
        router = stasis_message_router_create(
-               ast_channel_topic_all_cached());
+               ast_channel_topic_all());
        if (!router) {
                return AST_MODULE_LOAD_DECLINE;
        }
-       stasis_message_router_add(router, stasis_cache_update_type(),
+       stasis_message_router_add(router, ast_channel_snapshot_type(),
                updates, NULL);
        stasis_message_router_set_default(router, default_route, NULL);
 
index eaf9b9f..9658c17 100644 (file)
@@ -282,7 +282,9 @@ static int unload_module(void)
  */
 static int load_module(void)
 {
-       if (!(cli_aliases = ao2_container_alloc(MAX_ALIAS_BUCKETS, alias_hash_cb, alias_cmp_cb))) {
+       cli_aliases = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               MAX_ALIAS_BUCKETS, alias_hash_cb, NULL, alias_cmp_cb);
+       if (!cli_aliases) {
                return AST_MODULE_LOAD_DECLINE;
        }
 
index 854034f..6446f17 100644 (file)
@@ -1194,7 +1194,9 @@ static int realtime_sqlite3_require(const char *database, const char *table, va_
                return -1;
        }
 
-       if (!(columns = ao2_container_alloc(31, str_hash_fn, str_cmp_fn))) {
+       columns = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 31,
+               str_hash_fn, NULL, str_cmp_fn);
+       if (!columns) {
                unref_db(&db);
           return -1;
        }
@@ -1369,7 +1371,9 @@ static int load_module(void)
 {
        discover_sqlite3_caps();
 
-       if (!((databases = ao2_container_alloc(DB_BUCKETS, db_hash_fn, db_cmp_fn)))) {
+       databases = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, DB_BUCKETS,
+               db_hash_fn, NULL, db_cmp_fn);
+       if (!databases) {
                return AST_MODULE_LOAD_DECLINE;
        }
 
index 50dd510..bf172e3 100644 (file)
@@ -1125,7 +1125,8 @@ static int load_module(void)
                return AST_MODULE_LOAD_DECLINE;
        }
 
-       nodes = ao2_container_alloc(23, corosync_node_hash_fn, corosync_node_cmp_fn);
+       nodes = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0, 23,
+               corosync_node_hash_fn, NULL, corosync_node_cmp_fn);
        if (!nodes) {
                goto failed;
        }
index f03fdc9..39a7a64 100644 (file)
@@ -4724,7 +4724,9 @@ static int load_module(void)
        /* initialize the registry */
        faxregistry.active_sessions = 0;
        faxregistry.reserved_sessions = 0;
-       if (!(faxregistry.container = ao2_container_alloc(FAX_MAXBUCKETS, session_hash_cb, session_cmp_cb))) {
+       faxregistry.container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
+               FAX_MAXBUCKETS, session_hash_cb, NULL, session_cmp_cb);
+       if (!faxregistry.container) {
                return AST_MODULE_LOAD_DECLINE;
        }