mirror of
https://github.com/curl/curl.git
synced 2026-04-14 23:51:42 +03:00
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:
parent
1d66a769d7
commit
657aae79c0
18 changed files with 126 additions and 343 deletions
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
@ -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 */
|
||||
33
lib/url.c
33
lib/url.c
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
10
lib/url.h
10
lib/url.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue