Skip to content
makr-code edited this page Dec 21, 2025 · 1 revision

ThemisDB Wire Protocol v1 Specification

Version: 1.0.0
Date: December 4, 2025
Status: Draft - Implementation in Progress


Overview

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)

Connection Lifecycle

Client                          Server
  │                               │
  ├─────── HELLO ────────────────>│
  │                               │
  │<──── HELLO_ACK + AuthReq ────┤
  │                               │
  ├─────── AUTH_RESPONSE ────────>│
  │                               │
  │<────── AUTH_SUCCESS ──────────┤
  │                               │
  ├─────── QUERY (repeated) ─────>│
  │<────── RESPONSE ──────────────┤
  │                               │
  ├─────── CLOSE ────────────────>│
  │<────── CLOSE_ACK ─────────────┤
  │                               │

Message Framing

Every message uses a header + payload structure:

┌─────────────────────────────────────────┐
│         ThemisDB Wire Frame             │
├───────────┬──────────────┬──────────────┤
│  Header   │   Payload    │   Checksum   │
│  (12 B)   │  (variable)  │    (4 B)     │
└───────────┴──────────────┴──────────────┘

Header Format (12 bytes)

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

Checksum (4 bytes)

  • CRC32 checksum of (Header + Payload)
  • Detects transmission errors
  • Optional if using TLS (flag: 0x0001)

OpCodes

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 Payloads (Protocol Buffers)

HELLO Message

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"]
}

HELLO_ACK Message

message HelloAck {
  uint32 protocol_version = 1;
  string server_version = 2;     // "ThemisDB/1.0.0"
  repeated string capabilities = 3;
  bool auth_required = 4;
}

AUTH_RESPONSE Message

message AuthResponse {
  string username = 1;
  string password = 2;           // Hashed (SCRAM-SHA-256)
  string namespace = 3;          // Default: "default"
  map<string, string> metadata = 4; // Client metadata
}

GET Message

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
}

PUT Message

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)
}

QUERY_AQL Message

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
}

VECTOR_SEARCH Message

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
}

GEO_QUERY Message

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
}

TIMESERIES_QUERY Message

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
}

BPMN Messages

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;
}

ERROR Message

message ErrorResponse {
  uint32 error_code = 1;         // ThemisDB error codes
  string error_message = 2;
  string error_detail = 3;       // Stack trace (debug mode)
}

Error Codes

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.

Connection Pooling

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

Compression

Flag: 0x0002 (in message header)

Algorithm: LZ4 (fast compression/decompression)

Applies to: Payload only (not header)

Use case: Large query results (>1KB)


Encryption

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


Performance Characteristics

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

Implementation Roadmap

Phase 1: Core Protocol (Week 1-2)

  • ✅ Specification document (this)
  • Protocol Buffer definitions
  • C++ server-side parser (src/network/wire_protocol_server.cpp)
  • Message dispatcher (OpCode routing)

Phase 2: Basic Operations (Week 3)

  • GET/PUT/DELETE implementation
  • Error handling
  • Connection pooling

Phase 3: Advanced Features (Week 4)

  • QUERY_AQL with cursors
  • TRANSACTION support
  • VECTOR_SEARCH integration

Phase 4: Native Clients (Week 5-6)

  • Python native client (themis_native.py)
  • Go client
  • Java client

Phase 5: Extended Models (Week 7-8)

  • GEO_QUERY implementation
  • TIMESERIES_QUERY implementation
  • BPMN process engine integration

Phase 6: Benchmarking (Week 9)

  • Fair benchmarks vs PostgreSQL/MongoDB
  • Performance tuning
  • Production readiness

Example: Python Native Client Usage

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()

Next Steps

  1. Implement Protocol Buffers schemas (themis.proto)
  2. C++ server handler (wire_protocol_server.cpp)
  3. Python native client (themis_native.py)
  4. Benchmark suite (geo, timeseries, BPMN)
  5. Documentation & examples

Status: Specification complete ✅
Next: Begin implementation (Phase 1)

Navigation

Home

Architecture

Governance

Modules

Developer

Clone this wiki locally