diff --git a/apps/app_agent_pool.c b/apps/app_agent_pool.c
index a6a68f1a39f65ed8d6fcbfd262ba38fd3f0e7e49..5095001cf6287ae797d3f12fd96c3142e9e4d243 100644
--- a/apps/app_agent_pool.c
+++ b/apps/app_agent_pool.c
@@ -1442,7 +1442,7 @@ static void send_agent_login(struct ast_channel *chan, const char *agent)
 		return;
 	}
 
-	ast_channel_publish_blob(chan, ast_channel_agent_login_type(), blob);
+	ast_channel_publish_cached_blob(chan, ast_channel_agent_login_type(), blob);
 }
 
 static void send_agent_logoff(struct ast_channel *chan, const char *agent, long logintime)
@@ -1458,7 +1458,7 @@ static void send_agent_logoff(struct ast_channel *chan, const char *agent, long
 		return;
 	}
 
-	ast_channel_publish_blob(chan, ast_channel_agent_logoff_type(), blob);
+	ast_channel_publish_cached_blob(chan, ast_channel_agent_logoff_type(), blob);
 }
 
 /*!
diff --git a/apps/app_meetme.c b/apps/app_meetme.c
index b6f5fffb9a748b52c27b8c272d435d998b5bf1ff..1a780e6ffc30063c904a12f8402203b642dd6b16 100644
--- a/apps/app_meetme.c
+++ b/apps/app_meetme.c
@@ -1379,9 +1379,7 @@ static void meetme_stasis_generate_msg(struct ast_conference *meetme_conference,
 		}
 	}
 
-	ast_channel_lock(chan);
-	msg = ast_channel_blob_create(chan, message_type, json_object);
-	ast_channel_unlock(chan);
+	msg = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan), message_type, json_object);
 
 	if (!msg) {
 		return;
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 8e26135cd1258818f1c3f3e7c010bb50275288c4..fe6b00ab0f749e82490aae164d4da57e3b9a5c10 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -3510,9 +3510,7 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *
 				     "Queue", q->name,
 				     "Position", qe->pos,
 				     "Count", q->count);
-		ast_channel_lock(qe->chan);
-		ast_channel_publish_blob(qe->chan, queue_caller_join_type(), blob);
-		ast_channel_unlock(qe->chan);
+		ast_channel_publish_cached_blob(qe->chan, queue_caller_join_type(), blob);
 		ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
 	}
 	ao2_unlock(q);
@@ -3791,9 +3789,7 @@ static void leave_queue(struct queue_ent *qe)
 					     "Queue", q->name,
 					     "Position", qe->pos,
 					     "Count", q->count);
-			ast_channel_lock(qe->chan);
-			ast_channel_publish_blob(qe->chan, queue_caller_leave_type(), blob);
-			ast_channel_unlock(qe->chan);
+			ast_channel_publish_cached_blob(qe->chan, queue_caller_leave_type(), blob);
 			ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan));
 			/* Take us out of the queue */
 			if (prev) {
@@ -4395,9 +4391,7 @@ static void record_abandoned(struct queue_ent *qe)
 	qe->parent->callsabandoned++;
 	ao2_unlock(qe->parent);
 
-	ast_channel_lock(qe->chan);
-	ast_channel_publish_blob(qe->chan, queue_caller_abandon_type(), blob);
-	ast_channel_unlock(qe->chan);
+	ast_channel_publish_cached_blob(qe->chan, queue_caller_abandon_type(), blob);
 }
 
 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 3575bae8fe7a57b933b14fb48f5776acbb638903..505e4bac9e1f960e7bce680e69b35f8fc40bcd01 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -4178,6 +4178,15 @@ void ast_channel_dialed_causes_clear(const struct ast_channel *chan);
 
 struct ast_flags *ast_channel_flags(struct ast_channel *chan);
 
+/*!
+ * \since 12.4.0
+ * \brief Return whether or not any manager variables have been set
+ *
+ * \retval 0 if no manager variables are expected
+ * \retval 1 if manager variables are expected
+ */
+int ast_channel_has_manager_vars(void);
+
 /*!
  * \since 12
  * \brief Sets the variables to be stored in the \a manager_vars field of all
diff --git a/include/asterisk/stasis_channels.h b/include/asterisk/stasis_channels.h
index b4097b31b35d4a715bcf1baddbd933d116bef670..a252a2a90bfea782681de9f2b8e82cecbcd526f4 100644
--- a/include/asterisk/stasis_channels.h
+++ b/include/asterisk/stasis_channels.h
@@ -39,17 +39,16 @@
 struct ast_channel_snapshot {
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(name);             /*!< ASCII unique channel name */
-		AST_STRING_FIELD(type);             /*!< Type of channel technology */
-		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(uniqueid);         /*!< Unique Channel Identifier */
 		AST_STRING_FIELD(linkedid);         /*!< Linked Channel Identifier -- gets propagated by linkage */
-		AST_STRING_FIELD(hangupsource);     /*!< Who is responsible for hanging up this channel */
 		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 */
@@ -59,31 +58,20 @@ struct ast_channel_snapshot {
 		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(effective_name);   /*!< Effective Connected Line Name */
-		AST_STRING_FIELD(effective_number); /*!< Effective Connected Line Number */
 		AST_STRING_FIELD(language);         /*!< The default spoken language for the channel */
 		AST_STRING_FIELD(bridgeid);         /*!< Unique Bridge Identifier */
-		AST_STRING_FIELD(nativeformats);    /*!< Native formats on the channel */
-		AST_STRING_FIELD(readformat);       /*!< The current read format */
-		AST_STRING_FIELD(writeformat);      /*!< The current write format */
-		AST_STRING_FIELD(writetrans);       /*!< The current write translation path */
-		AST_STRING_FIELD(readtrans);        /*!< The current read translation path */
+		AST_STRING_FIELD(type);             /*!< Type of channel technology */
 	);
 
-	char callid[AST_CALLID_BUFFER_LENGTH];  /*!< Callid for the channel */
 	struct timeval creationtime;            /*!< The time of channel creation */
-	struct timeval hanguptime;              /*!< When the channel should hang up */
 	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 */
-	ast_group_t callgroup;                  /*!< Call group */
-	ast_group_t pickupgroup;                /*!< Pickup group */
 	struct ast_flags softhangup_flags;      /*!< softhangup channel flags */
 	struct varshead *manager_vars;          /*!< Variables to be appended to manager events */
-	struct varshead *channel_vars;          /*!< Variables set on the channel */
 	int tech_properties;                    /*!< Properties of the channel's technology */
 };
 
@@ -320,6 +308,23 @@ void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj,
 void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_type *type,
 	struct ast_json *blob);
 
+/*!
+ * \brief Publish a channel blob message using the latest snapshot from the cache
+ * \since 12.4.0
+ *
+ * \param chan Channel publishing the blob.
+ * \param type Type of stasis message.
+ * \param blob The blob being published. (NULL if no blob)
+ *
+ * \note As this only accesses the uniqueid and topic of the channel - neither of
+ * which should ever be changed on a channel anyhow - a channel does not have to
+ * be locked when calling this function.
+ *
+ * \return Nothing
+ */
+void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type,
+	struct ast_json *blob);
+
 /*!
  * \since 12
  * \brief Set flag to indicate channel snapshot is being staged.
diff --git a/main/aoc.c b/main/aoc.c
index 7dd888ec2ae8d297aca5719b591bc593942219d4..de43efcb5e47193c28dca64d5fd40b391beea1b3 100644
--- a/main/aoc.c
+++ b/main/aoc.c
@@ -1871,7 +1871,7 @@ int ast_aoc_manager_event(const struct ast_aoc_decoded *decoded, struct ast_chan
 		return 0;
 	}
 
-	ast_channel_publish_blob(chan, msg_type, blob);
+	ast_channel_publish_cached_blob(chan, msg_type, blob);
 	return 0;
 }
 
diff --git a/main/bridge_channel.c b/main/bridge_channel.c
index 9a1e40bba81329848a36a3c8e95f016ad27ac019..9b1b5737e73f71f82e5ecb5c903826dd28610cf3 100644
--- a/main/bridge_channel.c
+++ b/main/bridge_channel.c
@@ -838,18 +838,16 @@ int ast_bridge_channel_write_hold(struct ast_bridge_channel *bridge_channel, con
 		datalen = 0;
 	}
 
-	ast_channel_lock(bridge_channel->chan);
-	ast_channel_publish_blob(bridge_channel->chan, ast_channel_hold_type(), blob);
-	ast_channel_unlock(bridge_channel->chan);
+	ast_channel_publish_cached_blob(bridge_channel->chan, ast_channel_hold_type(), blob);
+
 	return ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_HOLD,
 		moh_class, datalen);
 }
 
 int ast_bridge_channel_write_unhold(struct ast_bridge_channel *bridge_channel)
 {
-	ast_channel_lock(bridge_channel->chan);
-	ast_channel_publish_blob(bridge_channel->chan, ast_channel_unhold_type(), NULL);
-	ast_channel_unlock(bridge_channel->chan);
+	ast_channel_publish_cached_blob(bridge_channel->chan, ast_channel_unhold_type(), NULL);
+
 	return ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_UNHOLD, NULL, 0);
 }
 
diff --git a/main/cel.c b/main/cel.c
index e61adfcec1163805551b615139722b2edd0b6294..c7f4fc36653be3ccfb5ccdc183f1f312b5c2c4a8 100644
--- a/main/cel.c
+++ b/main/cel.c
@@ -1798,9 +1798,7 @@ void ast_cel_publish_event(struct ast_channel *chan,
 		"event_type", event_type,
 		"event_details", blob);
 
-	ast_channel_lock(chan);
-	message = ast_channel_blob_create(chan, cel_generic_type(), cel_blob);
-	ast_channel_unlock(chan);
+	message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan), cel_generic_type(), cel_blob);
 	if (message) {
 		stasis_publish(ast_cel_topic(), message);
 	}
diff --git a/main/channel.c b/main/channel.c
index dd353947982411f4abb8e4ad0d537ae85455e2a8..04c396a7195a1bbce76f1c7c2ee936387115235e 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -1270,7 +1270,6 @@ int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
 	struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_HOLD };
 	int res;
 
-	ast_channel_lock(chan);
 	if (!ast_strlen_zero(musicclass)) {
 		f.data.ptr = (void *) musicclass;
 		f.datalen = strlen(musicclass) + 1;
@@ -1279,10 +1278,10 @@ int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
 				     "musicclass", musicclass);
 	}
 
-	ast_channel_publish_blob(chan, ast_channel_hold_type(), blob);
+	ast_channel_publish_cached_blob(chan, ast_channel_hold_type(), blob);
 
 	res = ast_queue_frame(chan, &f);
-	ast_channel_unlock(chan);
+
 	return res;
 }
 
@@ -1291,11 +1290,10 @@ int ast_queue_unhold(struct ast_channel *chan)
 	struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_UNHOLD };
 	int res;
 
-	ast_channel_lock(chan);
-	ast_channel_publish_blob(chan, ast_channel_unhold_type(), NULL);
+	ast_channel_publish_cached_blob(chan, ast_channel_unhold_type(), NULL);
 
 	res = ast_queue_frame(chan, &f);
-	ast_channel_unlock(chan);
+
 	return res;
 }
 
@@ -3639,7 +3637,7 @@ static void send_dtmf_begin_event(struct ast_channel *chan,
 		return;
 	}
 
-	ast_channel_publish_blob(chan, ast_channel_dtmf_begin_type(), blob);
+	ast_channel_publish_cached_blob(chan, ast_channel_dtmf_begin_type(), blob);
 }
 
 static void send_dtmf_end_event(struct ast_channel *chan,
@@ -3656,7 +3654,7 @@ static void send_dtmf_end_event(struct ast_channel *chan,
 		return;
 	}
 
-	ast_channel_publish_blob(chan, ast_channel_dtmf_end_type(), blob);
+	ast_channel_publish_cached_blob(chan, ast_channel_dtmf_end_type(), blob);
 }
 
 static void ast_read_generator_actions(struct ast_channel *chan, struct ast_frame *f)
@@ -3988,7 +3986,6 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
 					ast_frfree(f);
 					f = &ast_null_frame;
 				} else {
-					/* Answer the CDR */
 					ast_setstate(chan, AST_STATE_UP);
 				}
 			} else if (f->subclass.integer == AST_CONTROL_READ_ACTION) {
@@ -5332,10 +5329,6 @@ static int set_format(struct ast_channel *chan,
 			generator_write_format_change(chan);
 		}
 
-		ast_channel_lock(chan);
-		ast_channel_publish_snapshot(chan);
-		ast_channel_unlock(chan);
-
 		return 0;
 	}
 
@@ -5415,10 +5408,6 @@ static int set_format(struct ast_channel *chan,
 		generator_write_format_change(chan);
 	}
 
-	ast_channel_lock(chan);
-	ast_channel_publish_snapshot(chan);
-	ast_channel_unlock(chan);
-
 	return res;
 }
 
@@ -7414,6 +7403,17 @@ static void free_channelvars(void)
 	AST_RWLIST_UNLOCK(&channelvars);
 }
 
+int ast_channel_has_manager_vars(void)
+{
+	int vars_present;
+
+	AST_RWLIST_RDLOCK(&channelvars);
+	vars_present = !AST_LIST_EMPTY(&channelvars);
+	AST_RWLIST_UNLOCK(&channelvars);
+
+	return vars_present;
+}
+
 void ast_channel_set_manager_vars(size_t varc, char **vars)
 {
 	size_t i;
@@ -7644,12 +7644,9 @@ void ast_set_variables(struct ast_channel *chan, struct ast_variable *vars)
 {
 	struct ast_variable *cur;
 
-	ast_channel_stage_snapshot(chan);
-
-	for (cur = vars; cur; cur = cur->next)
+	for (cur = vars; cur; cur = cur->next) {
 		pbx_builtin_setvar_helper(chan, cur->name, cur->value);
-
-	ast_channel_stage_snapshot_done(chan);
+	}
 }
 
 static void *silence_generator_alloc(struct ast_channel *chan, void *data)
diff --git a/main/channel_internal_api.c b/main/channel_internal_api.c
index 9cc99f3d53db6e3f6bf0b413b8eae64c22dfd0f1..0c5117e6d1c45882da342f1552a17493428cbde0 100644
--- a/main/channel_internal_api.c
+++ b/main/channel_internal_api.c
@@ -943,9 +943,8 @@ void ast_channel_callid_set(struct ast_channel *chan, struct ast_callid *callid)
 		ast_channel_name(chan),
 		call_identifier_to,
 		call_identifier_from);
-
-	ast_channel_publish_snapshot(chan);
 }
+
 void ast_channel_state_set(struct ast_channel *chan, enum ast_channel_state value)
 {
 	chan->state = value;
@@ -1073,7 +1072,6 @@ void ast_channel_dtmf_tv_set(struct ast_channel *chan, struct timeval *value)
 void ast_channel_whentohangup_set(struct ast_channel *chan, struct timeval *value)
 {
 	chan->whentohangup = *value;
-	ast_channel_publish_snapshot(chan);
 }
 void ast_channel_varshead_set(struct ast_channel *chan, struct varshead *value)
 {
@@ -1131,7 +1129,6 @@ ast_group_t ast_channel_callgroup(const struct ast_channel *chan)
 void ast_channel_callgroup_set(struct ast_channel *chan, ast_group_t value)
 {
 	chan->callgroup = value;
-	ast_channel_publish_snapshot(chan);
 }
 ast_group_t ast_channel_pickupgroup(const struct ast_channel *chan)
 {
@@ -1140,7 +1137,6 @@ ast_group_t ast_channel_pickupgroup(const struct ast_channel *chan)
 void ast_channel_pickupgroup_set(struct ast_channel *chan, ast_group_t value)
 {
 	chan->pickupgroup = value;
-	ast_channel_publish_snapshot(chan);
 }
 struct ast_namedgroups *ast_channel_named_callgroups(const struct ast_channel *chan)
 {
diff --git a/main/cli.c b/main/cli.c
index 0fbdb69f675c89d203ba41f174dc8caf2508e282..bff58695d819de49f713250eb809cb0d01d69329 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -1513,8 +1513,7 @@ static char *handle_nodebugchan_deprecated(struct ast_cli_entry *e, int cmd, str
 
 static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	struct ast_channel_snapshot *snapshot;
+	struct ast_channel *chan;
 	struct timeval now;
 	char cdrtime[256];
 	struct ast_str *obuf;/*!< Buffer for CDR variables. */
@@ -1522,6 +1521,12 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 	long elapsed_seconds=0;
 	int hour=0, min=0, sec=0;
 	struct ast_var_t *var;
+	char nativeformats[256];
+	struct ast_str *write_transpath = ast_str_alloca(256);
+	struct ast_str *read_transpath = ast_str_alloca(256);
+	struct ast_bridge *bridge;
+	struct ast_callid *callid;
+	char callid_buf[32];
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -1538,25 +1543,27 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 		return CLI_SHOWUSAGE;
 	}
 
-	now = ast_tvnow();
-
-	if (!(msg = stasis_cache_get(ast_channel_cache_by_name(), ast_channel_snapshot_type(), a->argv[3]))) {
-		ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
-		return CLI_SUCCESS;
-	}
-	snapshot = stasis_message_data(msg);
-
 	obuf = ast_str_thread_get(&ast_str_thread_global_buf, 16);
 	if (!obuf) {
 		return CLI_FAILURE;
 	}
+
 	output = ast_str_create(8192);
 	if (!output) {
 		return CLI_FAILURE;
 	}
 
-	if (!ast_tvzero(snapshot->creationtime)) {
-		elapsed_seconds = now.tv_sec - snapshot->creationtime.tv_sec;
+	chan = ast_channel_get_by_name(a->argv[3]);
+	if (!chan) {
+		ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
+		return CLI_SUCCESS;
+	}
+
+	now = ast_tvnow();
+	ast_channel_lock(chan);
+
+	if (!ast_tvzero(ast_channel_creationtime(chan))) {
+		elapsed_seconds = now.tv_sec - ast_channel_creationtime(chan).tv_sec;
 		hour = elapsed_seconds / 3600;
 		min = (elapsed_seconds % 3600) / 60;
 		sec = elapsed_seconds % 60;
@@ -1565,6 +1572,16 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 		strcpy(cdrtime, "N/A");
 	}
 
+	ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath);
+	ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath);
+
+	bridge = ast_channel_get_bridge(chan);
+	callid = ast_channel_callid(chan);
+	if (callid) {
+		ast_callid_strnprint(callid_buf, sizeof(callid_buf), callid);
+		ast_callid_unref(callid);
+	}
+
 	ast_str_append(&output, 0,
 		" -- General --\n"
 		"           Name: %s\n"
@@ -1597,51 +1614,63 @@ static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
 		"    Application: %s\n"
 		"           Data: %s\n"
 		" Call Identifer: %s\n",
-		snapshot->name,
-		snapshot->type,
-		snapshot->uniqueid,
-		snapshot->linkedid,
-		S_OR(snapshot->caller_number, "(N/A)"),
-		S_OR(snapshot->caller_name, "(N/A)"),
-		S_OR(snapshot->connected_number, "(N/A)"),
-		S_OR(snapshot->connected_name, "(N/A)"),
-		S_OR(snapshot->effective_number, "(N/A)"),
-		S_OR(snapshot->effective_name, "(N/A)"),
-		S_OR(snapshot->caller_dnid, "(N/A)"),
-		snapshot->language,
-		ast_state2str(snapshot->state),
-		snapshot->state,
-		snapshot->nativeformats,
-		snapshot->writeformat,
-		snapshot->readformat,
-		!ast_strlen_zero(snapshot->writetrans) ? "Yes" : "No",
-		snapshot->writetrans,
-		!ast_strlen_zero(snapshot->readtrans) ? "Yes" : "No",
-		snapshot->readtrans,
-		(long) snapshot->hanguptime.tv_sec,
+		ast_channel_name(chan),
+		ast_channel_tech(chan)->type,
+		ast_channel_uniqueid(chan),
+		ast_channel_linkedid(chan),
+		S_COR(ast_channel_caller(chan)->id.number.valid,
+		      ast_channel_caller(chan)->id.number.str, "(N/A)"),
+		S_COR(ast_channel_caller(chan)->id.name.valid,
+		      ast_channel_caller(chan)->id.name.str, "(N/A)"),
+		S_COR(ast_channel_connected(chan)->id.number.valid,
+		      ast_channel_connected(chan)->id.number.str, "(N/A)"),
+		S_COR(ast_channel_connected(chan)->id.name.valid,
+		      ast_channel_connected(chan)->id.name.str, "(N/A)"),
+		S_COR(ast_channel_connected_effective_id(chan).number.valid,
+		      ast_channel_connected_effective_id(chan).number.str, "(N/A)"),
+		S_COR(ast_channel_connected_effective_id(chan).name.valid,
+		      ast_channel_connected_effective_id(chan).name.str, "(N/A)"),
+		S_OR(ast_channel_dialed(chan)->number.str, "(N/A)"),
+		ast_channel_language(chan),
+		ast_state2str(ast_channel_state(chan)),
+		ast_channel_state(chan),
+		ast_getformatname_multiple(nativeformats, sizeof(nativeformats), ast_channel_nativeformats(chan)),
+		ast_getformatname(ast_channel_writeformat(chan)),
+		ast_getformatname(ast_channel_readformat(chan)),
+		ast_str_strlen(write_transpath) ? "Yes" : "No",
+		ast_str_buffer(write_transpath),
+		ast_str_strlen(read_transpath) ? "Yes" : "No",
+		ast_str_buffer(read_transpath),
+		ast_channel_whentohangup(chan)->tv_sec,
 		cdrtime,
-		S_OR(snapshot->bridgeid, "(Not bridged)"),
-		snapshot->context,
-		snapshot->exten,
-		snapshot->priority,
-		snapshot->callgroup,
-		snapshot->pickupgroup,
-		S_OR(snapshot->appl, "(N/A)"),
-		S_OR(snapshot->data, "(Empty)"),
-		S_OR(snapshot->callid, "(None)"));
-
+		bridge ? bridge->uniqueid : "(Not bridged)",
+		ast_channel_context(chan),
+		ast_channel_exten(chan),
+		ast_channel_priority(chan),
+		ast_channel_callgroup(chan),
+		ast_channel_pickupgroup(chan),
+		S_OR(ast_channel_appl(chan), "(N/A)"),
+		S_OR(ast_channel_data(chan), "(Empty)"),
+		S_OR(callid_buf, "(None)")
+		);
 	ast_str_append(&output, 0, "      Variables:\n");
 
-	AST_LIST_TRAVERSE(snapshot->channel_vars, var, entries) {
+	AST_LIST_TRAVERSE(ast_channel_varshead(chan), var, entries) {
 		ast_str_append(&output, 0, "%s=%s\n", ast_var_name(var), ast_var_value(var));
 	}
 
-	if (ast_cdr_serialize_variables(snapshot->name, &obuf, '=', '\n')) {
+	if (ast_cdr_serialize_variables(ast_channel_name(chan), &obuf, '=', '\n')) {
 		ast_str_append(&output, 0, "  CDR Variables:\n%s\n", ast_str_buffer(obuf));
 	}
 
+	ast_channel_unlock(chan);
+
 	ast_cli(a->fd, "%s", ast_str_buffer(output));
 	ast_free(output);
+
+	ao2_cleanup(bridge);
+	ast_channel_unref(chan);
+
 	return CLI_SUCCESS;
 }
 
diff --git a/main/core_local.c b/main/core_local.c
index 98db5e575a65eeca6f7faa9070666c51e27f37b2..e803f29ec0d369051e81df2f17fb1d5eef287b19 100644
--- a/main/core_local.c
+++ b/main/core_local.c
@@ -328,12 +328,12 @@ static struct ast_multi_channel_blob *local_channel_optimization_blob(struct loc
 	RAII_VAR(struct ast_channel_snapshot *, local_one_snapshot, NULL, ao2_cleanup);
 	RAII_VAR(struct ast_channel_snapshot *, local_two_snapshot, NULL, ao2_cleanup);
 
-	local_one_snapshot = ast_channel_snapshot_create(p->base.owner);
+	local_one_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(p->base.owner));
 	if (!local_one_snapshot) {
 		return NULL;
 	}
 
-	local_two_snapshot = ast_channel_snapshot_create(p->base.chan);
+	local_two_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(p->base.chan));
 	if (!local_two_snapshot) {
 		return NULL;
 	}
@@ -371,7 +371,7 @@ static void local_optimization_started_cb(struct ast_unreal_pvt *base, struct as
 
 	if (source) {
 		RAII_VAR(struct ast_channel_snapshot *, source_snapshot, NULL, ao2_cleanup);
-		source_snapshot = ast_channel_snapshot_create(source);
+		source_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(source));
 		if (!source_snapshot) {
 			return;
 		}
@@ -516,12 +516,12 @@ static void publish_local_bridge_message(struct local_pvt *p)
 		goto end;
 	}
 
-	one_snapshot = ast_channel_snapshot_create(owner);
+	one_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(owner));
 	if (!one_snapshot) {
 		goto end;
 	}
 
-	two_snapshot = ast_channel_snapshot_create(chan);
+	two_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
 	if (!two_snapshot) {
 		goto end;
 	}
diff --git a/main/dial.c b/main/dial.c
index 2563c707b5cc7445f5e7cedaec098c4cc66eb1c5..f03d43d257c3a5560dcffc2853cd580c0578c1ed 100644
--- a/main/dial.c
+++ b/main/dial.c
@@ -323,7 +323,7 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe
 
 	ast_channel_appl_set(channel->owner, "AppDial2");
 	ast_channel_data_set(channel->owner, "(Outgoing Line)");
-	ast_publish_channel_state(channel->owner);
+
 	memset(ast_channel_whentohangup(channel->owner), 0, sizeof(*ast_channel_whentohangup(channel->owner)));
 
 	/* Inherit everything from he who spawned this dial */
diff --git a/main/endpoints.c b/main/endpoints.c
index 9cc0178e0dad2182a8d71a94a100e5c6b8ae2c52..10b32e268d4899823e894fd5432a7db90f5b5b8b 100644
--- a/main/endpoints.c
+++ b/main/endpoints.c
@@ -203,9 +203,6 @@ int ast_endpoint_add_channel(struct ast_endpoint *endpoint,
 	ast_str_container_add(endpoint->channel_ids, ast_channel_uniqueid(chan));
 	ao2_unlock(endpoint);
 
-	ast_channel_lock(chan);
-	ast_publish_channel_state(chan);
-	ast_channel_unlock(chan);
 	endpoint_publish_snapshot(endpoint);
 
 	return 0;
diff --git a/main/manager.c b/main/manager.c
index 7a7e8903ae955fee3aaa1ddfde614abfe8e9a691..6e056a163387b5f2cf6ded123ee4438957206a19 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -99,6 +99,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/bridge.h"
 #include "asterisk/features_config.h"
 #include "asterisk/rtp_engine.h"
+#include "asterisk/translate.h"
 
 /*** DOCUMENTATION
 	<manager name="Ping" language="en_US">
@@ -3846,95 +3847,110 @@ static int action_getvar(struct mansession *s, const struct message *m)
 static int action_status(struct mansession *s, const struct message *m)
 {
 	const char *name = astman_get_header(m, "Channel");
-	const char *cvariables = astman_get_header(m, "Variables");
-	char *variables = ast_strdupa(S_OR(cvariables, ""));
-	RAII_VAR(struct ao2_container *, cached_channels, NULL, ao2_cleanup);
-	struct stasis_message *msg;
+	const char *chan_variables = astman_get_header(m, "Variables");
+	const char *id = astman_get_header(m, "ActionID");
+	char *variables = ast_strdupa(S_OR(chan_variables, ""));
+	struct ast_str *variable_str = ast_str_create(1024);
+	struct ast_str *write_transpath = ast_str_alloca(256);
+	struct ast_str *read_transpath = ast_str_alloca(256);
+	struct ast_channel *chan;
+	char nativeformats[256];
 	int channels = 0;
 	int all = ast_strlen_zero(name); /* set if we want all channels */
-	const char *id = astman_get_header(m, "ActionID");
-	char idText[256];
+	char id_text[256];
+	struct ast_channel_iterator *it_chans = NULL;
 	AST_DECLARE_APP_ARGS(vars,
 		AST_APP_ARG(name)[100];
 	);
-	struct ast_str *str = ast_str_create(1000);
-	struct ao2_iterator it_chans;
-	struct timeval now = ast_tvnow();
 
-	if (!ast_strlen_zero(id)) {
-		snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
-	} else {
-		idText[0] = '\0';
+	if (!variable_str) {
+		astman_send_error(s, m, "Memory Allocation Failure");
+		return 1;
 	}
 
 	if (!(function_capable_string_allowed_with_auths(variables, s->session->writeperm))) {
+		ast_free(variable_str);
 		astman_send_error(s, m, "Status Access Forbidden: Variables");
 		return 0;
 	}
 
 	if (all) {
-		if (!(cached_channels = stasis_cache_dump(ast_channel_cache_by_name(), ast_channel_snapshot_type()))) {
-			ast_free(str);
+		if (!(it_chans = ast_channel_iterator_all_new())) {
+			ast_free(variable_str);
 			astman_send_error(s, m, "Memory Allocation Failure");
 			return 1;
 		}
-		it_chans = ao2_iterator_init(cached_channels, 0);
-		msg = ao2_iterator_next(&it_chans);
+		chan = ast_channel_iterator_next(it_chans);
 	} else {
-		if (!(msg = stasis_cache_get(ast_channel_cache_by_name(), ast_channel_snapshot_type(), name))) {
+		chan = ast_channel_get_by_name(name);
+		if (!chan) {
 			astman_send_error(s, m, "No such channel");
-			ast_free(str);
+			ast_free(variable_str);
 			return 0;
 		}
 	}
 
 	astman_send_ack(s, m, "Channel status will follow");
 
-	if (!ast_strlen_zero(cvariables)) {
+	if (!ast_strlen_zero(id)) {
+		snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
+	} else {
+		id_text[0] = '\0';
+	}
+
+	if (!ast_strlen_zero(chan_variables)) {
 		AST_STANDARD_APP_ARGS(vars, variables);
 	}
 
 	/* if we look by name, we break after the first iteration */
-	for (; msg; ao2_ref(msg, -1), msg = all ? ao2_iterator_next(&it_chans) : NULL) {
-		struct ast_channel_snapshot *snapshot = stasis_message_data(msg);
-		struct ast_channel *c;
-		struct ast_str *built = ast_manager_build_channel_state_string_prefix(snapshot, "");
-		long elapsed_seconds = 0;
+	for (; chan; all ? chan = ast_channel_iterator_next(it_chans) : 0) {
+		struct timeval now;
+		long elapsed_seconds;
+		struct ast_bridge *bridge;
 
-		if (!built) {
-			continue;
-		}
+		ast_channel_lock(chan);
+
+		now = ast_tvnow();
+		elapsed_seconds = ast_tvdiff_sec(now, ast_channel_creationtime(chan));
 
-		if (!ast_strlen_zero(cvariables) && (c = ast_channel_get_by_name(snapshot->name))) {
+		if (!ast_strlen_zero(chan_variables)) {
 			int i;
-			ast_str_reset(str);
+			ast_str_reset(variable_str);
 			for (i = 0; i < vars.argc; i++) {
 				char valbuf[512], *ret = NULL;
 
 				if (vars.name[i][strlen(vars.name[i]) - 1] == ')') {
-					if (ast_func_read(c, vars.name[i], valbuf, sizeof(valbuf)) < 0) {
+					if (ast_func_read(chan, vars.name[i], valbuf, sizeof(valbuf)) < 0) {
 						valbuf[0] = '\0';
 					}
 					ret = valbuf;
 				} else {
-					pbx_retrieve_variable(c, vars.name[i], &ret, valbuf, sizeof(valbuf), NULL);
+					pbx_retrieve_variable(chan, vars.name[i], &ret, valbuf, sizeof(valbuf), NULL);
 				}
 
-				ast_str_append(&str, 0, "Variable: %s=%s\r\n", vars.name[i], ret);
+				ast_str_append(&variable_str, 0, "Variable: %s=%s\r\n", vars.name[i], ret);
 			}
-			ast_channel_unref(c);
 		}
 
 		channels++;
 
-
-		if (!ast_tvzero(snapshot->creationtime)) {
-			elapsed_seconds = now.tv_sec - snapshot->creationtime.tv_sec;
-		}
+		bridge = ast_channel_get_bridge(chan);
 
 		astman_append(s,
 			"Event: Status\r\n"
 			"Privilege: Call\r\n"
+			"Channel: %s\r\n"
+			"ChannelState: %u\r\n"
+			"ChannelStateDesc: %s\r\n"
+			"CallerIDNum: %s\r\n"
+			"CallerIDName: %s\r\n"
+			"ConnectedLineNum: %s\r\n"
+			"ConnectedLineName: %s\r\n"
+			"Accountcode: %s\r\n"
+			"Context: %s\r\n"
+			"Exten: %s\r\n"
+			"Priority: %d\r\n"
+			"Uniqueid: %s\r\n"
 			"Type: %s\r\n"
 			"DNID: %s\r\n"
 			"EffectiveConnectedLineNum: %s\r\n"
@@ -3954,43 +3970,56 @@ static int action_status(struct mansession *s, const struct message *m)
 			"Seconds: %ld\r\n"
 			"%s"
 			"%s"
-			"%s"
 			"\r\n",
-			snapshot->type,
-			snapshot->caller_dnid,
-			S_OR(snapshot->effective_number, "<unknown>"),
-			S_OR(snapshot->effective_name, "<unknown>"),
-			snapshot->hanguptime.tv_sec,
-			snapshot->bridgeid,
-			snapshot->linkedid,
-			snapshot->appl,
-			snapshot->data,
-			snapshot->nativeformats,
-			snapshot->readformat,
-			snapshot->readtrans,
-			snapshot->writeformat,
-			snapshot->writetrans,
-			snapshot->callgroup,
-			snapshot->pickupgroup,
-			(long) elapsed_seconds,
-			ast_str_buffer(built),
-			ast_str_buffer(str),
-			idText);
+			ast_channel_name(chan),
+			ast_channel_state(chan),
+			ast_state2str(ast_channel_state(chan)),
+			S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "<unknown>"),
+			S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "<unknown>"),
+			S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, "<unknown>"),
+			S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, "<unknown>"),
+			ast_channel_accountcode(chan),
+			ast_channel_context(chan),
+			ast_channel_exten(chan),
+			ast_channel_priority(chan),
+			ast_channel_uniqueid(chan),
+			ast_channel_tech(chan)->type,
+			S_OR(ast_channel_dialed(chan)->number.str, ""),
+			S_COR(ast_channel_connected_effective_id(chan).number.valid, ast_channel_connected_effective_id(chan).number.str, "<unknown>"),
+			S_COR(ast_channel_connected_effective_id(chan).name.valid, ast_channel_connected_effective_id(chan).name.str, "<unknown>"),
+			ast_channel_whentohangup(chan)->tv_sec,
+			bridge ? bridge->uniqueid : "",
+			ast_channel_linkedid(chan),
+			ast_channel_appl(chan),
+			ast_channel_data(chan),
+			ast_getformatname_multiple(nativeformats, sizeof(nativeformats), ast_channel_nativeformats(chan)),
+			ast_getformatname(ast_channel_readformat(chan)),
+			ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath),
+			ast_getformatname(ast_channel_writeformat(chan)),
+			ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath),
+			ast_channel_callgroup(chan),
+			ast_channel_pickupgroup(chan),
+			(long)elapsed_seconds,
+			ast_str_buffer(variable_str),
+			id_text);
+
+		ao2_cleanup(bridge);
 
-		ast_free(built);
+		ast_channel_unlock(chan);
+		chan = ast_channel_unref(chan);
 	}
 
-	if (all) {
-		ao2_iterator_destroy(&it_chans);
+	if (it_chans) {
+		ast_channel_iterator_destroy(it_chans);
 	}
 
 	astman_append(s,
 		"Event: StatusComplete\r\n"
 		"%s"
 		"Items: %d\r\n"
-		"\r\n", idText, channels);
+		"\r\n", id_text, channels);
 
-	ast_free(str);
+	ast_free(variable_str);
 
 	return 0;
 }
diff --git a/main/pbx.c b/main/pbx.c
index b1c50e5abb86b56f1e311634d8cc29bc79e564c9..3c7b127e6f9c035ca5c675ebeff5dd0ab35b2790 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -8369,8 +8369,7 @@ static char *handle_show_device2extenstate(struct ast_cli_entry *e, int cmd, str
 /*! \brief CLI support for listing chanvar's variables in a parseable way */
 static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-	struct ast_channel_snapshot *snapshot;
+	struct ast_channel *chan;
 	struct ast_var_t *var;
 
 	switch (cmd) {
@@ -8384,19 +8383,23 @@ static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cl
 		return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
 	}
 
-	if (a->argc != e->args + 1)
+	if (a->argc != e->args + 1) {
 		return CLI_SHOWUSAGE;
+	}
 
-	if (!(msg = stasis_cache_get(ast_channel_cache_by_name(), ast_channel_snapshot_type(), a->argv[3]))) {
+	chan = ast_channel_get_by_name(a->argv[e->args]);
+	if (!chan) {
 		ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
 		return CLI_FAILURE;
 	}
-	snapshot = stasis_message_data(msg);
 
-	AST_LIST_TRAVERSE(snapshot->channel_vars, var, entries) {
+	ast_channel_lock(chan);
+	AST_LIST_TRAVERSE(ast_channel_varshead(chan), var, entries) {
 		ast_cli(a->fd, "%s=%s\n", ast_var_name(var), ast_var_value(var));
 	}
+	ast_channel_unlock(chan);
 
+	ast_channel_unref(chan);
 	return CLI_SUCCESS;
 }
 
@@ -10187,7 +10190,7 @@ static void *pbx_outgoing_exec(void *data)
 		struct ast_app *app = pbx_findapp(outgoing->app);
 
 		if (app) {
-			ast_verb(4, "Launching %s(%s) on %s\n", outgoing->app, outgoing->appdata,
+			ast_verb(4, "Launching %s(%s) on %s\n", outgoing->app, S_OR(outgoing->appdata, ""),
 				ast_channel_name(ast_dial_answered(outgoing->dial)));
 			pbx_exec(ast_dial_answered(outgoing->dial), app, outgoing->appdata);
 		} else {
@@ -11444,14 +11447,11 @@ int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const
 	AST_LIST_TRAVERSE_SAFE_END;
 
 	if (value && (newvariable = ast_var_assign(name, value))) {
-		if (headp == &globals)
+		if (headp == &globals) {
 			ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
+		}
 		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
 		ast_channel_publish_varset(chan, name, value);
-
-		if (headp != &globals) {
-			ast_channel_publish_snapshot(chan);
-		}
 	}
 
 	if (chan)
diff --git a/main/pickup.c b/main/pickup.c
index a415f1672876dc941ff63ef85f317dcc57fc8cce..5be0c03abecfc29112a1966879d3ac74884ec575 100644
--- a/main/pickup.c
+++ b/main/pickup.c
@@ -361,9 +361,7 @@ int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target)
 		goto pickup_failed;
 	}
 
-	ast_channel_lock(target);
-	target_snapshot = ast_channel_snapshot_create(target);
-	ast_channel_unlock(target);
+	target_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(target));
 	if (!target_snapshot) {
 		goto pickup_failed;
 	}
diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c
index 1e0b36edffcd2fc4303bace00e57477e20638efc..c5df5f4f9300a98dd31ac7ec5eb62e4287759340 100644
--- a/main/stasis_bridges.c
+++ b/main/stasis_bridges.c
@@ -407,9 +407,7 @@ struct stasis_message *ast_bridge_blob_create(
 	}
 
 	if (chan) {
-		ast_channel_lock(chan);
-		obj->channel = ast_channel_snapshot_create(chan);
-		ast_channel_unlock(chan);
+		obj->channel = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
 		if (obj->channel == NULL) {
 			return NULL;
 		}
@@ -593,9 +591,7 @@ static int bridge_channel_snapshot_pair_init(struct ast_bridge_channel_pair *pai
 		}
 	}
 
-	ast_channel_lock(pair->channel);
-	snapshot_pair->channel_snapshot = ast_channel_snapshot_create(pair->channel);
-	ast_channel_unlock(pair->channel);
+	snapshot_pair->channel_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(pair->channel));
 	if (!snapshot_pair->channel_snapshot) {
 		return -1;
 	}
@@ -1072,9 +1068,7 @@ void ast_bridge_publish_attended_transfer_link(int is_external, enum ast_transfe
 
 	transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_LINK;
 	for (i = 0; i < 2; ++i) {
-		ast_channel_lock(locals[i]);
-		transfer_msg->dest.links[i] = ast_channel_snapshot_create(locals[i]);
-		ast_channel_unlock(locals[i]);
+		transfer_msg->dest.links[i] = ast_channel_snapshot_get_latest(ast_channel_uniqueid(locals[i]));
 		if (!transfer_msg->dest.links[i]) {
 			return;
 		}
diff --git a/main/stasis_cache.c b/main/stasis_cache.c
index c1dab8539b767ad424d3a7ae15d359781023c98a..8b4304e5f4f3f1a8b61627820c09e161750db198 100644
--- a/main/stasis_cache.c
+++ b/main/stasis_cache.c
@@ -127,9 +127,17 @@ struct stasis_caching_topic *stasis_caching_unsubscribe_and_join(struct stasis_c
 	return NULL;
 }
 
+/*!
+ * \brief The key for an entry in the cache
+ * \note The items in this struct must be immutable for the item in the cache
+ */
 struct cache_entry_key {
+	/*! The message type of the item stored in the cache */
 	struct stasis_message_type *type;
+	/*! The unique ID of the item stored in the cache */
 	const char *id;
+	/*! The hash, computed from \c type and \c id */
+	unsigned int hash;
 };
 
 struct stasis_cache_entry {
@@ -166,6 +174,12 @@ static void cache_entry_dtor(void *obj)
 	AST_VECTOR_FREE(&entry->remote);
 }
 
+static void cache_entry_compute_hash(struct cache_entry_key *key)
+{
+	key->hash = ast_hashtab_hash_string(stasis_message_type_name(key->type));
+	key->hash += ast_hashtab_hash_string(key->id);
+}
+
 static struct stasis_cache_entry *cache_entry_create(struct stasis_message_type *type, const char *id, struct stasis_message *snapshot)
 {
 	struct stasis_cache_entry *entry;
@@ -187,6 +201,7 @@ static struct stasis_cache_entry *cache_entry_create(struct stasis_message_type
 		return NULL;
 	}
 	entry->key.type = ao2_bump(type);
+	cache_entry_compute_hash(&entry->key);
 
 	is_remote = ast_eid_cmp(&ast_eid_default, stasis_message_eid(snapshot)) ? 1 : 0;
 	if (AST_VECTOR_INIT(&entry->remote, is_remote)) {
@@ -211,7 +226,6 @@ static int cache_entry_hash(const void *obj, int flags)
 {
 	const struct stasis_cache_entry *object;
 	const struct cache_entry_key *key;
-	int hash = 0;
 
 	switch (flags & OBJ_SEARCH_MASK) {
 	case OBJ_SEARCH_KEY:
@@ -227,9 +241,7 @@ static int cache_entry_hash(const void *obj, int flags)
 		return 0;
 	}
 
-	hash += ast_hashtab_hash_string(stasis_message_type_name(key->type));
-	hash += ast_hashtab_hash_string(key->id);
-	return hash;
+	return (int)key->hash;
 }
 
 static int cache_entry_cmp(void *obj, void *arg, int flags)
@@ -347,6 +359,7 @@ static struct stasis_cache_entry *cache_find(struct ao2_container *entries, stru
 
 	search_key.type = type;
 	search_key.id = id;
+	cache_entry_compute_hash(&search_key);
 	entry = ao2_find(entries, &search_key, OBJ_SEARCH_KEY | OBJ_NOLOCK);
 
 	/* Ensure that what we looked for is what we found. */
diff --git a/main/stasis_channels.c b/main/stasis_channels.c
index f38edb0e1f605fca34a252fc2f0079a6a127c3e9..ad9da50cfb76f62e9c7513f8a600735f989df487 100644
--- a/main/stasis_channels.c
+++ b/main/stasis_channels.c
@@ -195,18 +195,12 @@ static void channel_snapshot_dtor(void *obj)
 
 	ast_string_field_free_memory(snapshot);
 	ao2_cleanup(snapshot->manager_vars);
-	ao2_cleanup(snapshot->channel_vars);
 }
 
 struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan)
 {
 	struct ast_channel_snapshot *snapshot;
 	struct ast_bridge *bridge;
-	char nativeformats[256];
-	struct ast_str *write_transpath = ast_str_alloca(256);
-	struct ast_str *read_transpath = ast_str_alloca(256);
-	struct ast_party_id effective_connected_id;
-	struct ast_callid *callid;
 
 	/* no snapshots for dummy channels */
 	if (!ast_channel_tech(chan)) {
@@ -263,38 +257,16 @@ struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *cha
 		ao2_cleanup(bridge);
 	}
 
-	ast_string_field_set(snapshot, nativeformats, ast_getformatname_multiple(nativeformats, sizeof(nativeformats),
-		ast_channel_nativeformats(chan)));
-	ast_string_field_set(snapshot, readformat, ast_getformatname(ast_channel_readformat(chan)));
-	ast_string_field_set(snapshot, writeformat, ast_getformatname(ast_channel_writeformat(chan)));
-	ast_string_field_set(snapshot, writetrans, ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath));
-	ast_string_field_set(snapshot, readtrans, ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath));
-
-	effective_connected_id = ast_channel_connected_effective_id(chan);
-	ast_string_field_set(snapshot, effective_name,
-		S_COR(effective_connected_id.name.valid, effective_connected_id.name.str, ""));
-	ast_string_field_set(snapshot, effective_number,
-		S_COR(effective_connected_id.number.valid, effective_connected_id.number.str, ""));
-
-	if ((callid = ast_channel_callid(chan))) {
-		ast_callid_strnprint(snapshot->callid, sizeof(snapshot->callid), callid);
-		ast_callid_unref(callid);
-	}
-
 	snapshot->creationtime = ast_channel_creationtime(chan);
-	snapshot->hanguptime = *(ast_channel_whentohangup(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);
-	snapshot->callgroup = ast_channel_callgroup(chan);
-	snapshot->pickupgroup = ast_channel_pickupgroup(chan);
 	ast_set_flag(&snapshot->softhangup_flags, ast_channel_softhangup_internal_flag(chan));
 
 	snapshot->manager_vars = ast_channel_get_manager_vars(chan);
-	snapshot->channel_vars = ast_channel_get_vars(chan);
 	snapshot->tech_properties = ast_channel_tech(chan)->properties;
 
 	return snapshot;
@@ -347,7 +319,11 @@ void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_cha
 
 	if (caller) {
 		ast_channel_lock(caller);
-		caller_snapshot = ast_channel_snapshot_create(caller);
+		if (ast_strlen_zero(dialstatus)) {
+			caller_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(caller));
+		} else {
+			caller_snapshot = ast_channel_snapshot_create(caller);
+		}
 		ast_channel_unlock(caller);
 		if (!caller_snapshot) {
 			return;
@@ -356,7 +332,11 @@ void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_cha
 	}
 
 	ast_channel_lock(peer);
-	peer_snapshot = ast_channel_snapshot_create(peer);
+	if (ast_strlen_zero(dialstatus)) {
+		peer_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(peer));
+	} else {
+		peer_snapshot = ast_channel_snapshot_create(peer);
+	}
 	ast_channel_unlock(peer);
 	if (!peer_snapshot) {
 		return;
@@ -682,9 +662,24 @@ void ast_channel_publish_snapshot(struct ast_channel *chan)
 	stasis_publish(ast_channel_topic(chan), message);
 }
 
+void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
+{
+	struct stasis_message *message;
+
+	if (!blob) {
+		blob = ast_json_null();
+	}
+
+	message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan), type, blob);
+	if (message) {
+		stasis_publish(ast_channel_topic(chan), message);
+	}
+	ao2_cleanup(message);
+}
+
 void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
 {
-	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+	struct stasis_message *message;
 
 	if (!blob) {
 		blob = ast_json_null();
@@ -694,11 +689,12 @@ void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_ty
 	if (message) {
 		stasis_publish(ast_channel_topic(chan), message);
 	}
+	ao2_cleanup(message);
 }
 
 void ast_channel_publish_varset(struct ast_channel *chan, const char *name, const char *value)
 {
-	RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+	struct ast_json *blob;
 
 	ast_assert(name != NULL);
 	ast_assert(value != NULL);
@@ -711,7 +707,15 @@ void ast_channel_publish_varset(struct ast_channel *chan, const char *name, cons
 		return;
 	}
 
-	ast_channel_publish_blob(chan, ast_channel_varset_type(), blob);
+	if (chan && !ast_channel_has_manager_vars()) {
+		ast_channel_publish_cached_blob(chan, ast_channel_varset_type(), blob);
+	} else {
+		/* This function is NULL safe. If there are manager variables,
+		 * we have to produce the full snapshot.
+		 */
+		ast_channel_publish_blob(chan, ast_channel_varset_type(), blob);
+	}
+	ast_json_unref(blob);
 }
 
 static struct ast_manager_event_blob *varset_to_ami(struct stasis_message *msg)
@@ -1179,3 +1183,4 @@ int ast_stasis_channels_init(void)
 
 	return res;
 }
+
diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c
index 30ced1b2ff8cb48586e01be34bd70c81bd3d5c3e..647344303064175032ea8bdc3ff33d30a8678d25 100644
--- a/res/ari/resource_channels.c
+++ b/res/ari/resource_channels.c
@@ -859,7 +859,7 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint,
 		return;
 	}
 
-	snapshot = ast_channel_snapshot_create(chan);
+	snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
 	ast_channel_unlock(chan);
 
 	if (!ast_strlen_zero(args_app)) {
@@ -1086,7 +1086,7 @@ static void ari_channels_handle_snoop_channel(
 		return;
 	}
 
-	snapshot = ast_channel_snapshot_create(snoop);
+	snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(snoop));
 	ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot, NULL));
 }
 
diff --git a/res/res_agi.c b/res/res_agi.c
index e223603a6299a1b883b844f076dea8f7813fd382..3adf36bacc4fdd5b6246c5ebff92988ad166fb59 100644
--- a/res/res_agi.c
+++ b/res/res_agi.c
@@ -1481,11 +1481,11 @@ static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char
 	   to execute based on the setup info */
 	ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, ast_uri_http);
 	startblob = ast_json_pack("{s: s}", "Env", ami_buffer);
-	ast_channel_lock(chan);
-	ast_channel_publish_blob(chan, agi_async_start_type(), startblob);
 
-	hungup = ast_check_hangup(chan);
-	ast_channel_unlock(chan);
+	ast_channel_publish_cached_blob(chan, agi_async_start_type(), startblob);
+
+	hungup = ast_check_hangup_locked(chan);
+
 	for (;;) {
 		/*
 		 * Process as many commands as we can.  Commands are added via
@@ -1529,9 +1529,7 @@ static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char
 			if (execblob && !ast_strlen_zero(cmd->cmd_id)) {
 				ast_json_object_set(execblob, "CommandId", ast_json_string_create(cmd->cmd_id));
 			}
-			ast_channel_lock(chan);
-			ast_channel_publish_blob(chan, agi_async_exec_type(), execblob);
-			ast_channel_unlock(chan);
+			ast_channel_publish_cached_blob(chan, agi_async_exec_type(), execblob);
 
 			free_agi_cmd(cmd);
 
@@ -1591,9 +1589,7 @@ async_agi_done:
 		ast_speech_destroy(async_agi.speech);
 	}
 	/* notify manager users this channel cannot be controlled anymore by Async AGI */
-	ast_channel_lock(chan);
-	ast_channel_publish_blob(chan, agi_async_end_type(), NULL);
-	ast_channel_unlock(chan);
+	ast_channel_publish_cached_blob(chan, agi_async_end_type(), NULL);
 
 async_agi_abort:
 	/* close the pipe */
@@ -3665,9 +3661,7 @@ static void publish_async_exec_end(struct ast_channel *chan, int command_id, con
 			     "Command", command,
 			     "ResultCode", result_code,
 			     "Result", result);
-	ast_channel_lock(chan);
-	ast_channel_publish_blob(chan, agi_exec_end_type(), blob);
-	ast_channel_unlock(chan);
+	ast_channel_publish_cached_blob(chan, agi_exec_end_type(), blob);
 }
 
 static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
@@ -3685,9 +3679,7 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch
 	startblob = ast_json_pack("{s: i, s: s}",
 			     "CommandId", command_id,
 			     "Command", ami_cmd);
-	ast_channel_lock(chan);
-	ast_channel_publish_blob(chan, agi_exec_start_type(), startblob);
-	ast_channel_unlock(chan);
+	ast_channel_publish_cached_blob(chan, agi_exec_start_type(), startblob);
 
 	parse_args(buf, &argc, argv);
 	c = find_command(argv, 0);
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 511b61393c849b1e69f0b14a11bb9fd02dcef6af..ea3326969d0de82cc55a2e602ddb29df03592e3d 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -1393,8 +1393,8 @@ static int cli_channel_print_header(void *obj, void *arg, int flags)
 		indent = CLI_INDENT_TO_SPACES(context->indent_level);
 		filler = CLI_LAST_TABSTOP - indent - 38;
 		ast_str_append(&context->output_buffer, 0,
-			"%*s:  <Codec>  Exten: <DialedExten%*.*s>  CLCID: <ConnectedLineCID.......>\n",
-			indent, "Codec", filler, filler, CLI_HEADER_FILLER);
+			"%*s: <DialedExten%*.*s>  CLCID: <ConnectedLineCID.......>\n",
+			indent, "Exten", filler, filler, CLI_HEADER_FILLER);
 		context->indent_level--;
 	}
 
@@ -1438,9 +1438,8 @@ static int cli_channel_print_body(void *obj, void *arg, int flags)
 		flexwidth = CLI_LAST_TABSTOP - indent - 25;
 
 		ast_str_append(&context->output_buffer, 0,
-			"%*s:  %-7s  Exten: %-*.*s  CLCID: \"%s\" <%s>\n",
-			indent, "Codec",
-			snapshot->nativeformats,
+			"%*s: %-*.*s  CLCID: \"%s\" <%s>\n",
+			indent, "Exten",
 			flexwidth, flexwidth,
 			snapshot->exten,
 			snapshot->connected_name,