As a forced topic starter, I would like to ponder over a library (no
matter, “standard” or not) content/API. Here I mean libraries designed
for comminicating with various servers using some application level
network protocol (http, postgres, resp and so on).
Briefly: do not mix CPU bound stuff (request constructing, reply
parsing) and I/O bound stuff (connecting, request sending, reply
receiving) in a (networking) library.
Now I will try to explain as clear as can why I think this way. Here is
some (event driven) state machine which I use in production DAQ systems:
state machine description
$init
$conn
$hitx
$hirx
$autx
$aurx
$idle
$fail
$wait
+init M0 conn
@conn M1
@conn M2
+conn M0 hitx
+conn M3 fail
@hitx M1
@hitx M2
+hitx M0 hirx
+hitx M3 fail
@hirx M1
@hirx M2
+hirx M0 autx
+hirx M3 fail
@autx M1
@autx M2
+autx M0 aurx
+autx M3 fail
@aurx M1
@aurx M2
+aurx M0 idle
+aurx M3 fail
@idle M2
+idle M3 fail
+fail M0 wait
+wait T0 conn
Do not be scared, the “syntax” is extremely simple:
$
designates a state
+<state1> Mx <state2>
means state1 → state2 transition when Mx
happens
@<state>
Mx means “when Mx happens, do smth, but do not leave the state”
If you are not very lazy, let’s convert this
textual description of the machine into graphical form:
Do the following:
- take a sheet of paper and a pencil (or a diagramm drawing tool,
dia
for instance)
- for each line starting with
$
(dollar sign) draw a circle, put the name inside; these are our states
- for each state:
- draw transition arrows (
+conn M0 hitx
=> draw an arrow from conn
to hitx
and mark this arrow with M0
)
- draw action arrows (
@autx M1
=> draw a loop arrow for the state)
Have you guessed what is this SM for? It’s a machine that perform a
connection to PostGres DBMS (with md5
authentication). And a bunch of
such machines in essence is a connection pool.
Some notes before I ask my main question. In every state where this machine is sending
something to a server (hitx
, autx
) it has these two reactions:
@hitx M1
// ok
@hitx M2
// failed
M1
and M2
are messages that coming from other machine,
similar to this one
Similarly, in every state where we are receiving, connector machine has
reactions to M1
(success) and M2
(failure) messages being sent by an RX
machine when it’ done.
So, the question is - what do I expect to be in a postgres library with such a construction?
The answer is quite obvious - I want CPU bound stuff only (how to make requests,
how to interpret DBMS answers), I do not want no connect/read/write things there.
I’d better do i/o in a way that is most suitable for an application.
In the case above (PG connector) I wanted to achieve high concurrency level
After each action/transition we go to an event loop and a program is able
to do many-many other things while connector is in the process of… connecting 
In my header for PG I have API like this:
int pg_mk_fhelo_msg(char *user, char *database, struct dbuf *b);
int pg_ck_bhelo_msg(struct dbuf *b, struct pg_error *e);
u32 pg_count_notifications(struct dbuf *b);
.....
About async/await/coroutines: although Zig is not ready for the
cooperative multitasking within a single execution thread, but… what
are going to do with this? I happened to hear something about “monkey
patching” in Python with regard to gevent/greenlets or so.
OK, let’s look at http in Zig from a bird’s perspective:
/opt/zig-0.12/lib/std/http$ ls -1
Client.zig
Headers.zig
protocol.zig
Server.zig
Aha! I see protocol.zig
and Headers.zig
. This is probably a good
sign. If it is possible to use these two (and they do not use any i/o)
without the other two, it’s just wonderful, this fits nicely into my
concepts of a network library design. However, I did not look deeper.