mirror of
https://github.com/curl/curl.git
synced 2026-08-25 00:03:33 +03:00
multi: timeout improvements
- Move expire timeout code from multi into splay.c - keep a "time_base" timestamp to calculate timediff_t for actual timeout values. Unfortunately this means our timeouts will go wrong after ~500,000 years of continuous operations... - use timediff_t as key in splay instead of curltime - use timediff_t in transfers expire times instead of curltime - re-comment splay.c for better understanding how it works - replace splay nodes double-linked "same" list with a single link, we almost never have duplicate keys - keep transfer `mid` in splay nodes instead of the transfer pointer - keep registered bit in splay node for tracking instead of separate bit in transfer - adapt unit1309.c to changes in timediff_t and mid Closes #22584
This commit is contained in:
parent
d854ab4673
commit
3d6d93a6be
19 changed files with 600 additions and 458 deletions
|
|
@ -17,7 +17,7 @@ it automatically rebalances itself in each operation.
|
|||
|
||||
## libcurl use
|
||||
|
||||
libcurl adds fixed timeout expiry timestamps to the splay tree, and is meant
|
||||
libcurl adds fixed timeout expiry `timediff_t` to the splay tree, and is meant
|
||||
to scale up to holding a huge amount of pending timeouts with decent
|
||||
performance.
|
||||
|
||||
|
|
@ -26,19 +26,25 @@ The splay tree is used to:
|
|||
1. figure out the next timeout expiry value closest in time
|
||||
2. iterate over timeouts that already have expired
|
||||
|
||||
This splay tree rebalances itself based on the time value.
|
||||
This splay tree rebalances itself based on the timeout value.
|
||||
|
||||
Each node in the splay tree points to a `struct Curl_easy`. Each `Curl_easy`
|
||||
struct is represented only once in the tree. To still allow each easy handle
|
||||
to have a large number of timeouts per handle, each handle has a sorted linked
|
||||
list of pending timeouts. Only the handle's timeout that is closest to expire
|
||||
Each node in the splay tree carries a `uint32_t id`. This is set to the
|
||||
`mid`, the unique transfer identifier in a multi handle. Each transfer
|
||||
is added only once in the tree. To still allow each transfer
|
||||
to have a large number of timeouts per handle, each handle has a sorted list
|
||||
of pending timeouts. Only the handle's timeout that is closest to expire
|
||||
is the timestamp used for the splay tree node.
|
||||
|
||||
When a specific easy handle's timeout expires, the node gets removed from the
|
||||
splay tree and from the handle's linked list of timeouts. The next timeout for
|
||||
splay tree and from the handle's list of timeouts. The next timeout for
|
||||
that handle is then first in line and becomes the new timeout value as the
|
||||
node is re-added to the splay.
|
||||
|
||||
To convert the `timediff_t` is the splay to the correct timestamps, the
|
||||
multi handle carries a "base timestamp", set once when created, and the
|
||||
timeout values are calculated relative to that. This works for about
|
||||
500,000 years of continued operation of a multi handle.
|
||||
|
||||
## `Curl_splay`
|
||||
|
||||
~~~c
|
||||
|
|
@ -50,15 +56,16 @@ Rearranges the tree `t` after the provide time `i`.
|
|||
## `Curl_splayinsert`
|
||||
|
||||
~~~c
|
||||
struct Curl_tree *Curl_splayinsert(struct curltime key,
|
||||
struct Curl_tree *Curl_splayinsert(timediff_t key,
|
||||
struct Curl_tree *t,
|
||||
struct Curl_tree *node);
|
||||
struct Curl_tree *node,
|
||||
uint32_t id);
|
||||
~~~
|
||||
|
||||
This function inserts a new `node` in the tree, using the given `key`
|
||||
timestamp. The `node` struct has a field called `->payload` that can be set to
|
||||
point to anything. libcurl sets this to the `struct Curl_easy` handle that is
|
||||
associated with the timeout value set in `key`.
|
||||
timeout. The `node` struct has a field called `->id` which is set to
|
||||
the passed `id`. libcurl sets this to the transfer's `mid`, the unique
|
||||
identifier in a multi handle.
|
||||
|
||||
The splay insert function does not allocate any memory, it assumes the caller
|
||||
has that arranged.
|
||||
|
|
@ -68,12 +75,12 @@ It returns a pointer to the new tree root.
|
|||
## `Curl_splaygetbest`
|
||||
|
||||
~~~c
|
||||
struct Curl_tree *Curl_splaygetbest(struct curltime key,
|
||||
struct Curl_tree *Curl_splaygetbest(timediff_t key,
|
||||
struct Curl_tree *tree,
|
||||
struct Curl_tree **removed);
|
||||
~~~
|
||||
|
||||
If there is a node in the `tree` that has a time value that is less than the
|
||||
If there is a node in the `tree` that has a timeout that is less than the
|
||||
provided `key`, this function removes that node from the tree and provides it
|
||||
in the `*removed` pointer (or NULL if there was no match).
|
||||
|
||||
|
|
@ -95,17 +102,16 @@ Note that a clean tree without any nodes present implies a NULL pointer.
|
|||
## `Curl_splayset`
|
||||
|
||||
~~~c
|
||||
void Curl_splayset(struct Curl_tree *node, void *payload);
|
||||
void Curl_splayset(struct Curl_tree *node, uint32_t id);
|
||||
~~~
|
||||
|
||||
Set a custom pointer to be stored in the splay node. This pointer is not used
|
||||
Sets the `id` in the splay node. This value is not used
|
||||
by the splay code itself and can be retrieved again with `Curl_splayget`.
|
||||
|
||||
## `Curl_splayget`
|
||||
|
||||
~~~c
|
||||
void *Curl_splayget(struct Curl_tree *node);
|
||||
uint32_t Curl_splayget(struct Curl_tree *node);
|
||||
~~~
|
||||
|
||||
Get the custom pointer from the splay node that was previously set with
|
||||
`Curl_splayset`. If no pointer was set before, it returns NULL.
|
||||
Get the `id` from the splay node that was previously set.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue