From 833d666803a2bac472c17b3c5b61683b780e267b Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Tue, 29 Sep 2020 23:49:57 +0000 Subject: [PATCH 1/8] Cleanup: Deduplicated code for client moves --- src/source.c | 58 ++++++++++++++++++++-------------------------------- 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/src/source.c b/src/source.c index d944cf40..130187a1 100644 --- a/src/source.c +++ b/src/source.c @@ -343,6 +343,24 @@ client_t *source_find_client(source_t *source, int id) return NULL; } +static inline void source_move_clients__single(source_t *source, avl_tree *from, avl_tree *to, avl_node *node) { + client_t *client = (client_t*)node->key; + + avl_delete(from, client, NULL); + + /* when switching a client to a different queue, be wary of the + * refbuf it's referring to, if it's http headers then we need + * to write them so don't release it. + */ + if (client->check_buffer != format_check_http_buffer) { + client_set_queue(client, NULL); + client->check_buffer = format_check_file_buffer; + if (source->con == NULL) + client->intro_offset = -1; + } + + avl_insert(to, (void *)client); +} /* Move clients from source to dest provided dest is running * and that the stream format is the same. @@ -373,8 +391,6 @@ void source_move_clients(source_t *source, source_t *dest) do { - client_t *client; - /* we need to move the client and pending trees - we must take the * locks in this order to avoid deadlocks */ avl_tree_wlock(source->pending_tree); @@ -396,49 +412,19 @@ void source_move_clients(source_t *source, source_t *dest) while (1) { - avl_node *node = avl_get_first (source->pending_tree); + avl_node *node = avl_get_first(source->pending_tree); if (node == NULL) break; - client = (client_t *)(node->key); - avl_delete (source->pending_tree, client, NULL); - - /* when switching a client to a different queue, be wary of the - * refbuf it's referring to, if it's http headers then we need - * to write them so don't release it. - */ - if (client->check_buffer != format_check_http_buffer) - { - client_set_queue (client, NULL); - client->check_buffer = format_check_file_buffer; - if (source->con == NULL) - client->intro_offset = -1; - } - - avl_insert (dest->pending_tree, (void *)client); + source_move_clients__single(source, source->pending_tree, dest->pending_tree, node); count++; } while (1) { - avl_node *node = avl_get_first (source->client_tree); + avl_node *node = avl_get_first(source->client_tree); if (node == NULL) break; - - client = (client_t *)(node->key); - avl_delete (source->client_tree, client, NULL); - - /* when switching a client to a different queue, be wary of the - * refbuf it's referring to, if it's http headers then we need - * to write them so don't release it. - */ - if (client->check_buffer != format_check_http_buffer) - { - client_set_queue (client, NULL); - client->check_buffer = format_check_file_buffer; - if (source->con == NULL) - client->intro_offset = -1; - } - avl_insert (dest->pending_tree, (void *)client); + source_move_clients__single(source, source->client_tree, dest->pending_tree, node); count++; } ICECAST_LOG_INFO("passing %lu listeners to \"%s\"", count, dest->mount); From b2cd834db7d302fd8968b32d40e13d94fcd34413 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Tue, 29 Sep 2020 23:51:10 +0000 Subject: [PATCH 2/8] Cleanup: Move lock out of loop as unlock is also outside the loop --- src/source.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/source.c b/src/source.c index 130187a1..9668abb0 100644 --- a/src/source.c +++ b/src/source.c @@ -389,13 +389,13 @@ void source_move_clients(source_t *source, source_t *dest) return; } + /* we need to move the client and pending trees - we must take the + * locks in this order to avoid deadlocks */ + avl_tree_wlock(source->pending_tree); + avl_tree_wlock(source->client_tree); + do { - /* we need to move the client and pending trees - we must take the - * locks in this order to avoid deadlocks */ - avl_tree_wlock(source->pending_tree); - avl_tree_wlock(source->client_tree); - if (source->on_demand == 0 && source->format == NULL) { ICECAST_LOG_INFO("source mount %s is not available", source->mount); From 55acb32b71be0fd5f9d4cbf63185866a82f8c2d0 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Tue, 29 Sep 2020 23:55:13 +0000 Subject: [PATCH 3/8] Cleanup: Corrected code style --- src/source.c | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/src/source.c b/src/source.c index 9668abb0..0fbb6d52 100644 --- a/src/source.c +++ b/src/source.c @@ -370,22 +370,20 @@ static inline void source_move_clients__single(source_t *source, avl_tree *from, void source_move_clients(source_t *source, source_t *dest) { unsigned long count = 0; - if (strcmp (source->mount, dest->mount) == 0) - { + if (strcmp(source->mount, dest->mount) == 0) { ICECAST_LOG_WARN("src and dst are the same \"%s\", skipping", source->mount); return; } /* we don't want the two write locks to deadlock in here */ - thread_mutex_lock (&move_clients_mutex); + thread_mutex_lock(&move_clients_mutex); /* if the destination is not running then we can't move clients */ - avl_tree_wlock (dest->pending_tree); - if (dest->running == 0 && dest->on_demand == 0) - { + avl_tree_wlock(dest->pending_tree); + if (dest->running == 0 && dest->on_demand == 0) { ICECAST_LOG_WARN("destination mount %s not running, unable to move clients ", dest->mount); - avl_tree_unlock (dest->pending_tree); - thread_mutex_unlock (&move_clients_mutex); + avl_tree_unlock(dest->pending_tree); + thread_mutex_unlock(&move_clients_mutex); return; } @@ -394,24 +392,20 @@ void source_move_clients(source_t *source, source_t *dest) avl_tree_wlock(source->pending_tree); avl_tree_wlock(source->client_tree); - do - { - if (source->on_demand == 0 && source->format == NULL) - { + do { + if (source->on_demand == 0 && source->format == NULL) { ICECAST_LOG_INFO("source mount %s is not available", source->mount); break; } - if (source->format && dest->format) - { - if (source->format->type != dest->format->type) - { + + if (source->format && dest->format) { + if (source->format->type != dest->format->type) { ICECAST_LOG_WARN("stream %s and %s are of different types, ignored", source->mount, dest->mount); break; } } - while (1) - { + while (1) { avl_node *node = avl_get_first(source->pending_tree); if (node == NULL) break; @@ -419,30 +413,29 @@ void source_move_clients(source_t *source, source_t *dest) count++; } - while (1) - { + while (1) { avl_node *node = avl_get_first(source->client_tree); if (node == NULL) break; source_move_clients__single(source, source->client_tree, dest->pending_tree, node); count++; } + ICECAST_LOG_INFO("passing %lu listeners to \"%s\"", count, dest->mount); source->listeners = 0; - stats_event (source->mount, "listeners", "0"); - + stats_event(source->mount, "listeners", "0"); } while (0); - avl_tree_unlock (source->pending_tree); - avl_tree_unlock (source->client_tree); + avl_tree_unlock(source->pending_tree); + avl_tree_unlock(source->client_tree); /* see if we need to wake up an on-demand relay */ if (dest->running == 0 && dest->on_demand && count) dest->on_demand_req = 1; - avl_tree_unlock (dest->pending_tree); - thread_mutex_unlock (&move_clients_mutex); + avl_tree_unlock(dest->pending_tree); + thread_mutex_unlock(&move_clients_mutex); } From 4f56236cbc7730bc3cc85d5e45699fee39a5098e Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 30 Sep 2020 17:25:49 +0000 Subject: [PATCH 4/8] Fix: Corrected type for id for source_find_client() --- src/source.c | 2 +- src/source.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/source.c b/src/source.c index 0fbb6d52..b4c31b3e 100644 --- a/src/source.c +++ b/src/source.c @@ -323,7 +323,7 @@ void source_free_source (source_t *source) } -client_t *source_find_client(source_t *source, int id) +client_t *source_find_client(source_t *source, connection_id_t id) { client_t fakeclient; void *result; diff --git a/src/source.h b/src/source.h index adb5f835..07d4252a 100644 --- a/src/source.h +++ b/src/source.h @@ -20,6 +20,7 @@ #include "common/httpp/httpp.h" #include "icecasttypes.h" +#include "connection.h" #include "yp.h" #include "util.h" #include "format.h" @@ -91,7 +92,7 @@ void source_update_settings (ice_config_t *config, source_t *source, mount_proxy void source_clear_source (source_t *source); source_t *source_find_mount(const char *mount); source_t *source_find_mount_raw(const char *mount); -client_t *source_find_client(source_t *source, int id); +client_t *source_find_client(source_t *source, connection_id_t id); int source_compare_sources(void *arg, void *a, void *b); void source_free_source(source_t *source); void source_move_clients (source_t *source, source_t *dest); From e86a46ee4a5562f89b68a92091a26be303a4edf9 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 30 Sep 2020 17:28:22 +0000 Subject: [PATCH 5/8] Update: Improved statistic update logic a bit --- src/source.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/source.c b/src/source.c index b4c31b3e..9ac90234 100644 --- a/src/source.c +++ b/src/source.c @@ -423,8 +423,8 @@ void source_move_clients(source_t *source, source_t *dest) ICECAST_LOG_INFO("passing %lu listeners to \"%s\"", count, dest->mount); - source->listeners = 0; - stats_event(source->mount, "listeners", "0"); + source->listeners -= count; + stats_event_sub(source->mount, "listeners", count); } while (0); avl_tree_unlock(source->pending_tree); From d92c9758a6df2570a5e77190144d59b9f54e651c Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 30 Sep 2020 17:50:26 +0000 Subject: [PATCH 6/8] Feature: Prepare for support to move single clients --- src/admin.c | 2 +- src/slave.c | 2 +- src/source.c | 46 ++++++++++++++++++++++++++++++---------------- src/source.h | 2 +- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/admin.c b/src/admin.c index 4fa253b7..2523771f 100644 --- a/src/admin.c +++ b/src/admin.c @@ -659,7 +659,7 @@ static void command_move_clients(client_t *client, node = admin_build_rootnode(doc, "iceresponse"); xmlDocSetRootElement(doc, node); - source_move_clients(source, dest); + source_move_clients(source, dest, NULL); snprintf(buf, sizeof(buf), "Clients moved from %s to %s", source->mount, dest_source); diff --git a/src/slave.c b/src/slave.c index 145871fb..662a3485 100644 --- a/src/slave.c +++ b/src/slave.c @@ -467,7 +467,7 @@ static void *start_relay_stream (void *arg) fallback_source = source_find_mount(relay->source->fallback_mount); if (fallback_source != NULL) - source_move_clients(relay->source, fallback_source); + source_move_clients(relay->source, fallback_source, NULL); avl_tree_unlock(global.source_tree); } diff --git a/src/source.c b/src/source.c index 9ac90234..8cf771b4 100644 --- a/src/source.c +++ b/src/source.c @@ -367,7 +367,7 @@ static inline void source_move_clients__single(source_t *source, avl_tree *from, * The only lock that should be held when this is called is the * source tree lock */ -void source_move_clients(source_t *source, source_t *dest) +void source_move_clients(source_t *source, source_t *dest, connection_id_t *id) { unsigned long count = 0; if (strcmp(source->mount, dest->mount) == 0) { @@ -405,20 +405,34 @@ void source_move_clients(source_t *source, source_t *dest) } } - while (1) { - avl_node *node = avl_get_first(source->pending_tree); - if (node == NULL) - break; - source_move_clients__single(source, source->pending_tree, dest->pending_tree, node); - count++; - } + if (id) { + client_t fakeclient; + connection_t fakecon; + void *result; - while (1) { - avl_node *node = avl_get_first(source->client_tree); - if (node == NULL) - break; - source_move_clients__single(source, source->client_tree, dest->pending_tree, node); - count++; + fakeclient.con = &fakecon; + fakeclient.con->id = *id; + + if (avl_get_by_key(source->client_tree, &fakeclient, &result) == 0) { + source_move_clients__single(source, source->client_tree, dest->pending_tree, result); + count++; + } + } else { + while (1) { + avl_node *node = avl_get_first(source->pending_tree); + if (node == NULL) + break; + source_move_clients__single(source, source->pending_tree, dest->pending_tree, node); + count++; + } + + while (1) { + avl_node *node = avl_get_first(source->client_tree); + if (node == NULL) + break; + source_move_clients__single(source, source->client_tree, dest->pending_tree, node); + count++; + } } ICECAST_LOG_INFO("passing %lu listeners to \"%s\"", count, dest->mount); @@ -653,7 +667,7 @@ static void source_init (source_t *source) fallback_source = source_find_mount(source->fallback_mount); if (fallback_source) - source_move_clients (fallback_source, source); + source_move_clients(fallback_source, source, NULL); avl_tree_unlock(global.source_tree); } @@ -852,7 +866,7 @@ static void source_shutdown (source_t *source) fallback_source = source_find_mount(source->fallback_mount); if (fallback_source != NULL) - source_move_clients(source, fallback_source); + source_move_clients(source, fallback_source, NULL); avl_tree_unlock(global.source_tree); } diff --git a/src/source.h b/src/source.h index 07d4252a..86b9990a 100644 --- a/src/source.h +++ b/src/source.h @@ -95,7 +95,7 @@ source_t *source_find_mount_raw(const char *mount); client_t *source_find_client(source_t *source, connection_id_t id); int source_compare_sources(void *arg, void *a, void *b); void source_free_source(source_t *source); -void source_move_clients (source_t *source, source_t *dest); +void source_move_clients(source_t *source, source_t *dest, connection_id_t *id); int source_remove_client(void *key); void source_main(source_t *source); void source_recheck_mounts (int update_all); From 81bd709accf16cddbe998de614338453f55e4135 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 30 Sep 2020 19:22:36 +0000 Subject: [PATCH 7/8] Fix: Corrected node vs. client --- src/source.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/source.c b/src/source.c index 8cf771b4..dd9684fc 100644 --- a/src/source.c +++ b/src/source.c @@ -343,9 +343,7 @@ client_t *source_find_client(source_t *source, connection_id_t id) return NULL; } -static inline void source_move_clients__single(source_t *source, avl_tree *from, avl_tree *to, avl_node *node) { - client_t *client = (client_t*)node->key; - +static inline void source_move_clients__single(source_t *source, avl_tree *from, avl_tree *to, client_t *client) { avl_delete(from, client, NULL); /* when switching a client to a different queue, be wary of the @@ -422,7 +420,7 @@ void source_move_clients(source_t *source, source_t *dest, connection_id_t *id) avl_node *node = avl_get_first(source->pending_tree); if (node == NULL) break; - source_move_clients__single(source, source->pending_tree, dest->pending_tree, node); + source_move_clients__single(source, source->pending_tree, dest->pending_tree, node->key); count++; } @@ -430,7 +428,7 @@ void source_move_clients(source_t *source, source_t *dest, connection_id_t *id) avl_node *node = avl_get_first(source->client_tree); if (node == NULL) break; - source_move_clients__single(source, source->client_tree, dest->pending_tree, node); + source_move_clients__single(source, source->client_tree, dest->pending_tree, node->key); count++; } } From 2bf77f20129f3faf2d7fee3bcf8cc0003402b3f3 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 30 Sep 2020 19:47:05 +0000 Subject: [PATCH 8/8] Feature: Support moving individual clients between mounts --- admin/listclients.xsl | 6 +++++- admin/moveclients.xsl | 10 +++++++++- src/admin.c | 13 ++++++++++++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/admin/listclients.xsl b/admin/listclients.xsl index 69689f01..79642763 100644 --- a/admin/listclients.xsl +++ b/admin/listclients.xsl @@ -36,7 +36,11 @@ - Kick + + Kick +   + Move + diff --git a/admin/moveclients.xsl b/admin/moveclients.xsl index 5bdcacba..107a4f0f 100644 --- a/admin/moveclients.xsl +++ b/admin/moveclients.xsl @@ -17,7 +17,15 @@ -

Choose the mountpoint to which you want to move the listeners to:

+ + + +

Choose the mountpoint to which you want to move the listener to:

+
+ +

Choose the mountpoint to which you want to move the listeners to:

+
+