2019-05-02 16:19:00 +00:00
|
|
|
====================
|
|
|
|
Garlic Farm Protocol
|
|
|
|
====================
|
|
|
|
.. meta::
|
|
|
|
:author: zzz
|
2019-05-03 16:24:18 +00:00
|
|
|
:created: 2019-05-02
|
2019-05-02 16:19:00 +00:00
|
|
|
:thread: http://zzz.i2p/topics/2234
|
|
|
|
:lastupdated: 2019-05-03
|
|
|
|
:status: Open
|
|
|
|
|
|
|
|
.. contents::
|
|
|
|
|
|
|
|
|
|
|
|
Overview
|
|
|
|
========
|
|
|
|
|
|
|
|
This is the spec for the Garlic Farm wire protocol,
|
2019-05-02 20:25:42 +00:00
|
|
|
based on JRaft, its "exts" code for implementation over TCP,
|
|
|
|
and its "dmprinter" sample application [JRAFT]_.
|
2019-05-02 21:01:23 +00:00
|
|
|
JRaft is an implementation of the Raft protocol [RAFT]_.
|
|
|
|
|
|
|
|
We were unable to find any implementation with a documented wire protocol.
|
|
|
|
However, the JRaft implementation is simple enough that we could
|
|
|
|
inspect the code and then document its protocol.
|
|
|
|
This proposal is the result of that effort.
|
2019-05-02 16:19:00 +00:00
|
|
|
|
|
|
|
This will be the backend for coordination of routers publishing
|
|
|
|
entries in a Meta LeaseSet. See proposal 123.
|
|
|
|
|
|
|
|
|
|
|
|
Goals
|
|
|
|
=====
|
|
|
|
|
2019-05-02 21:01:23 +00:00
|
|
|
- Small code size
|
|
|
|
- Based on existing implementation
|
|
|
|
- No serialized Java objects or any Java-specific features or encoding
|
2019-05-03 12:14:47 +00:00
|
|
|
- Any bootstrapping is out-of-scope. At least one other server is assumed
|
|
|
|
to be hardcoded, or configured out-of-band of this protocol.
|
2019-05-02 16:19:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
Design
|
|
|
|
======
|
|
|
|
|
2019-05-02 21:01:23 +00:00
|
|
|
The Raft protocol is not a concrete protocol; it defines only a state machine.
|
|
|
|
Therefore we document the concrete protocol of JRaft and base our protocol on it.
|
|
|
|
There are no changes to the JRaft protocol other than the addition of
|
|
|
|
an authentication handshake.
|
2019-05-02 16:19:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
Specification
|
|
|
|
=============
|
|
|
|
|
|
|
|
The wire protocol is over SSL sockets or non-SSL I2P sockets.
|
|
|
|
There is no support for clearnet non-SSL sockets.
|
|
|
|
|
2019-05-02 21:01:23 +00:00
|
|
|
|
|
|
|
Handshake and authentication
|
|
|
|
----------------------------
|
|
|
|
|
|
|
|
Not defined by JRaft.
|
|
|
|
|
2019-05-02 16:19:00 +00:00
|
|
|
TODO authentication. Perhaps new messages, or perhaps something before
|
|
|
|
the request/response phase happens.
|
|
|
|
|
2019-05-02 21:01:23 +00:00
|
|
|
Requirements:
|
|
|
|
|
|
|
|
- user/password
|
|
|
|
- version
|
|
|
|
- cluster identifier
|
|
|
|
- extensible
|
2019-05-02 16:19:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
Message Types
|
|
|
|
-------------
|
|
|
|
|
2019-05-02 21:01:23 +00:00
|
|
|
There are two types of messages, requests and responses.
|
2019-05-03 12:14:47 +00:00
|
|
|
Requests may contain Log Entries, and are variable-sized;
|
|
|
|
responses do not contain Log Entries, and are fixed-size.
|
|
|
|
|
|
|
|
|
2019-05-02 21:01:23 +00:00
|
|
|
|
|
|
|
|
2019-05-03 16:24:18 +00:00
|
|
|
======================== ====== =========== ================= =====================================
|
|
|
|
Message Number Sent By Sent To Notes
|
|
|
|
======================== ====== =========== ================= =====================================
|
|
|
|
RequestVoteRequest 1 Candidate Follower Standard Raft RPC; must not contain log entries
|
|
|
|
RequestVoteResponse 2 Follower Candidate Standard Raft RPC
|
|
|
|
AppendEntriesRequest 3 Leader Follower Standard Raft RPC
|
|
|
|
AppendEntriesResponse 4 Follower Leader / Client Standard Raft RPC
|
|
|
|
ClientRequest 5 Client Leader / Follower Response is AppendEntriesResponse; must contain Application log entries only
|
|
|
|
AddServerRequest 6 Client Leader Must contain a single ClusterServer log entry only
|
|
|
|
AddServerResponse 7 Leader Client Leader will also send a JoinClusterRequest
|
|
|
|
RemoveServerRequest 8 Follower Leader Must contain a single ClusterServer log entry only
|
2019-05-02 18:58:45 +00:00
|
|
|
RemoveServerResponse 9 Leader Follower
|
2019-05-03 16:24:18 +00:00
|
|
|
SyncLogRequest 10 Leader Follower Must contain a single LogPack log entry only
|
2019-05-02 18:58:45 +00:00
|
|
|
SyncLogResponse 11 Follower Leader
|
2019-05-03 16:24:18 +00:00
|
|
|
JoinClusterRequest 12 Leader New Server Invitation to join; must contain a single Configuration log entry only
|
|
|
|
JoinClusterResponse 13 New Server Leader
|
|
|
|
LeaveClusterRequest 14 Leader Follower Command to leave
|
2019-05-02 18:58:45 +00:00
|
|
|
LeaveClusterResponse 15 Follower Leader
|
2019-05-03 16:24:18 +00:00
|
|
|
InstallSnapshotRequest 16 Leader Follower Must contain a single SnapshotSyncRequest log entry only
|
|
|
|
InstallSnapshotResponse 17 Follower Leader Raft Section 7
|
|
|
|
======================== ====== =========== ================= =====================================
|
2019-05-02 18:58:45 +00:00
|
|
|
|
2019-05-02 16:19:00 +00:00
|
|
|
|
|
|
|
Definitions
|
|
|
|
-----------
|
|
|
|
|
|
|
|
- Source: Identifies the originator of the message
|
|
|
|
- Destination: Identifies the recipient of the message
|
2019-05-02 17:15:09 +00:00
|
|
|
- Terms: See Raft. Initialized to 0, increases monotonically
|
|
|
|
- Indexes: See Raft. Initialized to 0, increases monotonically
|
2019-05-02 16:19:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Requests
|
|
|
|
--------
|
|
|
|
|
|
|
|
Requests contain a header and zero or more log entries.
|
2019-05-03 12:14:47 +00:00
|
|
|
Requests contain a fixed-size header and optional Log Entries of variable size.
|
2019-05-02 16:19:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
Request Header
|
|
|
|
``````````````
|
|
|
|
|
|
|
|
The request header is 45 bytes, as follows.
|
2019-05-02 18:58:45 +00:00
|
|
|
All values are unsigned big-endian.
|
2019-05-02 16:19:00 +00:00
|
|
|
|
|
|
|
.. raw:: html
|
|
|
|
|
|
|
|
{% highlight lang='dataspec' %}
|
|
|
|
|
2019-05-03 12:14:47 +00:00
|
|
|
Message type: 1 byte
|
|
|
|
Source: ID, 4 byte integer
|
|
|
|
Destination: ID, 4 byte integer
|
|
|
|
Term: Current term (or candidate term for RequestVoteRequest), 8 byte integer
|
|
|
|
Last Log Term: 8 byte integer
|
|
|
|
Last Log Index: 8 byte integer
|
|
|
|
Commit Index: 8 byte integer
|
|
|
|
Log entries size: Total size in bytes, 4 byte integer
|
|
|
|
Log entries: see below, total length as specified
|
2019-05-02 16:19:00 +00:00
|
|
|
|
|
|
|
{% endhighlight %}
|
|
|
|
|
|
|
|
|
|
|
|
Log Entries
|
|
|
|
```````````
|
|
|
|
|
|
|
|
The log contains zero or more log entries.
|
|
|
|
Each log entry is as follows.
|
2019-05-02 18:58:45 +00:00
|
|
|
All values are unsigned big-endian.
|
2019-05-02 16:19:00 +00:00
|
|
|
|
|
|
|
.. raw:: html
|
|
|
|
|
|
|
|
{% highlight lang='dataspec' %}
|
|
|
|
|
|
|
|
Term: 8 byte integer
|
|
|
|
Value type: 1 byte
|
2019-05-02 18:58:45 +00:00
|
|
|
Entry size: In bytes, 4 byte integer
|
2019-05-02 16:19:00 +00:00
|
|
|
Entry: length as specified
|
|
|
|
|
|
|
|
{% endhighlight %}
|
|
|
|
|
2019-05-02 18:58:45 +00:00
|
|
|
|
|
|
|
Log Contents
|
|
|
|
````````````
|
|
|
|
|
|
|
|
All values are unsigned big-endian.
|
|
|
|
|
2019-05-02 17:15:09 +00:00
|
|
|
======================== ======
|
|
|
|
Log Value Type Number
|
|
|
|
======================== ======
|
|
|
|
Application 1
|
|
|
|
Configuration 2
|
|
|
|
ClusterServer 3
|
|
|
|
LogPack 4
|
|
|
|
SnapshotSyncRequest 5
|
|
|
|
======================== ======
|
2019-05-02 16:19:00 +00:00
|
|
|
|
|
|
|
|
2019-05-02 17:15:09 +00:00
|
|
|
Application
|
|
|
|
~~~~~~~~~~~
|
|
|
|
|
2019-05-02 16:19:00 +00:00
|
|
|
TBD, probably JSON.
|
|
|
|
|
|
|
|
|
2019-05-02 17:15:09 +00:00
|
|
|
Configuration
|
|
|
|
~~~~~~~~~~~~~
|
|
|
|
|
2019-05-02 17:33:44 +00:00
|
|
|
This is used for the leader to serialize a new cluster configuration and replicate to peers.
|
2019-05-02 20:25:42 +00:00
|
|
|
It contains zero or more ClusterServer configurations.
|
2019-05-02 17:33:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
.. raw:: html
|
|
|
|
|
|
|
|
{% highlight lang='dataspec' %}
|
|
|
|
|
|
|
|
Log Index: 8 byte integer
|
|
|
|
Last Log Index: 8 byte integer
|
2019-05-02 20:25:42 +00:00
|
|
|
ClusterServer Data for each server:
|
2019-05-02 17:33:44 +00:00
|
|
|
ID: 4 byte integer
|
|
|
|
Endpoint data len: In bytes, 4 byte integer
|
2019-05-02 20:25:42 +00:00
|
|
|
Endpoint data: ASCII string of the form "tcp://localhost:9001", length as specified
|
2019-05-02 17:33:44 +00:00
|
|
|
|
|
|
|
{% endhighlight %}
|
2019-05-02 17:15:09 +00:00
|
|
|
|
2019-05-02 18:58:45 +00:00
|
|
|
|
2019-05-02 17:15:09 +00:00
|
|
|
ClusterServer
|
|
|
|
~~~~~~~~~~~~~
|
|
|
|
|
2019-05-02 17:33:44 +00:00
|
|
|
The configuration information for a server in a cluster.
|
2019-05-02 21:01:23 +00:00
|
|
|
This is included only in a AddServerRequest or RemoveServerRequest message.
|
2019-05-02 17:33:44 +00:00
|
|
|
|
2019-05-02 20:25:42 +00:00
|
|
|
When used in a AddServerRequest Message:
|
|
|
|
|
2019-05-02 17:33:44 +00:00
|
|
|
.. raw:: html
|
|
|
|
|
|
|
|
{% highlight lang='dataspec' %}
|
|
|
|
|
|
|
|
ID: 4 byte integer
|
|
|
|
Endpoint data len: In bytes, 4 byte integer
|
2019-05-02 20:25:42 +00:00
|
|
|
Endpoint data: ASCII string of the form "tcp://localhost:9001", length as specified
|
|
|
|
|
|
|
|
{% endhighlight %}
|
|
|
|
|
|
|
|
|
|
|
|
When used in a RemoveServerRequest Message:
|
|
|
|
|
|
|
|
.. raw:: html
|
|
|
|
|
|
|
|
{% highlight lang='dataspec' %}
|
|
|
|
|
|
|
|
ID: 4 byte integer
|
2019-05-02 17:33:44 +00:00
|
|
|
|
|
|
|
{% endhighlight %}
|
|
|
|
|
2019-05-02 17:15:09 +00:00
|
|
|
|
|
|
|
LogPack
|
|
|
|
~~~~~~~
|
|
|
|
|
2019-05-03 12:14:47 +00:00
|
|
|
This is included only in a SyncLogRequest message.
|
|
|
|
|
2019-05-02 17:44:01 +00:00
|
|
|
The following is gzipped before transmission:
|
|
|
|
|
|
|
|
|
|
|
|
.. raw:: html
|
|
|
|
|
|
|
|
{% highlight lang='dataspec' %}
|
|
|
|
|
|
|
|
Index data len: In bytes, 4 byte integer
|
|
|
|
Log data len: In bytes, 4 byte integer
|
2019-05-02 20:25:42 +00:00
|
|
|
Index data: 8 bytes for each index, length as specified
|
|
|
|
Log data: length as specified
|
2019-05-02 17:44:01 +00:00
|
|
|
|
|
|
|
{% endhighlight %}
|
|
|
|
|
|
|
|
|
2019-05-02 17:15:09 +00:00
|
|
|
|
|
|
|
SnapshotSyncRequest
|
2019-05-02 17:44:01 +00:00
|
|
|
~~~~~~~~~~~~~~~~~~~
|
2019-05-02 17:15:09 +00:00
|
|
|
|
2019-05-02 21:01:23 +00:00
|
|
|
This is included only in a InstallSnapshotRequest message.
|
2019-05-02 17:15:09 +00:00
|
|
|
|
2019-05-02 17:33:44 +00:00
|
|
|
.. raw:: html
|
|
|
|
|
|
|
|
{% highlight lang='dataspec' %}
|
|
|
|
|
2019-05-03 19:04:32 +00:00
|
|
|
Last Log Index: 8 byte integer
|
2019-05-02 17:33:44 +00:00
|
|
|
Last Log Term: 8 byte integer
|
|
|
|
Config data len: In bytes, 4 byte integer
|
|
|
|
Config data: length as specified
|
2019-05-02 20:25:42 +00:00
|
|
|
Offset: The offset of the data in the database, in bytes, 8 byte integer
|
2019-05-02 17:33:44 +00:00
|
|
|
Data len: In bytes, 4 byte integer
|
|
|
|
Data: length as specified
|
|
|
|
Is Done: 1 if done, 0 if not done (1 byte)
|
|
|
|
|
|
|
|
{% endhighlight %}
|
|
|
|
|
2019-05-02 17:15:09 +00:00
|
|
|
|
2019-05-02 16:19:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
Responses
|
|
|
|
---------
|
|
|
|
|
2019-05-03 12:14:47 +00:00
|
|
|
All responses are 26 bytes, as follows.
|
2019-05-02 17:15:09 +00:00
|
|
|
All values are unsigned big-endian.
|
2019-05-02 16:19:00 +00:00
|
|
|
|
|
|
|
.. raw:: html
|
|
|
|
|
|
|
|
{% highlight lang='dataspec' %}
|
|
|
|
|
|
|
|
Message type: 1 byte
|
2019-05-02 21:01:23 +00:00
|
|
|
Source: ID, 4 byte integer
|
2019-05-03 16:24:18 +00:00
|
|
|
Destination: Usually the actual destination ID (see notes), 4 byte integer
|
2019-05-02 21:01:23 +00:00
|
|
|
Term: Current term, 8 byte integer
|
2019-05-02 17:15:09 +00:00
|
|
|
Next Index: Initialized to leader last log index + 1, 8 byte integer
|
|
|
|
Is Accepted: 1 if accepted, 0 if not accepted (1 byte)
|
2019-05-02 16:19:00 +00:00
|
|
|
|
|
|
|
{% endhighlight %}
|
|
|
|
|
|
|
|
|
2019-05-03 16:24:18 +00:00
|
|
|
Notes
|
|
|
|
`````
|
|
|
|
|
|
|
|
The Destination ID is usually the actual destination for this message.
|
|
|
|
However, for AppendEntriesResponse, AddServerResponse, and RemoveServerResponse,
|
|
|
|
it is the ID of the current leader.
|
|
|
|
|
|
|
|
|
2019-05-02 16:19:00 +00:00
|
|
|
Justification
|
|
|
|
=============
|
|
|
|
|
|
|
|
Atomix is too large and won't allow customization for us to route
|
|
|
|
the protocol over I2P. Also, its wire format is undocumented, and depends
|
|
|
|
on Java serialization.
|
|
|
|
|
|
|
|
|
|
|
|
Notes
|
|
|
|
=====
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Issues
|
|
|
|
======
|
|
|
|
|
2019-05-03 19:04:32 +00:00
|
|
|
- There's no way for a client to find out about and connect to an unknown leader.
|
|
|
|
It would be a minor change for a Follower to send the Configuration as a Log Entry in the AppendEntriesResponse.
|
|
|
|
|
2019-05-02 16:19:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
Migration
|
|
|
|
=========
|
|
|
|
|
|
|
|
No backward compatibility issues.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
References
|
|
|
|
==========
|
|
|
|
|
|
|
|
.. [JRAFT]
|
|
|
|
https://github.com/datatechnology/jraft
|
2019-05-02 21:01:23 +00:00
|
|
|
|
|
|
|
.. [RAFT]
|
|
|
|
https://ramcloud.stanford.edu/wiki/download/attachments/11370504/raft.pdf
|