Use the C SDK
Applies to: current development source bundles. Obtain a matched client/server release through early-access support; registry publication is not available yet. Paths below are relative to the supplied source checkout.
C11/POSIX application client and shared transport for the Java, .NET, and PHP bindings. Source release, ABI 1; not published to a package repository. Linux and macOS build targets; macOS arm64 is currently validated.
Build and install
Requires a C compiler, Make, POSIX threads, OpenSSL 3+, and json-c 0.16+.
On Debian/Ubuntu install build-essential libssl-dev libjson-c-dev.
On Apple Silicon macOS install openssl@3 json-c with Homebrew.
make -C c-smkv
make -C c-smkv install PREFIX=/your/install/prefix
Headers go in include/, the shared library in lib/. Keep the matching
OpenSSL/json-c runtime libraries installed. On Linux run your distribution's
loader-cache setup or set LD_LIBRARY_PATH to your chosen library directory.
On macOS the library has an @rpath install name; give applications an rpath.
Override CPPFLAGS/LDFLAGS or DEPS_PREFIX for other dependency locations.
Binary API
#include <smkv.h>
#include <stdio.h>
int main(void) {
int error;
smkv_client *client = smkv_create("{\"endpoint\":\"127.0.0.1:7379\"}", &error);
if (!client) return 1;
smkv_result result;
int code = smkv_call(client, 2, "greeting", 8, "hello", 5,
UINT64_MAX, 1, 0, &result);
smkv_free(result.data);
if (!code) {
code = smkv_call(client, 1, "greeting", 8, NULL, 0,
UINT64_MAX, 0, 0, &result);
if (!code) fwrite(result.data, 1, result.length, stdout);
smkv_free(result.data);
}
smkv_destroy(client);
return code != 0;
}
Link with -I.../include -L.../lib -lsmkv and the appropriate loader path.
A zero-length successful value differs from SMKV_NOT_FOUND. Output buffers must
be released with smkv_free, even when empty (NULL is allowed).
smkv_call opcodes: 1 get, 2 put, 3 delete, 4 row get, 5 row put, 6 row update,
7 row delete. Raw row operations require wire-encoded keys and values; use the
JSON API below to avoid manual row encoding. Flags: 1 local sync, 2 replica ack,
4 durable replica ack (also set 2). TTL is milliseconds; UINT64_MAX means omitted,
zero expires immediately. Omitted TTL preserves expiry on update, clears it on put.
Delete/get must omit TTL. Replica reads are explicitly selected with replica=1.
Configuration, routing, and security
Use either endpoint for direct connections or seeds for management discovery:
{
"seeds": ["10.0.0.1:7381", "10.0.0.2:7381"],
"timeout_ms": 5000,
"max_key_bytes": 1024,
"max_value_bytes": 1048576,
"security": {"ca": "/etc/smkv/ca.pem", "name": "app", "token": "FROM_SECRET_PROVIDER"},
"management_security": {"ca": "/etc/smkv/ca.pem", "name": "app", "token": "FROM_SECRET_PROVIDER"}
}
The token shown is a placeholder: real tokens must match server configuration and
contain 32–256 printable ASCII characters. TLS and auth are independently optional.
Omit ca for plaintext, omit name/token for no auth. TLS validates the supplied
CA and hostname/IP and never downgrades; data and management profiles are independent.
Cluster discovery is lazy on the first operation. CRC32 routes the complete key (including the table for rows). Only explicit WrongOwner responses trigger retries. Maps must agree on cluster identity, partition count, and each observed epoch; stale-only observations are rejected. Discovery probes seeds sequentially with a 500 ms per-seed cap within the total deadline. Epochs above INT64_MAX are rejected.
JSON convenience ABI
smkv_request_json(client, request) returns allocated UTF-8 JSON; free it with
smkv_free. Request fields: numeric op, hex key, optional value (hex),
flags, ttl_ms (decimal string), and replica (bool). Rows also use table.
Row gets use an optional columns array for projection; puts/updates use a
columns object of tagged values, and updates may include a remove array.
{"op":5,"table":"users","key":"3432","columns":{
"name":{"t":"s","v":"Ada"},
"visits":{"t":"i","v":"1"},
"payload":{"t":"b","v":"00ff"},
"active":{"t":"bool","v":true},
"ratio":{"t":"f","v":"000000000000f43f"}
}}
i uses a signed int64 decimal string; f uses eight little-endian IEEE754 bytes
in hex. Responses contain code, unknown, and successful value or columns.
Server diagnostics and tokens are deliberately excluded from errors.
Lifecycle and limits
One handle serializes requests and retains at most one TCP connection. Use a bounded application pool of handles for concurrency; this initial SDK does not provide a multi-connection pool. Switching owners reconnects. There is no async API, scan API, batch API, Windows qualification, or throughput claim yet.
The deadline includes lock wait, discovery, connect, and I/O. Native DNS cannot be
interrupted; use IP addresses for strict bounds. smkv_close interrupts active I/O
and rejects queued operations. Stop all callers before smkv_destroy; never use a
destroyed pointer. Do not share clients across fork.
Positive error codes match server statuses. Negative codes are defined in
smkv.h. outcome_unknown means a mutation may have completed; never blindly
retry it. No uncertain mutation is automatically replayed. Successful default
writes do not request per-write fsync.
Run python3 c-smkv/tests/test_native.py after building for ABI fault tests and
see cross-language qualification.