refactor(map): avoid duplicated khash_t types for values

This reduces the total number of khash_t instantiations from 22 to 8.

Make the khash internal functions take the size of values as a runtime
parameter. This is abstracted with typesafe Map containers which
are still specialized for both key, value type.

Introduce `Set(key)` type for when there is no value.

Refactor shada.c to use Map/Set instead of khash directly.
This requires `map_ref` operation to be more flexible.
Return pointers to both key and value, plus an indicator for new_item.
As a bonus, `map_key` is now redundant.

Instead of Map(cstr_t, FileMarks), use a pointer map as the FileMarks struct is
humongous.

Make `event_strings` actually work like an intern pool instead of wtf it
was doing before.
This commit is contained in:
bfredl
2023-05-14 18:45:56 +02:00
parent 33687f5e87
commit e2fdd53d8c
32 changed files with 408 additions and 462 deletions

View File

@@ -110,7 +110,7 @@ static void log_client_msg(uint64_t channel_id, bool is_request, const char *nam
# define log_server_msg(...)
#endif
static PMap(cstr_t) event_strings = MAP_INIT;
static Set(cstr_t) event_strings = SET_INIT;
static msgpack_sbuffer out_buffer;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -254,14 +254,12 @@ void rpc_subscribe(uint64_t id, char *event)
abort();
}
char *event_string = pmap_get(cstr_t)(&event_strings, event);
if (!event_string) {
event_string = xstrdup(event);
pmap_put(cstr_t)(&event_strings, event_string, event_string);
const char **key_alloc = NULL;
if (set_put_ref(cstr_t, &event_strings, event, &key_alloc)) {
*key_alloc = xstrdup(event);
}
pmap_put(cstr_t)(channel->rpc.subscribed_events, event_string, event_string);
set_put(cstr_t, channel->rpc.subscribed_events, *key_alloc);
}
/// Unsubscribes to event broadcasts
@@ -553,9 +551,9 @@ static void broadcast_event(const char *name, Array args)
kvec_t(Channel *) subscribed = KV_INITIAL_VALUE;
Channel *channel;
map_foreach_value(&channels, channel, {
pmap_foreach_value(&channels, channel, {
if (channel->is_rpc
&& pmap_has(cstr_t)(channel->rpc.subscribed_events, name)) {
&& set_has(cstr_t, channel->rpc.subscribed_events, name)) {
kv_push(subscribed, channel);
}
});
@@ -583,24 +581,12 @@ end:
static void unsubscribe(Channel *channel, char *event)
{
char *event_string = pmap_get(cstr_t)(&event_strings, event);
if (!event_string) {
if (!set_has(cstr_t, &event_strings, event)) {
WLOG("RPC: ch %" PRIu64 ": tried to unsubscribe unknown event '%s'",
channel->id, event);
return;
}
pmap_del(cstr_t)(channel->rpc.subscribed_events, event_string);
map_foreach_value(&channels, channel, {
if (channel->is_rpc
&& pmap_has(cstr_t)(channel->rpc.subscribed_events, event_string)) {
return;
}
});
// Since the string is no longer used by other channels, release it's memory
pmap_del(cstr_t)(&event_strings, event_string);
xfree(event_string);
set_del(cstr_t, channel->rpc.subscribed_events, event);
}
/// Mark rpc state as closed, and release its reference to the channel.
@@ -630,13 +616,7 @@ void rpc_free(Channel *channel)
unpacker_teardown(channel->rpc.unpacker);
xfree(channel->rpc.unpacker);
// Unsubscribe from all events
char *event_string;
map_foreach_value(channel->rpc.subscribed_events, event_string, {
unsubscribe(channel, event_string);
});
pmap_destroy(cstr_t)(channel->rpc.subscribed_events);
set_destroy(cstr_t, channel->rpc.subscribed_events);
kv_destroy(channel->rpc.call_stack);
api_free_dictionary(channel->rpc.info);
}
@@ -734,3 +714,12 @@ const char *rpc_client_name(Channel *chan)
return NULL;
}
void rpc_free_all_mem(void)
{
cstr_t key;
set_foreach(&event_strings, key, {
xfree((void *)key);
});
set_destroy(cstr_t, &event_strings);
}

View File

@@ -31,7 +31,7 @@ typedef struct {
} RequestEvent;
typedef struct {
PMap(cstr_t) subscribed_events[1];
Set(cstr_t) subscribed_events[1];
bool closed;
Unpacker *unpacker;
uint32_t next_request_id;