The server is a more interesting topic than the client, for the reason that it
sports two different storage engines. The course stipulates also supporting the popular embedded
Rust key-value store Sled, in addition to the Bitcask
inspired engine from the previous module. In order to allow choosing between the two, the server
executable has a flag --engine, defaulting to our handrolled alternative (named kvs).
If the user doesn’t specify any engine, we either detect the one previously used or fall back
to kvs. Picking a different engine than the one previously used is considered an error.
Once launched, the server uses
TcpListener to receive incoming
connections from clients (represented as
TcpStream objects). For each incoming connection,
the server attempts to interpret the data sent as a Bincode serialized command (see the definition
in the preceding section on the client). Depending on the command type, it will perform either a
get, set or remove operation. The operation itself gets delegated to the configured storage engine.
The result from the operation then gets written back (Bincode serialized) to the client.
If an error occurred during the operation, information on this gets encoded in the response
for the client to interpret.
It’s worth mentioning that the server is written such that it can only handle a single request at
a time, synchronously, so it’s not very performant (although easily understood as a result).
Parallelization of request handling gets introduced in the next course module. Exciting!