lib: add meta_hash to connection, eliminate hash_offt

With a meta_hash at each connection (similar to easy handle, let
multi_ev.c store its pollsets as meta data, no longer needing its own
hashes.

This eliminates the last use of Curl_hash_offt. Remove it.

Closes #17095
This commit is contained in:
Stefan Eissing 2025-04-18 11:03:29 +02:00 committed by Daniel Stenberg
parent 1d66a769d7
commit 657aae79c0
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
18 changed files with 126 additions and 343 deletions

View file

@ -149,40 +149,3 @@ Called repeatedly, it iterates over all the entries in the hash table.
Note: it only guarantees functionality if the hash table remains untouched
during its iteration.
# `curl_off_t` dedicated hash functions
## `Curl_hash_offt_init`
~~~c
void Curl_hash_offt_init(struct Curl_hash *h,
size_t slots,
Curl_hash_dtor dtor);
~~~
Initializes a hash table for `curl_off_t` values. Pass in desired number of
`slots` and `dtor` function.
## `Curl_hash_offt_set`
~~~c
void *Curl_hash_offt_set(struct Curl_hash *h, curl_off_t id, void *elem);
~~~
Associate a custom `elem` pointer with the given `id`.
## `Curl_hash_offt_remove`
~~~c
int Curl_hash_offt_remove(struct Curl_hash *h, curl_off_t id);
~~~
Remove the `id` from the hash.
## `Curl_hash_offt_get`
~~~c
void *Curl_hash_offt_get(struct Curl_hash *h, curl_off_t id);
~~~
Get the pointer associated with the specified `id`.

View file

@ -126,6 +126,3 @@ Iterating a sparse bitset works the same as for bitset and table.
At last, there are places in libcurl such as the HTTP/2 and HTTP/3 protocol implementations that need
to store their own data related to a transfer. `uint_hash` allows then to associate an unsigned int,
e.g. the transfer's `mid`, to their own data.
This is just a variation of `hash_offt` that can associate data with a `connection_id`. Which
is a specialization of the generic `Curl_hash`.

View file

@ -164,7 +164,6 @@ LIB_CFILES = \
getinfo.c \
gopher.c \
hash.c \
hash_offt.c \
headers.c \
hmac.c \
hostip.c \
@ -237,6 +236,7 @@ LIB_CFILES = \
timeval.c \
transfer.c \
uint-bset.c \
uint-hash.c \
uint-spbset.c \
uint-table.c \
url.c \
@ -314,7 +314,6 @@ LIB_HFILES = \
getinfo.h \
gopher.h \
hash.h \
hash_offt.h \
headers.h \
hostip.h \
hsts.h \
@ -380,6 +379,7 @@ LIB_HFILES = \
timeval.h \
transfer.h \
uint-bset.h \
uint-hash.h \
uint-spbset.h \
uint-table.h \
url.h \

View file

@ -249,7 +249,7 @@ static void doh_probe_done(struct Curl_easy *data,
Curl_dyn_len(&doh_req->resp_body));
Curl_dyn_free(&doh_req->resp_body);
}
Curl_meta_clear(doh, CURL_EZM_DOH_PROBE);
Curl_meta_remove(doh, CURL_EZM_DOH_PROBE);
}
if(result)

View file

@ -1419,7 +1419,7 @@ CURLcode Curl_meta_set(struct Curl_easy *data, const char *key,
return CURLE_OK;
}
void Curl_meta_clear(struct Curl_easy *data, const char *key)
void Curl_meta_remove(struct Curl_easy *data, const char *key)
{
Curl_hash_delete(&data->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
}

View file

@ -29,7 +29,7 @@
#include <nghttp2/nghttp2.h>
#include "urldata.h"
#include "bufq.h"
#include "hash_offt.h"
#include "uint-hash.h"
#include "http1.h"
#include "http2.h"
#include "http.h"

View file

@ -27,6 +27,7 @@
#include <curl/curl.h>
#include "urldata.h"
#include "url.h"
#include "cfilters.h"
#include "curl_trc.h"
#include "multiif.h"
@ -57,7 +58,7 @@ static void mev_in_callback(struct Curl_multi *multi, bool value)
*/
struct mev_sh_entry {
struct uint_spbset xfers; /* bitset of transfers `mid`s on this socket */
struct Curl_hash_offt conns; /* hash of connections using this socket */
struct connectdata *conn; /* connection using this socket or NULL */
void *user_data; /* libcurl app data via curl_multi_assign() */
unsigned int action; /* CURL_POLL_IN/CURL_POLL_OUT we last told the
* libcurl application to watch out for */
@ -84,7 +85,6 @@ static void mev_sh_entry_dtor(void *freethis)
{
struct mev_sh_entry *entry = (struct mev_sh_entry *)freethis;
Curl_uint_spbset_destroy(&entry->xfers);
Curl_hash_offt_destroy(&entry->conns);
free(entry);
}
@ -117,7 +117,6 @@ mev_sh_entry_add(struct Curl_hash *sh, curl_socket_t s)
return NULL; /* major failure */
Curl_uint_spbset_init(&check->xfers);
Curl_hash_offt_init(&check->conns, CURL_MEV_CONN_HASH_SIZE, NULL);
/* make/add new hash entry */
if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
@ -136,7 +135,7 @@ static void mev_sh_entry_kill(struct Curl_multi *multi, curl_socket_t s)
static size_t mev_sh_entry_user_count(struct mev_sh_entry *e)
{
return Curl_uint_spbset_count(&e->xfers) + Curl_hash_offt_count(&e->conns);
return Curl_uint_spbset_count(&e->xfers) + (e->conn ? 1 : 0);
}
static bool mev_sh_entry_xfer_known(struct mev_sh_entry *e,
@ -148,7 +147,7 @@ static bool mev_sh_entry_xfer_known(struct mev_sh_entry *e,
static bool mev_sh_entry_conn_known(struct mev_sh_entry *e,
struct connectdata *conn)
{
return !!Curl_hash_offt_get(&e->conns, conn->connection_id);
return (e->conn == conn);
}
static bool mev_sh_entry_xfer_add(struct mev_sh_entry *e,
@ -164,7 +163,11 @@ static bool mev_sh_entry_conn_add(struct mev_sh_entry *e,
{
/* detect weird values */
DEBUGASSERT(mev_sh_entry_user_count(e) < 100000);
return !!Curl_hash_offt_set(&e->conns, conn->connection_id, conn);
DEBUGASSERT(!e->conn);
if(e->conn)
return FALSE;
e->conn = conn;
return TRUE;
}
@ -180,7 +183,12 @@ static bool mev_sh_entry_xfer_remove(struct mev_sh_entry *e,
static bool mev_sh_entry_conn_remove(struct mev_sh_entry *e,
struct connectdata *conn)
{
return Curl_hash_offt_remove(&e->conns, conn->connection_id);
DEBUGASSERT(e->conn == conn);
if(e->conn == conn) {
e->conn = NULL;
return TRUE;
}
return FALSE;
}
/* Purge any information about socket `s`.
@ -344,11 +352,11 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi,
return CURLM_OUT_OF_MEMORY;
}
CURL_TRC_M(data, "ev entry fd=%" FMT_SOCKET_T ", added %s #%" FMT_OFF_T
", total=%u/%zu (xfer/conn)", s,
", total=%u/%d (xfer/conn)", s,
conn ? "connection" : "transfer",
conn ? conn->connection_id : data->mid,
Curl_uint_spbset_count(&entry->xfers),
Curl_hash_offt_count(&entry->conns));
entry->conn ? 1 : 0);
}
else {
for(j = 0; j < prev_ps->num; j++) {
@ -414,9 +422,9 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi,
if(mresult)
return mresult;
CURL_TRC_M(data, "ev entry fd=%" FMT_SOCKET_T ", removed transfer, "
"total=%u/%zu (xfer/conn)", s,
"total=%u/%d (xfer/conn)", s,
Curl_uint_spbset_count(&entry->xfers),
Curl_hash_offt_count(&entry->conns));
entry->conn ? 1 : 0);
}
else {
mresult = mev_forget_socket(multi, data, s, "last user gone");
@ -430,15 +438,22 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi,
return CURLM_OK;
}
static void mev_pollset_dtor(void *key, size_t klen, void *entry)
{
(void)key;
(void)klen;
free(entry);
}
static struct easy_pollset*
mev_add_new_conn_pollset(struct Curl_hash_offt *h, curl_off_t id)
mev_add_new_conn_pollset(struct connectdata *conn)
{
struct easy_pollset *ps;
ps = calloc(1, sizeof(*ps));
if(!ps)
return NULL;
if(!Curl_hash_offt_set(h, id, ps)) {
if(Curl_conn_meta_set(conn, CURL_META_MEV_POLLSET, ps, mev_pollset_dtor)) {
free(ps);
return NULL;
}
@ -446,14 +461,14 @@ mev_add_new_conn_pollset(struct Curl_hash_offt *h, curl_off_t id)
}
static struct easy_pollset*
mev_add_new_xfer_pollset(struct uint_hash *h, unsigned int id)
mev_add_new_xfer_pollset(struct Curl_easy *data)
{
struct easy_pollset *ps;
ps = calloc(1, sizeof(*ps));
if(!ps)
return NULL;
if(!Curl_uint_hash_set(h, id, ps)) {
if(Curl_meta_set(data, CURL_META_MEV_POLLSET, ps, mev_pollset_dtor)) {
free(ps);
return NULL;
}
@ -461,16 +476,14 @@ mev_add_new_xfer_pollset(struct uint_hash *h, unsigned int id)
}
static struct easy_pollset *
mev_get_last_pollset(struct Curl_multi *multi,
struct Curl_easy *data,
mev_get_last_pollset(struct Curl_easy *data,
struct connectdata *conn)
{
if(data) {
if(conn)
return Curl_hash_offt_get(&multi->ev.conn_pollsets,
conn->connection_id);
return Curl_conn_meta_get(conn, CURL_META_MEV_POLLSET);
else if(data)
return Curl_uint_hash_get(&multi->ev.xfer_pollsets, data->mid);
return Curl_meta_get(data, CURL_META_MEV_POLLSET);
}
return NULL;
}
@ -494,15 +507,13 @@ static CURLMcode mev_assess(struct Curl_multi *multi,
struct easy_pollset ps, *last_ps;
mev_init_cur_pollset(&ps, data, conn);
last_ps = mev_get_last_pollset(multi, data, conn);
last_ps = mev_get_last_pollset(data, conn);
if(!last_ps && ps.num) {
if(conn)
last_ps = mev_add_new_conn_pollset(&multi->ev.conn_pollsets,
conn->connection_id);
last_ps = mev_add_new_conn_pollset(conn);
else
last_ps = mev_add_new_xfer_pollset(&multi->ev.xfer_pollsets,
data->mid);
last_ps = mev_add_new_xfer_pollset(data);
if(!last_ps)
return CURLM_OUT_OF_MEMORY;
}
@ -588,7 +599,7 @@ void Curl_multi_ev_expire_xfers(struct Curl_multi *multi,
while(Curl_uint_spbset_next(&entry->xfers, mid, &mid));
}
if(Curl_hash_offt_count(&entry->conns))
if(entry->conn)
*run_cpool = TRUE;
}
}
@ -605,7 +616,7 @@ void Curl_multi_ev_xfer_done(struct Curl_multi *multi,
DEBUGASSERT(!data->conn); /* transfer should have been detached */
if(data != multi->admin) {
(void)mev_assess(multi, data, NULL);
Curl_uint_hash_remove(&multi->ev.xfer_pollsets, data->mid);
Curl_meta_remove(data, CURL_META_MEV_POLLSET);
}
}
@ -614,36 +625,18 @@ void Curl_multi_ev_conn_done(struct Curl_multi *multi,
struct connectdata *conn)
{
(void)mev_assess(multi, data, conn);
Curl_hash_offt_remove(&multi->ev.conn_pollsets, conn->connection_id);
Curl_conn_meta_remove(conn, CURL_META_MEV_POLLSET);
}
#define CURL_MEV_PS_HASH_SLOTS (991) /* nice prime */
static void mev_hash_conn_pollset_free(curl_off_t id, void *entry)
{
(void)id;
free(entry);
}
static void mev_hash_xfer_pollset_free(unsigned int id, void *entry)
{
(void)id;
free(entry);
}
void Curl_multi_ev_init(struct Curl_multi *multi, size_t hashsize)
{
Curl_hash_init(&multi->ev.sh_entries, hashsize, mev_sh_entry_hash,
mev_sh_entry_compare, mev_sh_entry_dtor);
Curl_uint_hash_init(&multi->ev.xfer_pollsets,
CURL_MEV_PS_HASH_SLOTS, mev_hash_xfer_pollset_free);
Curl_hash_offt_init(&multi->ev.conn_pollsets,
CURL_MEV_PS_HASH_SLOTS, mev_hash_conn_pollset_free);
}
void Curl_multi_ev_cleanup(struct Curl_multi *multi)
{
Curl_hash_destroy(&multi->ev.sh_entries);
Curl_uint_hash_destroy(&multi->ev.xfer_pollsets);
Curl_hash_offt_destroy(&multi->ev.conn_pollsets);
}

View file

@ -25,17 +25,17 @@
***************************************************************************/
#include "hash.h"
#include "hash_offt.h"
struct Curl_easy;
struct Curl_multi;
struct easy_pollset;
struct uint_bset;
/* meta key for event pollset at easy handle or connection */
#define CURL_META_MEV_POLLSET "meta:mev:ps"
struct curl_multi_ev {
struct Curl_hash sh_entries;
struct uint_hash xfer_pollsets;
struct Curl_hash_offt conn_pollsets;
};
/* Setup/teardown of multi event book-keeping. */

View file

@ -26,207 +26,12 @@
#include <curl/curl.h>
#include "hash_offt.h"
#include "uint-hash.h"
#include "curl_memory.h"
/* The last #include file should be: */
#include "memdebug.h"
/* random patterns for API verification */
#ifdef DEBUGBUILD
#define CURL_HASHOFFTINIT 0x7117e781
#endif
static size_t hash_offt_hash(curl_off_t id, size_t slots)
{
return (size_t)((id >= 0) ? (id % slots) : (-id % slots));
}
struct Curl_hash_offt_entry {
curl_off_t id;
struct Curl_hash_offt_entry *next;
void *value;
};
void Curl_hash_offt_init(struct Curl_hash_offt *h,
size_t slots,
Curl_hash_offt_dtor *dtor)
{
DEBUGASSERT(h);
DEBUGASSERT(slots);
h->table = NULL;
h->dtor = dtor;
h->size = 0;
h->slots = slots;
#ifdef DEBUGBUILD
h->init = CURL_HASHOFFTINIT;
#endif
}
static struct Curl_hash_offt_entry *
hash_offt_mk_entry(curl_off_t id, void *value)
{
struct Curl_hash_offt_entry *e;
/* allocate the struct for the hash entry */
e = malloc(sizeof(*e));
if(e) {
e->id = id;
e->next = NULL;
e->value = value;
}
return e;
}
static void hash_offt_entry_clear(struct Curl_hash_offt *h,
struct Curl_hash_offt_entry *e)
{
DEBUGASSERT(h);
DEBUGASSERT(e);
if(e->value) {
if(h->dtor)
h->dtor(e->id, e->value);
e->value = NULL;
}
}
static void hash_offt_entry_destroy(struct Curl_hash_offt *h,
struct Curl_hash_offt_entry *e)
{
hash_offt_entry_clear(h, e);
free(e);
}
static void hash_offt_entry_unlink(struct Curl_hash_offt *h,
struct Curl_hash_offt_entry **he_anchor,
struct Curl_hash_offt_entry *he)
{
*he_anchor = he->next;
--h->size;
}
static void hash_offtr_elem_link(struct Curl_hash_offt *h,
struct Curl_hash_offt_entry **he_anchor,
struct Curl_hash_offt_entry *he)
{
he->next = *he_anchor;
*he_anchor = he;
++h->size;
}
#define CURL_HASH_OFFT_SLOT(h,id) h->table[hash_offt_hash(id, h->slots)]
#define CURL_HASH_OFFT_SLOT_ADDR(h,id) &CURL_HASH_OFFT_SLOT(h,id)
bool Curl_hash_offt_set(struct Curl_hash_offt *h, curl_off_t id, void *value)
{
struct Curl_hash_offt_entry *he, **slot;
DEBUGASSERT(h);
DEBUGASSERT(h->slots);
DEBUGASSERT(h->init == CURL_HASHOFFTINIT);
if(!h->table) {
h->table = calloc(h->slots, sizeof(*he));
if(!h->table)
return FALSE; /* OOM */
}
slot = CURL_HASH_OFFT_SLOT_ADDR(h, id);
for(he = *slot; he; he = he->next) {
if(he->id == id) {
/* existing key entry, overwrite by clearing old pointer */
hash_offt_entry_clear(h, he);
he->value = value;
return TRUE;
}
}
he = hash_offt_mk_entry(id, value);
if(!he)
return FALSE; /* OOM */
hash_offtr_elem_link(h, slot, he);
return TRUE;
}
bool Curl_hash_offt_remove(struct Curl_hash_offt *h, curl_off_t id)
{
DEBUGASSERT(h);
DEBUGASSERT(h->slots);
DEBUGASSERT(h->init == CURL_HASHOFFTINIT);
if(h->table) {
struct Curl_hash_offt_entry *he, **he_anchor;
he_anchor = CURL_HASH_OFFT_SLOT_ADDR(h, id);
while(*he_anchor) {
he = *he_anchor;
if(id == he->id) {
hash_offt_entry_unlink(h, he_anchor, he);
hash_offt_entry_destroy(h, he);
return TRUE;
}
he_anchor = &he->next;
}
}
return FALSE;
}
void *Curl_hash_offt_get(struct Curl_hash_offt *h, curl_off_t id)
{
DEBUGASSERT(h);
DEBUGASSERT(h->init == CURL_HASHOFFTINIT);
if(h->table) {
struct Curl_hash_offt_entry *he;
DEBUGASSERT(h->slots);
he = CURL_HASH_OFFT_SLOT(h, id);
while(he) {
if(id == he->id) {
return he->value;
}
he = he->next;
}
}
return NULL;
}
void Curl_hash_offt_clear(struct Curl_hash_offt *h)
{
if(h && h->table) {
struct Curl_hash_offt_entry *he, **he_anchor;
size_t i;
DEBUGASSERT(h->init == CURL_HASHOFFTINIT);
for(i = 0; i < h->slots; ++i) {
he_anchor = &h->table[i];
while(*he_anchor) {
he = *he_anchor;
hash_offt_entry_unlink(h, he_anchor, he);
hash_offt_entry_destroy(h, he);
}
}
}
}
void
Curl_hash_offt_destroy(struct Curl_hash_offt *h)
{
DEBUGASSERT(h->init == CURL_HASHOFFTINIT);
if(h->table) {
Curl_hash_offt_clear(h);
Curl_safefree(h->table);
}
DEBUGASSERT(h->size == 0);
h->slots = 0;
}
size_t Curl_hash_offt_count(struct Curl_hash_offt *h)
{
DEBUGASSERT(h->init == CURL_HASHOFFTINIT);
return h->size;
}
/* FOR NOW: basically a duplicate of Curl_hash_offt, BUT we hope to
* eliminate the offt variant in the near future. */
/* random patterns for API verification */
#ifdef DEBUGBUILD
#define CURL_UINTHASHINIT 0x7117e779
@ -311,7 +116,7 @@ static void uint_hash_elem_link(struct uint_hash *h,
}
#define CURL_UINT_HASH_SLOT(h,id) h->table[uint_hash_hash(id, h->slots)]
#define CURL_UINT_HASH_SLOT_ADDR(h,id) &CURL_HASH_OFFT_SLOT(h,id)
#define CURL_UINT_HASH_SLOT_ADDR(h,id) &CURL_UINT_HASH_SLOT(h,id)
bool Curl_uint_hash_set(struct uint_hash *h, unsigned int id, void *value)
{
@ -401,8 +206,12 @@ static void uint_hash_clear(struct uint_hash *h)
}
}
void
Curl_uint_hash_destroy(struct uint_hash *h)
void Curl_uint_hash_clear(struct uint_hash *h)
{
uint_hash_clear(h);
}
void Curl_uint_hash_destroy(struct uint_hash *h)
{
DEBUGASSERT(h->init == CURL_UINTHASHINIT);
if(h->table) {

View file

@ -1,5 +1,5 @@
#ifndef HEADER_CURL_HASH_OFFT_H
#define HEADER_CURL_HASH_OFFT_H
#ifndef HEADER_CURL_UINT_HASH_H
#define HEADER_CURL_UINT_HASH_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@ -30,32 +30,6 @@
#include "llist.h"
struct Curl_hash_offt_entry;
typedef void Curl_hash_offt_dtor(curl_off_t id, void *value);
/* Hash for `curl_off_t` as key */
struct Curl_hash_offt {
struct Curl_hash_offt_entry **table;
Curl_hash_offt_dtor *dtor;
size_t slots;
size_t size;
#ifdef DEBUGBUILD
int init;
#endif
};
void Curl_hash_offt_init(struct Curl_hash_offt *h,
size_t slots,
Curl_hash_offt_dtor *dtor);
void Curl_hash_offt_destroy(struct Curl_hash_offt *h);
bool Curl_hash_offt_set(struct Curl_hash_offt *h, curl_off_t id, void *value);
bool Curl_hash_offt_remove(struct Curl_hash_offt *h, curl_off_t id);
void *Curl_hash_offt_get(struct Curl_hash_offt *h, curl_off_t id);
void Curl_hash_offt_clear(struct Curl_hash_offt *h);
size_t Curl_hash_offt_count(struct Curl_hash_offt *h);
/* A version with unsigned int as key */
typedef void Curl_uint_hash_dtor(unsigned int id, void *value);
struct uint_hash_entry;
@ -76,6 +50,7 @@ void Curl_uint_hash_init(struct uint_hash *h,
unsigned int slots,
Curl_uint_hash_dtor *dtor);
void Curl_uint_hash_destroy(struct uint_hash *h);
void Curl_uint_hash_clear(struct uint_hash *h);
bool Curl_uint_hash_set(struct uint_hash *h, unsigned int id, void *value);
bool Curl_uint_hash_remove(struct uint_hash *h, unsigned int id);
@ -90,4 +65,4 @@ void Curl_uint_hash_visit(struct uint_hash *h,
Curl_uint_hash_visit_cb *cb,
void *user_data);
#endif /* HEADER_CURL_HASH_OFFT_H */
#endif /* HEADER_CURL_UINT_HASH_H */

View file

@ -601,6 +601,7 @@ void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
#endif
Curl_safefree(conn->destination);
Curl_uint_spbset_destroy(&conn->xfers_attached);
Curl_hash_destroy(&conn->meta_hash);
free(conn); /* free all the connection oriented data */
}
@ -3322,6 +3323,15 @@ static void reuse_conn(struct Curl_easy *data,
Curl_conn_free(data, temp);
}
static void conn_meta_freeentry(void *p)
{
(void)p;
/* Will always be FALSE. Cannot use a 0 assert here since compilers
* are not in agreement if they then want a NORETURN attribute or
* not. *sigh* */
DEBUGASSERT(p == NULL);
}
/**
* create_conn() sets up a new connectdata struct, or reuses an already
* existing one, and resolves hostname.
@ -3377,6 +3387,9 @@ static CURLcode create_conn(struct Curl_easy *data,
*in_connect = conn;
/* Do the unfailable inits first, before checks that may early return */
Curl_hash_init(&conn->meta_hash, 23,
Curl_hash_str, Curl_str_key_compare, conn_meta_freeentry);
/* GSSAPI related inits */
Curl_sec_conn_init(conn);
@ -3944,3 +3957,23 @@ void Curl_data_priority_clear_state(struct Curl_easy *data)
}
#endif /* defined(USE_HTTP2) || defined(USE_HTTP3) */
CURLcode Curl_conn_meta_set(struct connectdata *conn, const char *key,
void *meta_data, Curl_meta_dtor *meta_dtor)
{
if(!Curl_hash_add2(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1,
meta_data, meta_dtor)) {
meta_dtor(CURL_UNCONST(key), strlen(key) + 1, meta_data);
}
return CURLE_OK;
}
void Curl_conn_meta_remove(struct connectdata *conn, const char *key)
{
Curl_hash_delete(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
}
void *Curl_conn_meta_get(struct connectdata *conn, const char *key)
{
return Curl_hash_pick(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1);
}

View file

@ -54,10 +54,18 @@ typedef void Curl_meta_dtor(void *key, size_t key_len, void *meta_data);
* Takes ownership of `meta_data` and destroys it when the call fails. */
CURLcode Curl_meta_set(struct Curl_easy *data, const char *key,
void *meta_data, Curl_meta_dtor *meta_dtor);
void Curl_meta_clear(struct Curl_easy *data, const char *key);
void Curl_meta_remove(struct Curl_easy *data, const char *key);
void *Curl_meta_get(struct Curl_easy *data, const char *key);
void Curl_meta_reset(struct Curl_easy *data);
/* Set connection meta data for the key. Any existing entry for that
* key will be destroyed.
* Takes ownership of `meta_data` and destroys it when the call fails. */
CURLcode Curl_conn_meta_set(struct connectdata *conn, const char *key,
void *meta_data, Curl_meta_dtor *meta_dtor);
void Curl_conn_meta_remove(struct connectdata *conn, const char *key);
void *Curl_conn_meta_get(struct connectdata *conn, const char *key);
/* Get protocol handler for a URI scheme
* @param scheme URI scheme, case-insensitive
* @return NULL of handler not found

View file

@ -152,7 +152,6 @@ typedef unsigned int curl_prot_t;
#include "http_chunks.h" /* for the structs and enum stuff */
#include "hostip.h"
#include "hash.h"
#include "hash_offt.h"
#include "splay.h"
#include "dynbuf.h"
#include "dynhds.h"
@ -750,6 +749,12 @@ struct connectdata {
track the connections in the log output */
char *destination; /* string carrying normalized hostname+port+scope */
/* `meta_hash` is a general key-value store for implementations
* with the lifetime of the connection.
* Elements need to be added with their own destructor to be invoked when
* the connection is cleaned up (see Curl_hash_add2()).*/
struct Curl_hash meta_hash;
/* 'dns_entry' is the particular host we use. This points to an entry in the
DNS cache and it will not get pruned while locked. It gets unlocked in
multi_done(). This entry will be NULL if the connection is reused as then

View file

@ -28,7 +28,7 @@
#include "../urldata.h"
#include "../hash.h"
#include "../hash_offt.h"
#include "../uint-hash.h"
#include "../timeval.h"
#include "../multiif.h"
#include "../sendf.h"

View file

@ -47,7 +47,7 @@
#endif
#include "../urldata.h"
#include "../hash_offt.h"
#include "../uint-hash.h"
#include "../sendf.h"
#include "../strdup.h"
#include "../rand.h"

View file

@ -29,7 +29,7 @@
#include <openssl/err.h>
#include <openssl/ssl.h>
#include "../bufq.h"
#include "../hash_offt.h"
#include "../uint-hash.h"
#include "../urldata.h"
#include "../cfilters.h"
#include "../cf-socket.h"

View file

@ -2,7 +2,7 @@
<info>
<keywords>
unittest
hash
uint_hash
</keywords>
</info>
@ -16,7 +16,7 @@ none
unittest
</features>
<name>
Internal hash_offt create/add/destroy testing, exercising clean functions
Internal uint_hash create/add/destroy testing, exercising clean functions
</name>
</client>
</testcase>

View file

@ -25,13 +25,13 @@
#include "curlx.h"
#include "hash_offt.h"
#include "uint-hash.h"
#include "memdebug.h" /* LAST include file */
static struct Curl_hash_offt hash_static;
static struct uint_hash hash_static;
static void mydtor(curl_off_t id, void *elem)
static void mydtor(unsigned int id, void *elem)
{
int *ptr = (int *)elem;
(void)id;
@ -40,13 +40,13 @@ static void mydtor(curl_off_t id, void *elem)
static CURLcode unit_setup(void)
{
Curl_hash_offt_init(&hash_static, 15, mydtor);
Curl_uint_hash_init(&hash_static, 15, mydtor);
return CURLE_OK;
}
static void unit_stop(void)
{
Curl_hash_offt_destroy(&hash_static);
Curl_uint_hash_destroy(&hash_static);
}
UNITTEST_START
@ -54,34 +54,34 @@ UNITTEST_START
int *value2;
bool ok;
curl_off_t key = 20;
curl_off_t key2 = 25;
unsigned int key = 20;
unsigned int key2 = 25;
value = malloc(sizeof(int));
abort_unless(value != NULL, "Out of memory");
*value = 199;
ok = Curl_hash_offt_set(&hash_static, key, value);
ok = Curl_uint_hash_set(&hash_static, key, value);
if(!ok)
free(value);
abort_unless(ok, "insertion into hash failed");
v = Curl_hash_offt_get(&hash_static, key);
v = Curl_uint_hash_get(&hash_static, key);
abort_unless(v == value, "lookup present entry failed");
v = Curl_hash_offt_get(&hash_static, key2);
v = Curl_uint_hash_get(&hash_static, key2);
abort_unless(!v, "lookup missing entry failed");
Curl_hash_offt_clear(&hash_static);
Curl_uint_hash_clear(&hash_static);
/* Attempt to add another key/value pair */
value2 = malloc(sizeof(int));
abort_unless(value2 != NULL, "Out of memory");
*value2 = 204;
ok = Curl_hash_offt_set(&hash_static, key2, value2);
ok = Curl_uint_hash_set(&hash_static, key2, value2);
if(!ok)
free(value2);
abort_unless(ok, "insertion into hash failed");
v = Curl_hash_offt_get(&hash_static, key2);
v = Curl_uint_hash_get(&hash_static, key2);
abort_unless(v == value2, "lookup present entry failed");
v = Curl_hash_offt_get(&hash_static, key);
v = Curl_uint_hash_get(&hash_static, key);
abort_unless(!v, "lookup missing entry failed");
UNITTEST_STOP