ID | IEP-9 |
Author | Pavel Tupitsyn |
Sponsor | Pavel Tupitsyn |
Created | 20-NOV-2017 |
Status | DRAFT |
Implement thin Ignite client in any programming language / platform using a well-defined binary connectiona protocol.
"Thin" here means that we do not start an Ignite node in order to communicate with the cluster, we do not implement discovery/communication spi logic, as opposed to currently available Ignite Client Mode.
Every Ignite node listens on a TCP port. Thin client implementations connect to any node in the cluster through TCP socket and perform Ignite operations using a well-defined binary protocol.
Server-side connection parameters are defined in ClientConnectorConfiguration
class. Default port is 10800. Connector is enabled by default, no configuration changes needed.
Byte order is little-endian. Strings are UTF-8 with int prefix (no null terminator). All data types in this proposal are Java-like (byte = 8 bits, short = 2 bytes, int = 4 bytes, long = 8 bytes).
User data, such as cache keys and values, is represented in Ignite Binary Object format. Binary Object can be a primitive (predefined type) or a complex object.
Primitives (predefined types)
Primitives are represented as a type code + value:
byte | Type code |
... | Value |
Available primitives are listed below:
Name | Type Code | Size (bytes) |
---|---|---|
byte | 1 | 1 |
short | 2 | 2 |
int | 3 | 4 |
long | 4 | 8 |
float | 5 | 4 |
double | 6 | 8 |
char | 7 | 2 |
bool | 8 | 1 |
string | 9 | 4 bytes length + length * 2 |
UUID (Guid) | 10 | 8 |
date | 11 | 8 |
byte array | 12 | 4 bytes length + length |
short array | 13 | 4 bytes length + length * 2 |
int array | 14 | 4 bytes length + length * 4 |
long array | 15 | 4 bytes length + length * 8 |
float array | 16 | 4 bytes length + length * 4 |
double array | 17 | 4 bytes length + length * 8 |
char array | 18 | 4 bytes length + length * 2 |
bool array | 19 | 4 bytes length + length |
string array | 20 | 4 bytes length + variable length strings, see above |
UUID (Guid) array | 21 | 4 bytes length + length * 8 |
date array | 22 | 4 bytes length + length * 8 |
NULL | 101 | 0 |
Complex Objects
Complex objects consist of a 24-byte header and a set of fields (key-value pairs).
Header | |
---|---|
byte | Object type code, always 103 |
byte | Version, always 1 |
short | Flags, see below |
int | Type id, Java-style hash code of the type name |
int | Hash code, Java-style hash of contents without header, necessary for comparisons |
int | Length, including header |
int | Schema Id, see below |
int | SchemaOffset, see below |
All messages, request and response, including handshake, start with int
message length (excluding these first 4 bytes). E.g. empty message would be represented by 4 zero bytes.
int | Length of Payload |
... | Payload |
Length is omitted in all message descriptions below for brevity.
The first message upon connection establishment must be a handshake. Handshake ensures that client and server versions are compatible.
Request | |
byte | Handshake code, always 1 |
short | Version major |
short | Version minor |
short | Version patch |
byte | Client code, always 2 |
Response (success) | |
byte | Success flag, 1 |
Response (failure) | |
byte | Success flag, 0 |
short | Server version major |
short | Server version minor |
short | Server version patch |
string | Error message |
Upon successful handshake client can start performing operations by sending a request with specific op code. Each operation has it's own request and response format, with a common header.
Request | |
short | Operation code |
long | Request id, generated by client and returned as-is in response |
... | Operation-specific data |
Response | |
long | Request id (see above) |
int | Status code (0 for success, otherwise error code) |
string | Error message (present only when status is not 0) |
... | Operation-specific data |
Operation codes and request ids are omitted everywhere below for brevity.
OP_CACHE_GET = 1
Request | |
int | Cache ID: Java-style hash code of the cache name |
byte | flags |
BinaryObject | key |
Response | |
BinaryObject | value |
OP_CACHE_GET_ALL = 12
Request | |
int | Cache ID: Java-style hash code of the cache name |
byte | flags |
int | key count |
BinaryObject * count | keys |
Response | |
int | result count |
(BinaryObject + BinaryObject) * count | Resulting key-value pairs. Keys that are not present in the cache are not included. |
OP_CACHE_PUT = 4
Request | |
int | Cache ID: Java-style hash code of the cache name |
byte | flags |
BinaryObject | key |
BinaryObject | value |
Request | |
int | Cache ID: Java-style hash code of the cache name |
byte | flags |
int | Key-value pair count |
(BinaryObject + BinaryObject) * count | Key-value pairs |
OP_CACHE_CONTAINS_KEY = 10
Request | |
int | Cache ID: Java-style hash code of the cache name |
byte | flags |
BinaryObject | key |
Response | |
bool | True when key is present, false otherwise |
OP_CACHE_CONTAINS_KEYS = 11
Request | |
int | Cache ID: Java-style hash code of the cache name |
byte | flags |
int | key count |
BinaryObject * count | keys |
Response | |
bool | True when keys are present, false otherwise |
OP_CACHE_GET_AND_PUT = 13
Request | |
int | Cache ID: Java-style hash code of the cache name |
byte | flags |
BinaryObject | key |
BinaryObject | value |
Response | |
BinaryObject | Existing value for the specified key, or null |
Let's see how request and response would look for a cache.get operation for integer key and value:
TODO
Similar protocols from other vendors:
See "thin client" component in JIRA