← The Dry Stack

Code

The core is C++; you write your app in C# against thin, zero-copy wrappers. Every snippet below is lifted straight from the repo's samples — real API, not pseudo-code.

Facts — store & queryC#

Open a shard, batch-ingest a column, then run a SIMD scan and an aggregate — answers come back in microseconds.

// from tests/Facts.Smoke
using Dry.Facts;

Facts.LoadNative();

// One shard: a single F64 "value" column, tags 0..999, no ref payload.
using var db = new FactsDb();
db.Open(root, new[] { ShardSpec.WithColumns(tagMax: 999, hasRef: false, ColumnType.F64) });

// Ingest a batch: write the column, commit under a tag, flush.
var w = db.CreateBatchBuffer(0, 4096, withTimestamps: false)
          .Writer(db.AppenderFor(0));
for (int i = 0; i < 1_000_000; i++)
{
    w.ColumnSpan()[0] = BitConverter.DoubleToUInt64Bits(i * 0.5);
    w.Commit(tag: (uint)(i % 1000), refLen: 0);
}
w.Flush();

// Query: SIMD value-scan + a min/max/sum/mean aggregate.
var rdr  = db.ReaderFor(0);
var recs = new ReadRangeRecord[16384];
var cols = new ulong[16384];
uint hits = rdr.ScanValueF64(col: 0, CmpOp.Gt, 32700.0, 0, ulong.MaxValue, recs, default, cols);

ColStats st = rdr.AggValue(col: 0, 0, ulong.MaxValue);
Console.WriteLine($"{hits} hits, mean={st.Mean:F2}, max={st.Max}");
Nio — messagingC#

A request/response server and client. The blocking round-trip is ~6µs on loopback; batched events go out with no per-message copies.

// from samples/Example
NioUnsafe.Init(partitionCount: 8, cqSize: 1024);

// Server: answer PING with PONG.
var server = new Server(partitionId: 0);
server.Listen("127.0.0.1", 19000);
server.OnRequest = (Session s, uint seq, ushort type, ReadOnlySpan<byte> payload) =>
{
    if (type == TYPE_PING) s.Respond(seq, TYPE_PONG, payload);
};
server.Start();

// Client: blocking request/response (~6 us round-trip on loopback).
using var client = new Client(partitionId: 1);
client.Connect("127.0.0.1", 19000);
var reply = client.Query(TYPE_PING, ping);   // reply.TypeId == TYPE_PONG

// Fire millions of events with zero copies by batching into the TX slot.
using (var batch = client.BeginBatch())
    for (int i = 0; i < 32_000; i++)
        batch.SendEvent(TYPE_EVENT, payload);
File transfer — an app on NioC#

What you build on top: a full file & directory transfer server and client — list, upload, download whole trees — is a thin layer over Nio. This is essentially the whole thing.

// from samples/FtServer + samples/FtClient
using Dry.Nio;
using Dry.FileTransfer;

Nio.Init(partitionCount: 1, cqSize: 1024);

// Server: serve a directory.
var server = new FileTransferServer(partitionId: 0);
server.OnTransferComplete = path => Console.WriteLine($"[sent] {path}");
server.Listen("127.0.0.1", 22100, rootPath: "ftroot");
server.Start();

// Client: connect, then pull a file — or a whole tree.
using var client = new FileTransferClient(partitionId: 0);
client.Connect("127.0.0.1", 22100);

var r = client.Download("large.bin", "local.bin", overwrite: true);
Console.WriteLine($"{r.BytesReceived} bytes  success={r.Success}");

client.UploadDirectory("demo_docs", "uploads/docs", overwrite: true);
Zao — serializeC#

Tag a struct with [WireType]; the source generator emits WriteTo / ReadFrom / MaxSize at build time. Blittable types serialize at memcpy speed.

// from samples/Example2
using Dry.Zao;

// Declare a wire type — codegen does the rest, no reflection at runtime.
[WireType(0x01)]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public partial struct PlayerMoved
{
    public int   PlayerId;
    public float X, Y, Z;
}

var msg = new PlayerMoved { PlayerId = 42, X = 1.5f, Y = 2.5f, Z = -3f };

byte[] buf = new byte[PlayerMoved.MaxSize];
int n = msg.WriteTo(buf);                       // serialize  (tier-0: pure memcpy)
PlayerMoved back = PlayerMoved.ReadFrom(buf);   // deserialize

// Richer shapes just work too — strings, arrays, List<T>, Dictionary<K,V>.
Facts — the native coreC++

The same engine underneath the C# wrapper. The C ABI is what every language binds to; this is the Linux bring-up smoke test.

// from src/factslib/linux_smoke.cpp
#include "facts_db_capi.h"

ColumnDesc cols[1] = {};  cols[0].type = ColumnType::F64;
ShardConfig cfg{};
cfg.columns = cols;  cfg.n_columns = 1;  cfg.has_ref = 1;
cfg.tag_min = 0;     cfg.tag_max = 99;

facts_db_t* db = facts_db_create();
facts_db_open(db, root, &cfg, 1, 0);

facts_appender_t* ap = facts_db_appender(db);
for (uint64_t i = 0; i < N; ++i)
    facts_appender_append(ap, /*tag*/ i % 100, 0, &cv, 0, ref8, 8);
facts_db_flush(db);

facts_reader_t* rd = facts_db_reader_for(db, 0);
uint32_t got = facts_reader_scan_value(rd, /*col*/ 0, /*Gt*/ 1, f64_bits(0.0),
                                       0, UINT64_MAX, recs, pay, paycap, colv, reccap);
Want the full samples, or to build against it? info@drylane.io