Home/Packages/HoloDb.Protocol

HoloDb.Protocol · data

Columns stay columns, all the way to the client.

HoloDb.Protocol defines how the HoloDb server and client communicate. Instead of sending results as JSON or row-by-row data structures, it preserves the columnar shape: a long[], double[], or string[] travels as a typed array over the wire, not as individual objects — keeping HoloDb's columnar advantage intact when data moves between processes.

v1.0.2 net8.0+ length-prefixed TCP framing transport-agnostic (TLS-ready)
dotnet add package EvaluatedApplications.HoloDb.Protocol

Most consumers should depend on HoloDb.Client instead, which pulls this package in transitively. Depend on it directly only if you're implementing a server.

Why it matters

the win doesn't stop at the wire

Most database protocols trade columnar performance for JSON or ORM convenience. If you run a columnar query — the common case — and the server has to serialize it back to rows, materialize it into objects, and send JSON, you've lost the performance win that made the columnar query fast in the first place. This protocol keeps that win alive. It also encodes the wire format explicitly — no framework assumptions about object graphs or reflection — which makes it predictable (you know exactly what bytes cross the network), versionable (clients and servers from different builds detect incompatibility and fail cleanly), and testable (every message shape can be validated bit-for-bit).

What it does

features

Columnar results

long[], double[], string[] delivered directly, not wrapped in row objects.

Materialized rows

For non-columnar queries (JOINs, GROUP BY), results are packed into a compact binary row format.

Length-prefixed frames

Message boundaries stay safe even over unreliable transports or when connection buffering breaks alignment.

Transport-agnostic

Works over TCP, TLS, or any duplex Stream — this package doesn't provide encryption; TLS is the transport layer's concern.

Security hardening

Frame size limits and count-bounds checks protect against hostile or malformed length prefixes forcing huge allocations.

Version negotiation

Client and server compatibility is checked before executing queries, and error semantics distinguish protocol errors from query errors so callers know whether to retry.

A minimal example

client and server side

Client-side (using HoloDb.Client, which wraps this protocol):

using var client = new HoloDbClient("localhost", 5433, token: "mytoken"); await client.ConnectAsync(); // Result comes back as a columnar QueryResult if the query was columnar. var result = await client.ExecuteAsync("SELECT * FROM prices WHERE date > ?", new[] { arg }); if (result.IsColumnar && result.Columns["price"] is double[] prices) { foreach (var p in prices) Console.WriteLine($"Price: {p}"); }

Server-side (using this package to build a server):

var payload = await Wire.ReadFrameAsync(networkStream); var request = HoloProtocol.DecodeRequest(payload); if (request.Op == WireOp.Exec) { var result = await engine.ExecuteAsync(request.Sql); var response = HoloProtocol.Result(result); await Wire.WriteFrameAsync(networkStream, response); }

Compatibility & wire stability

frozen on purpose

The wire format is frozen: opcode byte values never change, and message field order and types are stable. Old clients can talk to new servers (version negotiation detects incompatibility and fails cleanly), and changes to the protocol are rare and coordinated — both client and server must be rebuilt together.

Depends on: HoloDb (for the QueryResult type that crosses the wire in both directions). Auth tokens travel as plain UTF-8 in the Hello handshake — TLS is assumed by the deployment, not provided by this package. License: proprietary; every capability is free to use today.