From 7e4ac2d40ec156bae2e4691ddbdbb7938ad16312 Mon Sep 17 00:00:00 2001 From: Georgiy Lebedev Date: Mon, 11 Dec 2023 10:48:34 +0300 Subject: [PATCH] Docs: add a design document for the Client Add a document that states the requirements for the Client, and then proposes a design that fulfills them. --- docs/client-design.md | 184 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 docs/client-design.md diff --git a/docs/client-design.md b/docs/client-design.md new file mode 100644 index 000000000..f7fba3d2f --- /dev/null +++ b/docs/client-design.md @@ -0,0 +1,184 @@ +# Tntcxx Client Design + +## Scope + +This document describes the design of the Tntcxx Client. First we state the +requirements and use cases we have in mind, and then we propose a design that +fulfills them. + +## Requirements + +### Functional Requirements + +We envision Tntcxx to be used primarily as a part of network applications (e.g., +an HTTP server), the Tntcxx Client backing requests to Tarantool. Such +applications are usually built around a central event processing loop, which is +responsible for multiplexing network I/O. + +#### Application Event Processing Loop Integration + +The first and foremost requirement is that there must be a convenient +way to integrate the Tntcxx Client into the event processing loop used by the +application. Moreover, the Tntcxx Client must never run the event processing +loop itself. + +At the same time, since event processing loops are inherently single threaded, +we do expect the Tntcxx Client to be used in a multithreaded environment, i.e., +when connections and reqeust futures are in different threads. So we do not aim +to design the Tntcxx Client to be thread-safe. + +#### Asynchronous Request Processing + +Since the Tntcxx Client is constrained from running the event processing loop, +the Tntcxx Client must support asynchronous request processing through +application-provided callbacks, futures or scatter-gather. The Tntcxx Client +must only be responsible for posting requests — the responses must be processed +and returned to the application as they arrive, i.e., asynchronously. + +#### Connection Status + +The application must be able to check the status of a Tntcxx Client. + +#### Request Status + +The application must be able to check the status of a Tntcxx Client request. + +#### Request Cancelling + +The application must be able to cancel a Tntcxx Client request. + +#### Error Handling + +There must be a convenient exception-safe way for the application to handle +errors arising throughout the Tntcxx Client request lifecycle. A request error +returned either through the callback, or through the future. + +#### Request Handling + +In order for the application to be able to manage a request, a request handle is +always returned. The application can check the request status, cancel the +request, handle request errors and retrieve the response through this handle +(only once). However, if the response was retrieved by other means (either +returned through a callback or collected through scatter-gather), the handle +cannot return the response. + +#### Request Timeout + +Since the Tntcxx Client does not have control over the application's event +processing loop, the application must implement its own request timeouts. The +application can cancel stale requests. + +#### Response Lifetime + +The response lifetime is managed implicitly and does not require any +interference from the application. The response can be retrieved only once, and +it is uniquely owned by the application (i.e., it is not copyable). + +#### Request Retrying + +Since the Tntcxx Client does not have control over the application's event +processing loop, the application must implement its own request retrying. + +#### Reconnection + +The Tntcxx Client must support implicit reconnection with the same session +settings it was created with. + +#### Connection Pool + +TBD. + +#### Transactions + +TBD. + +#### Failover + +TBD. + +## Design + +### Socket + +```c++ +template +class Socket { +public: + Resource get_resource(); +}; +``` + +### Network Provider + +```c++ +template +class NetProvider { +public: + template + using read_ready_cb_f = void (*)(Socket sock, Data *data); + + template + using write_ready_cb_f = void (*)(Socket sock, Data *data); + + int register(Socket sock, Data *data, read_ready_cb_f read_ready_cb, write_ready_cb_f write_ready_cb); + int unregister(Socket sock); +}; +``` + +```c++ +template +class EpollNetProviderData { +public: + EpollNetProviderData(Socket sock, Data *data, read_ready_cb_f read_ready_cb, write_ready_cb_f write_ready_cb); + + int type; + + void read_ready(); + void write_ready(); +}; +``` + +### Connection + +```c++ +struct ConnectionOptions { + /* All existing options. */ + + static constexpr size_t DEFAULT_RECONNECTION_INTERVAL = 2; + size_t reconnection_interval = DEFAULT_RECONNECTION_INTERVAL; +}; + +template +class Connection { +public: + using request_cb_f = void (*)(std::optional error, Response response, Connection &connection); + + Connection(NetProvider net_provider, ConnectionOptions connection_options); + + enum class ConnectionStatus status(); + + std::optional error(); + + /* An abstract request's interface. */ + Request some_request(/* options */); + Request some_request(/* options */, request_cb_f request_cb); + + template + void gather_responses(Container &responses); +}; +``` + +### Request + +```c++ +class Request { +public: + enum class RequestStatus status(); + + std::optional error(); + + void cancel(); + + std::optional get_response(); +}; +```