Partition: add client list

For efficient traversal within one partition, e.g. for distributing
partition-local idle events.
This commit is contained in:
Max Kellermann 2020-01-20 13:16:13 +01:00
parent 77271ebc1f
commit 56eaf000a4
6 changed files with 19 additions and 10 deletions

View File

@ -25,6 +25,7 @@
#include "mixer/Volume.hxx" #include "mixer/Volume.hxx"
#include "IdleFlags.hxx" #include "IdleFlags.hxx"
#include "client/Listener.hxx" #include "client/Listener.hxx"
#include "client/Client.hxx"
#include "input/cache/Manager.hxx" #include "input/cache/Manager.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"

View File

@ -32,6 +32,8 @@
#include "Chrono.hxx" #include "Chrono.hxx"
#include "config.h" #include "config.h"
#include <boost/intrusive/list.hpp>
#include <string> #include <string>
#include <memory> #include <memory>
@ -39,6 +41,7 @@ struct Instance;
class MultipleOutputs; class MultipleOutputs;
class SongLoader; class SongLoader;
class ClientListener; class ClientListener;
class Client;
/** /**
* A partition of the Music Player Daemon. It is a separate unit with * A partition of the Music Player Daemon. It is a separate unit with
@ -55,6 +58,11 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
std::unique_ptr<ClientListener> listener; std::unique_ptr<ClientListener> listener;
boost::intrusive::list<Client,
boost::intrusive::base_hook<boost::intrusive::list_base_hook<boost::intrusive::tag<Partition>,
boost::intrusive::link_mode<boost::intrusive::normal_link>>>,
boost::intrusive::constant_time_size<false>> clients;
MaskMonitor global_events; MaskMonitor global_events;
struct playlist playlist; struct playlist playlist;

View File

@ -68,7 +68,9 @@ Client::SetPartition(Partition &new_partition) noexcept
if (partition == &new_partition) if (partition == &new_partition)
return; return;
partition->clients.erase(partition->clients.iterator_to(*this));
partition = &new_partition; partition = &new_partition;
partition->clients.push_back(*this);
/* set idle flags for those subsystems which are specific to /* set idle flags for those subsystems which are specific to
the current partition to force the client to reload its the current partition to force the client to reload its

View File

@ -52,6 +52,8 @@ class BackgroundCommand;
class Client final class Client final
: FullyBufferedSocket, : FullyBufferedSocket,
public boost::intrusive::list_base_hook<boost::intrusive::tag<Partition>,
boost::intrusive::link_mode<boost::intrusive::normal_link>>,
public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> { public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {
TimerEvent timeout_event; TimerEvent timeout_event;

View File

@ -72,6 +72,7 @@ client_new(EventLoop &loop, Partition &partition,
num); num);
client_list.Add(*client); client_list.Add(*client);
partition.clients.push_back(*client);
FormatInfo(client_domain, "[%u] opened from %s", FormatInfo(client_domain, "[%u] opened from %s",
num, remote.c_str()); num, remote.c_str());
@ -81,6 +82,7 @@ void
Client::Close() noexcept Client::Close() noexcept
{ {
partition->instance.client_list->Remove(*this); partition->instance.client_list->Remove(*this);
partition->clients.erase(partition->clients.iterator_to(*this));
if (FullyBufferedSocket::IsDefined()) if (FullyBufferedSocket::IsDefined())
FullyBufferedSocket::Close(); FullyBufferedSocket::Close();

View File

@ -22,8 +22,8 @@
#include "client/Client.hxx" #include "client/Client.hxx"
#include "client/List.hxx" #include "client/List.hxx"
#include "client/Response.hxx" #include "client/Response.hxx"
#include "Instance.hxx"
#include "util/ConstBuffer.hxx" #include "util/ConstBuffer.hxx"
#include "Partition.hxx"
#include <set> #include <set>
#include <string> #include <string>
@ -79,11 +79,7 @@ handle_channels(Client &client, gcc_unused Request args, Response &r)
std::set<std::string> channels; std::set<std::string> channels;
const auto &partition = client.GetPartition(); for (const auto &c : client.GetPartition().clients) {
for (const auto &c : *client.GetInstance().client_list) {
if (&c.GetPartition() != &partition)
continue;
const auto &subscriptions = c.GetSubscriptions(); const auto &subscriptions = c.GetSubscriptions();
channels.insert(subscriptions.begin(), channels.insert(subscriptions.begin(),
subscriptions.end()); subscriptions.end());
@ -125,10 +121,8 @@ handle_send_message(Client &client, Request args, Response &r)
bool sent = false; bool sent = false;
const ClientMessage msg(channel_name, message_text); const ClientMessage msg(channel_name, message_text);
const auto &partition = client.GetPartition(); for (auto &c : client.GetPartition().clients)
for (auto &c : *client.GetInstance().client_list) if (c.PushMessage(msg))
if (&c.GetPartition() == &partition &&
c.PushMessage(msg))
sent = true; sent = true;
if (sent) if (sent)