Stand: 6. April 2026
Version: v1.3.0
Kategorie: 🧩 Architecture
Status: Draft - Implementation in Progress
ThemisDB Wire Protocol v1 is a binary, stateful, request-response protocol over TCP for high-performance client-server communication.
Design Goals:
- 🚀 Low latency: 10-20x faster than HTTP/JSON
- 📦 Binary encoding: Protocol Buffers for serialization
- 🔒 Authentication: Built-in auth handshake
- 🔄 Connection pooling: Persistent connections
- 📡 Streaming: Large result sets via cursor pagination
- 🛡️ Type safety: Strict message schemas
Influences:
- PostgreSQL Wire Protocol (frontend/backend messages)
- MongoDB Wire Protocol (OP_MSG, OP_QUERY)
- Redis RESP3 (simplicity)
- Cassandra CQL Binary Protocol v4 (frames)
Client Server
│ │
├─────── HELLO ────────────────>│
│ │
│<──── HELLO_ACK + AuthReq ────┤
│ │
├─────── AUTH_RESPONSE ────────>│
│ │
│<────── AUTH_SUCCESS ──────────┤
│ │
├─────── QUERY (repeated) ─────>│
│<────── RESPONSE ──────────────┤
│ │
├─────── CLOSE ────────────────>│
│<────── CLOSE_ACK ─────────────┤
│ │
Every message uses a header + payload structure:
┌─────────────────────────────────────────┐
│ ThemisDB Wire Frame │
├───────────┬──────────────┬──────────────┤
│ Header │ Payload │ Checksum │
│ (12 B) │ (variable) │ (4 B) │
└───────────┴──────────────┴──────────────┘
| Offset | Size | Field | Type | Description |
|---|---|---|---|---|
| 0 | 4 | Magic | uint32 | 0x544D4442 ("TMDB" in ASCII) |
| 4 | 1 | Version | uint8 | Protocol version (0x01 = v1) |
| 5 | 1 | OpCode | uint8 | Operation code (see OpCodes) |
| 6 | 2 | Flags | uint16 | Message flags (compressed, encrypted) |
| 8 | 4 | PayloadLength | uint32 | Length of payload in bytes |
- CRC32 checksum of (Header + Payload)
- Detects transmission errors
- Optional if using TLS (flag: 0x0001)
| OpCode | Name | Direction | Description |
|---|---|---|---|
| 0x01 | HELLO | Client→Server | Connection handshake |
| 0x02 | HELLO_ACK | Server→Client | Handshake acknowledgment |
| 0x03 | AUTH_REQUEST | Server→Client | Request authentication |
| 0x04 | AUTH_RESPONSE | Client→Server | Provide credentials |
| 0x05 | AUTH_SUCCESS | Server→Client | Authentication succeeded |
| 0x06 | AUTH_FAILURE | Server→Client | Authentication failed |
| 0x10 | GET | Client→Server | Get entity by key |
| 0x11 | PUT | Client→Server | Insert/update entity |
| 0x12 | DELETE | Client→Server | Delete entity by key |
| 0x13 | BATCH_GET | Client→Server | Get multiple entities |
| 0x14 | BATCH_PUT | Client→Server | Insert/update multiple entities |
| 0x20 | QUERY_AQL | Client→Server | Execute AQL query |
| 0x21 | QUERY_RESULT | Server→Client | Query result (single batch) |
| 0x22 | QUERY_CURSOR | Server→Client | Query result with cursor (streaming) |
| 0x23 | CURSOR_NEXT | Client→Server | Fetch next cursor batch |
| 0x24 | CURSOR_CLOSE | Client→Server | Close cursor |
| 0x30 | TRANSACTION_BEGIN | Client→Server | Start transaction |
| 0x31 | TRANSACTION_COMMIT | Client→Server | Commit transaction |
| 0x32 | TRANSACTION_ABORT | Client→Server | Abort transaction |
| 0x40 | VECTOR_SEARCH | Client→Server | Execute vector similarity search |
| 0x41 | GRAPH_TRAVERSE | Client→Server | Execute graph traversal |
| 0x50 | GEO_QUERY | Client→Server | Geospatial query (bbox, radius) |
| 0x51 | TIMESERIES_QUERY | Client→Server | Time-series aggregation |
| 0x60 | BPMN_START_PROCESS | Client→Server | Start BPMN process instance |
| 0x61 | BPMN_TASK_COMPLETE | Client→Server | Complete BPMN task |
| 0x62 | BPMN_QUERY_INSTANCE | Client→Server | Query process instance state |
| 0xF0 | ERROR | Server→Client | Error response |
| 0xF1 | OK | Server→Client | Success (no data) |
| 0xFE | PING | Bidirectional | Keepalive ping |
| 0xFF | CLOSE | Bidirectional | Close connection |
message HelloRequest {
uint32 protocol_version = 1; // 1 = v1
string client_name = 2; // "themis-python-native/1.0"
string client_version = 3; // "1.0.0"
repeated string capabilities = 4; // ["compression", "tls", "streaming"]
}message HelloAck {
uint32 protocol_version = 1;
string server_version = 2; // "ThemisDB/1.0.0"
repeated string capabilities = 3;
bool auth_required = 4;
}message AuthResponse {
string username = 1;
string password = 2; // Hashed (SCRAM-SHA-256)
string namespace = 3; // Default: "default"
map<string, string> metadata = 4; // Client metadata
}message GetRequest {
string model = 1; // "documents"
string collection = 2; // "articles"
string uuid = 3; // "doc_12345"
bool decrypt = 4; // Return decrypted entity
repeated string fields = 5; // Projection (empty = all fields)
}
message GetResponse {
bool found = 1;
bytes entity = 2; // Serialized entity (JSON or Protobuf)
uint64 version = 3; // MVCC version
uint64 timestamp_ns = 4; // Creation timestamp
}message PutRequest {
string model = 1;
string collection = 2;
string uuid = 3;
bytes entity = 4; // Serialized entity
bool encrypt = 5; // Enable encryption
uint64 expected_version = 6; // CAS (0 = any)
}
message PutResponse {
bool success = 1;
uint64 version = 2; // New MVCC version
string error = 3; // Error message (if success=false)
}message QueryRequest {
string aql = 1; // AQL query string
map<string, bytes> bind_vars = 2; // Bind variables
uint32 batch_size = 3; // Results per batch (default: 100)
bool stream = 4; // Enable cursor streaming
}
message QueryResult {
repeated bytes results = 1; // Array of serialized entities
bool has_more = 2; // More results available
string cursor_id = 3; // Cursor ID (if has_more=true)
uint64 count = 4; // Total result count (if available)
uint64 query_time_us = 5; // Query execution time
}message VectorSearchRequest {
string collection = 1;
repeated float vector = 2; // Query vector (384-dim, etc.)
uint32 k = 3; // Top-k results
string distance_metric = 4; // "cosine", "euclidean", "dot"
map<string, bytes> filters = 5; // Document filters
}
message VectorSearchResponse {
repeated VectorResult results = 1;
}
message VectorResult {
string uuid = 1;
float distance = 2;
bytes entity = 3; // Document content
}message GeoQueryRequest {
string collection = 1;
oneof query {
BoundingBox bbox = 2;
RadiusSearch radius = 3;
}
uint32 limit = 4;
}
message BoundingBox {
double min_lat = 1;
double min_lon = 2;
double max_lat = 3;
double max_lon = 4;
}
message RadiusSearch {
double center_lat = 1;
double center_lon = 2;
double radius_meters = 3;
}
message GeoQueryResponse {
repeated GeoResult results = 1;
}
message GeoResult {
string uuid = 1;
double latitude = 2;
double longitude = 3;
bytes entity = 4;
double distance_meters = 5; // Distance from query point
}message TimeSeriesQueryRequest {
string collection = 1;
uint64 start_time_ns = 2; // Start timestamp (nanoseconds)
uint64 end_time_ns = 3; // End timestamp
string aggregation = 4; // "avg", "sum", "min", "max", "count"
uint64 bucket_size_ns = 5; // Time bucket size
}
message TimeSeriesQueryResponse {
repeated TimeSeriesBucket buckets = 1;
}
message TimeSeriesBucket {
uint64 timestamp_ns = 1; // Bucket start time
double value = 2; // Aggregated value
uint64 count = 3; // Number of data points
}message BpmnStartProcessRequest {
string process_definition_key = 1;
map<string, bytes> variables = 2;
}
message BpmnStartProcessResponse {
string process_instance_id = 1;
string status = 2; // "running", "completed", "failed"
}
message BpmnTaskCompleteRequest {
string task_id = 1;
map<string, bytes> variables = 2;
}
message BpmnQueryInstanceRequest {
string process_instance_id = 1;
}
message BpmnQueryInstanceResponse {
string status = 1;
repeated BpmnTask active_tasks = 2;
map<string, bytes> variables = 3;
}
message BpmnTask {
string task_id = 1;
string task_name = 2;
string assignee = 3;
}message ErrorResponse {
uint32 error_code = 1; // ThemisDB error codes
string error_message = 2;
string error_detail = 3; // Stack trace (debug mode)
}| Code | Name | Description |
|---|---|---|
| 1000 | AUTHENTICATION_FAILED | Invalid credentials |
| 1001 | AUTHORIZATION_FAILED | Insufficient permissions |
| 2000 | ENTITY_NOT_FOUND | Entity does not exist |
| 2001 | ENTITY_ALREADY_EXISTS | Duplicate key violation |
| 2002 | VERSION_CONFLICT | CAS version mismatch (MVCC conflict) |
| 3000 | INVALID_QUERY | AQL syntax error |
| 3001 | QUERY_TIMEOUT | Query exceeded timeout |
| 4000 | TRANSACTION_CONFLICT | Transaction rollback |
| 5000 | INTERNAL_ERROR | Server-side error |
| 5001 | RESOURCE_EXHAUSTED | Out of memory, connections, etc. |
Client-side pooling:
- Maintain pool of persistent TCP connections
- Default pool size: 10 connections
- Idle timeout: 60 seconds
- Connection reuse reduces handshake overhead
Server-side limits:
- Max connections per client: 100 (configurable)
- Connection timeout: 300 seconds
- Max idle time: 120 seconds
Flag: 0x0002 (in message header)
Algorithm: LZ4 (fast compression/decompression)
Applies to: Payload only (not header)
Use case: Large query results (>1KB)
Flag: 0x0004 (in message header)
Algorithm: ChaCha20-Poly1305 (AEAD)
Key exchange: During AUTH_RESPONSE (ECDHE)
Use case: Sensitive data transmission
Note: Prefer TLS at transport layer
| Metric | HTTP/REST | Wire Protocol | Improvement |
|---|---|---|---|
| Handshake overhead | 3-5ms | 0.5-1ms | 5x faster |
| Serialization | JSON | Protobuf | 10-20x faster |
| GET latency | 1.5ms | 0.3ms | 5x faster |
| QUERY latency | 5ms | 1.2ms | 4x faster |
| Throughput (ops/sec) | 1000 | 10000 | 10x faster |
- ✅ Specification document (this)
- Protocol Buffer definitions
- C++ server-side parser (src/network/wire_protocol_server.cpp)
- Message dispatcher (OpCode routing)
- GET/PUT/DELETE implementation
- Error handling
- Connection pooling
- QUERY_AQL with cursors
- TRANSACTION support
- VECTOR_SEARCH integration
- Python native client (themis_native.py)
- Go client
- Java client
- GEO_QUERY implementation
- TIMESERIES_QUERY implementation (MVP - see wire_protocol_timeseries_integration.md)
- BPMN process engine integration
- Fair benchmarks vs PostgreSQL/MongoDB
- Performance tuning
- Production readiness
from themis_native import ThemisNativeClient
# Create client with binary protocol
client = ThemisNativeClient(
host="localhost",
port=8766, # Wire protocol port (not 8765 HTTP)
username="admin",
password="secret",
namespace="production"
)
# GET operation (binary, ~0.3ms)
entity = client.get(model="documents", collection="articles", uuid="doc_123")
# PUT operation (binary, ~0.4ms)
client.put(
model="documents",
collection="articles",
uuid="doc_456",
entity={"title": "New Article", "content": "..."}
)
# AQL Query (binary, ~1.2ms for 100 results)
results = client.query("""
FOR doc IN articles
FILTER doc.published == true
SORT doc.created_at DESC
LIMIT 100
RETURN doc
""")
# Vector search (binary, ~2ms for top-10)
results = client.vector_search(
collection="embeddings",
vector=[0.1, 0.2, ...], # 384-dim
k=10,
distance="cosine"
)
# Geospatial query (binary, ~1.5ms)
results = client.geo_query(
collection="locations",
bbox=(52.5, 13.4, 52.6, 13.5), # Berlin bounding box
limit=100
)
# Time-series aggregation (binary, ~3ms)
results = client.timeseries_query(
collection="metrics",
start_time=datetime(2025, 12, 1),
end_time=datetime(2025, 12, 4),
aggregation="avg",
bucket_size=timedelta(hours=1)
)
client.close()- Future Enhancements - Planned improvements for wire protocol and BPMN/process engine
- Implement Protocol Buffers schemas (themis.proto)
- C++ server handler (wire_protocol_server.cpp)
- Python native client (themis_native.py)
- Benchmark suite (geo, timeseries, BPMN)
- Documentation & examples
Status: Specification complete ✅
Next: Begin implementation (Phase 1)