commit 2da0223d5d1e91a7154996969ce44f48d9838a4f
parent 2d9c7c26de3f8a4d41dfd3ea080ebb20a681dfa9
Author: Laurent Bercot <ska-skaware@skarnet.org>
Date: Wed, 29 Sep 2021 13:45:39 +0000
Doc fixes
Signed-off-by: Laurent Bercot <ska@appnovation.com>
Diffstat:
2 files changed, 122 insertions(+), 23 deletions(-)
diff --git a/doc/libstddjb/cdb.html b/doc/libstddjb/cdb.html
@@ -20,8 +20,111 @@
<h1> The <tt>skalibs/cdb.h</tt> header </h1>
+<h2> General information </h2>
+
+<p>
+ A <a href="https://cr.yp.to/cdb/cdb.txt">cdb</a>, for <em>constant database</em>,
+is an immutable key-value store. In skalibs, a cdb is built once via the
+<a href="cdbmake.html">cdbmake</a> primitives and stored on disk; the <tt>cdb</tt>
+primitives, documented here, are about accessing the information.
+</p>
+
+<h2> Data structures </h2>
+
+<ul>
+ <li> A <tt>cdb</tt> is an opaque structure, that must be initialized to <tt>CDB_ZERO</tt> when declared. </li>
+ <li> A <tt>cdb_data</tt> is a structure that is passed by address to cdb-reading primitives, which fill
+it with record information. It contains (at least) two fields:
+ <ul>
+ <li> <tt>s</tt>, a <tt>char const *</tt>, which holds a pointer to the record; the <tt>const</tt> indicates
+that a cdb is read-only, you cannot write to the record even when you have a pointer to it. </li>
+ <li> <tt>len</tt>, a <tt>uint32_t</tt>, which holds the record length. It can be zero (records can be
+empty). A cdb must fit into 4 GB, so record lengths always fit in 32 bits. </li>
+ </ul>
+Pointers returned in a <tt>cdb_data</tt> are only valid while the cdb is mapped.
+Make sure to copy the information before calling <tt>cdb_free()</tt>.
+ </li>
+ <li> A <tt>cdb_find_state</tt> is an opaque structure, that should be initialized to <tt>CDB_FIND_STATE_ZERO</tt>
+when declared. It is passed by address to <tt>cdb_findnext</tt>, to maintain position state when looking for
+all the data records under one key. </li>
+</ul>
+
+<h2> Macros and functions </h2>
+
+<h3> Starting and ending </h3>
+
+<p>
+<code> int cdb_init (cdb *c, char const *file) </code> <br />
+Maps the file named <em>file</em> to the cdb pointed to by <em>c</em>.
+<em>*c</em> must be CDB_ZERO before the call. The function returns a
+positive integer if it succeeds, and 0 (and sets errno) if it fails.
+</p>
+
+<p>
+<code> int cdb_init_at (cdb *c, int dfd, char const *file) </code> <br />
+Like <tt>cdb_init</tt>, but <em>file</em> is interpreted relative to the
+file descriptor <em>dfd</em>, which must be open on a directory.
+</p>
+
+<p>
+<code> int cdb_init_fromfd (cdb *c, int fd) </code> <br />
+Like <tt>cdb_init</tt>, but the database file is already open and
+readable via then file descriptor <em>fd</em>.
+</p>
+
+<p>
+<code> void cdb_free (cdb *c) </code> <br />
+Frees the resources used by a cdb mapping. After the call, <em>c</em>
+is immediately reusable by another <tt>cdb_init</tt> function.
+</p>
+
+<h3> cdb lookup </h3>
+
+<h4> Single record lookup </h4>
+
+<p>
+<code> int cdb_find (cdb const *c, cdb_data *data, char const *key, uint32_t klen) </code> <br />
+Looks up key <em>key</em> of length <em>klen</em> in the cdb <em>*c</em>. The function returns
+-1 if <em>*c</em> isn't a valid cdb; 0 if no record can be found for the key; and 1 on success, in
+which case the corresponding value is returned in <em>*data</em>: <tt><em>data</em>→s</tt>
+points to the start of the value, and <tt><em>data</em>→len</tt> contains the length of
+the value. Only the first record with the same key can be obtained this way.
+</p>
+
+<h4> Multiple record lookup </h4>
+
+<p>
+<code> void cdb_findstart (cdb_find_state *state) </code> <br />
+Initializes <em>state</em> so that the next invocation of <tt>cdb_findnext()</tt>
+finds the first record for a given key.
+</p>
+
+<p>
+<code> int cdb_findnext (cdb const *c, cdb_data *data, char const *key, uint32_t klen, cdb_find_state *state) </code> <br />
+Like <tt>cdb_find</tt>, except that the extra argument <em>state</em> memorizes
+internal cdb lookup data, so the next <tt>cdb_findnext()</tt> invocation with the
+same <em>key</em>, <em>klen</em> and <em>state</em> will yield the next record
+for the key. <tt>cdb_findnext</tt> returns 0 when all the records for the key have
+been exhausted.
+</p>
+
+<h3> cdb enumeration </h3>
+
+<p>
+<code> void cdb_traverse_init (uint32_t *pos) </code> <br />
+Initializes <em>*pos</em> so that the next invocation of <tt>cdb_traverse_next</tt>
+finds the first entry in the cdb. <em>*pos</em> can also be initialized to the
+macro CDB_TRAVERSE_INIT() instead.
+</p>
+
<p>
- TODO: write this documentation page. (Sorry!)
+<code> int cdb_traverse_next (cdb const *c, cdb_data *key, cdb_data *data, uint32_t *pos) </code> <br />
+Gets the next entry in the cdb <em>*c</em>. On success, the key is stored in <em>*key</em> and the
+data is stored in <em>*data</em>. <em>*pos*</em> is an opaque integer storing internal
+state; it is automatically updated so that the next invocation of <tt>cdb_traverse_next()</tt>
+yields the next entry. The function returns -1 if <em>*c</em> is not a valid cdb or <em>*pos</em>
+is not valid state, 1 on success, and 0 if no entry can be found, i.e. the end of the cdb has
+been reached.
</p>
</body>
diff --git a/doc/libstddjb/selfpipe.html b/doc/libstddjb/selfpipe.html
@@ -132,7 +132,7 @@ non-blocking descriptor that can be used in your event loop. It will
be selected for readability when you've caught a signal.
</p>
-<h3> Trapping/untrapping signals </h3>
+<h3> Trapping signals </h3>
<pre>
int r = selfpipe_trap(SIGTERM) ;
@@ -140,24 +140,14 @@ int r = selfpipe_trap(SIGTERM) ;
<p>
<tt>selfpipe_trap()</tt> catches a signal and sends it to the selfpipe.
-Uncaught signals won't trigger the selfpipe. <tt>r</tt> is 0 if
-the operation succeeded, and -1 if it failed. If it succeeded, you
+Uncaught signals won't trigger the selfpipe. <tt>r</tt> is 1 if
+the operation succeeded, and 0 if it failed. If it succeeded, you
can forget about the trapped signal entirely. <br />
-In our example, if <tt>r</tt> is 0, then a SIGTERM will instantly
+In our example, if <tt>r</tt> is 1, then a SIGTERM will instantly
trigger readability on <tt>fd</tt>.
</p>
<pre>
-int r = selfpipe_untrap(SIGTERM) ;
-</pre>
-
-<p>
-Conversely, <tt>selfpipe_untrap()</tt> uncatches a signal; the selfpipe
-will not manage it anymore. <tt>r</tt> is 0 if the operation succeeded
-and -1 if it failed.
-</p>
-
-<pre>
int r ;
sigset_t set ;
sigemptyset(&set) ;
@@ -167,12 +157,12 @@ r = selfpipe_trapset(&set) ;
</pre>
<p>
-<tt>selfpipe_trap()</tt> and <tt>selfpipe_untrap()</tt> handle signals one
+<tt>selfpipe_trap()</tt> handles signals one
by one. Alternatively (and often preferrably), you can use
<tt>selfpipe_trapset()</tt> to directly handle signal sets. When you call
<tt>selfpipe_trapset()</tt>, signals that are present in <tt>set</tt> will
be caught by the selfpipe, and signals that are absent from <tt>set</tt>
-will be uncaught. <tt>r</tt> is 0 if the operation succeeded and -1 if it
+will be uncaught. <tt>r</tt> is 1 if the operation succeeded and 0 if it
failed.
</p>
@@ -200,7 +190,8 @@ selfpipe_finish() ;
<p>
Call <tt>selfpipe_finish()</tt> when you're done using the selfpipe.
-Signal handlers will be restored to their previous value.
+Signal handlers will be restored to SIG_DFL, i.e. signals will not
+be trapped anymore.
</p>
<h2> Any limitations ? </h2>
@@ -211,11 +202,16 @@ Signal handlers will be restored to their previous value.
<ul>
<li> The selfpipe library uses a global pipe;
-so, it's not safe for multithreading. I'm not sure how multithreaded
-programs handle signals; I personally don't like multithreading and
-never use it, so I'm not knowledgeable about it. Anyway, if your
-program is multithreaded, chances are you don't have an asynchronous
-event loop, so the self-pipe trick has less benefits for you. </li>
+so, it's theoretically not safe for multithreading. However, as long as you dedicate
+one thread to signal handling and block signals in all the other threads
+(see <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html">pthread_sigmask()</a>)
+then you should be able to use the selfpipe in the thread that handles
+signals without trouble. Since reading the selfpipe involves waiting for
+a file descriptor to become readable, it is recommended to do this in a
+thread that will already have a regular input/output loop (via
+<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html">poll()</a>
+or <a href="iopause.html">iopause()</a>) so you can just add the selfpipe
+to the list of fds you're reading on. </li>
<li> In rare cases, the self-pipe can theoretically be filled, if some
application sends more than PIPE_BUF signals before you have time to
<tt>selfpipe_read()</tt>. On most Unix systems, PIPE_BUF is 4096,