-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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.
- Loading branch information
1 parent
ac98986
commit 7e4ac2d
Showing
1 changed file
with
184 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 Resource> | ||
class Socket { | ||
public: | ||
Resource get_resource(); | ||
}; | ||
``` | ||
### Network Provider | ||
```c++ | ||
template<class Socket, class Data *> | ||
class NetProvider { | ||
public: | ||
template<class Socket, class Data *> | ||
using read_ready_cb_f = void (*)(Socket sock, Data *data); | ||
template<class Socket, class Data *> | ||
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 Socket, class Data *> | ||
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 NetProvider> | ||
class Connection { | ||
public: | ||
using request_cb_f = void (*)(std::optional<RequestError> error, Response response, Connection &connection); | ||
Connection(NetProvider net_provider, ConnectionOptions connection_options); | ||
enum class ConnectionStatus status(); | ||
std::optional<ConnectionError> error(); | ||
/* An abstract request's interface. */ | ||
Request some_request(/* options */); | ||
Request some_request(/* options */, request_cb_f request_cb); | ||
template<class Container> | ||
void gather_responses(Container<Response> &responses); | ||
}; | ||
``` | ||
|
||
### Request | ||
|
||
```c++ | ||
class Request { | ||
public: | ||
enum class RequestStatus status(); | ||
|
||
std::optional<RequestError> error(); | ||
|
||
void cancel(); | ||
|
||
std::optional<Response> get_response(); | ||
}; | ||
``` |