Java Client
The Java client is a blocking, java.net.Socket-based driver with no runtime dependencies, paired with a thread-safe VeltrixDBPool for use from multi-threaded servers.
Install
Maven:
xml<dependency> <groupId>com.veltrixdb</groupId> <artifactId>veltrixdb-client</artifactId> <version>1.0.0</version> </dependency>
Gradle:
groovyimplementation 'com.veltrixdb:veltrixdb-client:1.0.0'
Requires Java 11+ at runtime (the client source is compiled targeting Java 17 in its own build). No runtime dependencies — VeltrixDBClient is built on plain java.net.Socket/javax.net.ssl.
Quick start
This example follows the class's own documented usage in VeltrixDBClient.java: open a connection, ping, then put/get/delete. VeltrixDBClient implements Closeable, so try-with-resources closes the socket automatically.
javaimport com.veltrixdb.client.VeltrixDBClient; // Single connection (not thread-safe — use VeltrixDBPool for concurrent access) try (VeltrixDBClient c = new VeltrixDBClient("127.0.0.1", 9000)) { c.ping(); c.put("hello", "world".getBytes()); byte[] val = c.get("hello"); // null if not found System.out.println(new String(val)); // "world" c.delete("hello"); }
Config
VeltrixDBClient.Config lets you set timeouts and TLS explicitly instead of using the two-argument constructor:
javaVeltrixDBClient.Config cfg = new VeltrixDBClient.Config(); cfg.host = "prod-veltrix.internal"; cfg.port = 9000; cfg.connectTimeoutMs = 3_000; // TCP connect timeout (default 5000) cfg.socketTimeoutMs = 5_000; // per-operation read timeout (default 10000, 0 = none) cfg.sslContext = null; // non-null = TLS VeltrixDBClient c = new VeltrixDBClient(cfg);
API surface
Every data method throws IOException (network failure) and VeltrixDBException (server-side error response). These are checked exceptions in the actual source, so calling code must declare or catch them.
Core key-value
| Method | Description |
|---|---|
ping() | Check connection health |
put(key, value) | Write a key |
get(key) | Read a key. Returns null if not found |
delete(key) | Delete a key (no-op if already absent) |
info() | Get server stats string |
auth(user, pass) | Authenticate |
close() | Close the underlying socket (safe to call more than once) |
isClosed() | Whether the socket has been closed |
Batch operations
| Method | Description |
|---|---|
multiPut(entries) | Write multiple keys. Returns Exception[] (null = success) |
multiGet(keys) | Read multiple keys. Returns MultiGetResult[] |
Entry and MultiGetResult are static nested classes on VeltrixDBClient:
javaimport com.veltrixdb.client.VeltrixDBClient.Entry; import java.util.List; List<Entry> entries = List.of( new Entry("user:1", "{\"name\":\"Alice\"}".getBytes()), new Entry("user:2", "{\"name\":\"Bob\"}".getBytes(), 60) // TTL 60s ); Exception[] errors = c.multiPut(entries); // errors[i] is null if that entry succeeded VeltrixDBClient.MultiGetResult[] results = c.multiGet(List.of("user:1", "user:missing")); // results[i].found is false, results[i].value is null when not found
Namespaces
| Method | Description |
|---|---|
putNS(ns, key, value, ttl) | Write into a namespace |
getNS(ns, key) | Read from a namespace |
deleteNS(ns, key) | Delete from a namespace |
scanNamespace(ns, prefix, limit) | Scan keys in a namespace, returns NSEntry[] |
listNamespaces() | List namespaces, returns NSInfo[] |
dropNamespace(ns) | Delete all keys in a namespace; returns the deleted count |
Hash fields (per-field TTL)
| Method | Description |
|---|---|
hset(key, field, value, ttl) | Set a field with its own TTL |
hget(key, field) | Get a field value (null if not found/expired) |
hdel(key, field) | Delete one field |
hgetAll(key) | Get all live fields as HashField[] |
hkeys(key) | Get all live field names as String[] |
hlen(key) | Count live fields |
hexpire(key, field, ttl) | Update TTL of an existing field |
httl(key, field) | Remaining TTL (-1=forever, -2=not found) |
Atomic operations
New in v1.1.0 — typed atomic ops (previously Rust/C++ only). Each method has an overload with a trailing ttlSeconds for the stored value (≤ 0 = no expiry); like the rest of the API, all of them throw IOException and VeltrixDBException:
| Method | Description |
|---|---|
cas(key, expected, newValue) / cas(key, expected, newValue, ttlSeconds) | Compare-and-swap; returns a CasResult enum: SWAPPED, MISMATCH, or NOT_FOUND |
incr(key) / incr(key, delta) / incr(key, delta, ttlSeconds) | Atomically add delta (default 1); returns the new value as long. Missing keys start from 0 |
decr(key) / decr(key, delta) / decr(key, delta, ttlSeconds) | Atomically subtract delta (default 1); returns the new value as long. Missing keys start from 0 |
setnx(key, value) / setnx(key, value, ttlSeconds) | Set only if absent; returns true when the key was created, false when it already existed |
CasResult is a nested enum on VeltrixDBClient:
javaimport com.veltrixdb.client.VeltrixDBClient.CasResult; // Counter — missing key starts from 0 long n = c.incr("counter", 5); // 5 n = c.decr("counter", 2); // 3 // Compare-and-swap CasResult r = c.cas("hello", "world".getBytes(), "earth".getBytes()); switch (r) { case SWAPPED: System.out.println("replaced"); break; case MISMATCH: System.out.println("value did not match"); break; case NOT_FOUND: System.out.println("key does not exist"); break; } // Set-if-absent with a 30-second TTL (lock-style) boolean acquired = c.setnx("lock", "owner-A".getBytes(), 30);
Connection pool (thread-safe)
VeltrixDBPool wraps an ArrayBlockingQueue<VeltrixDBClient> and pre-dials poolSize connections in its constructor. This is the class's own documented quick start:
javaimport com.veltrixdb.client.VeltrixDBPool; VeltrixDBPool.Config cfg = new VeltrixDBPool.Config(); cfg.host = "127.0.0.1"; cfg.port = 9000; cfg.poolSize = 16; try (VeltrixDBPool pool = new VeltrixDBPool(cfg)) { // Functional style — acquire/release handled automatically pool.execute(c -> { c.put("key", "value".getBytes()); return null; }); byte[] val = pool.execute(c -> c.get("key")); }
Manual acquire/release is also supported when you need to hold a connection across multiple calls:
javaVeltrixDBClient c = pool.acquire(); try { c.put("x", data); pool.release(c); } catch (Exception e) { c.close(); // broken conn — don't return to pool pool.replenish(); // replace it throw e; }
VeltrixDBPool.Config extends VeltrixDBClient.Config, adding poolSize (default 8), acquireTimeoutMs (default 5000), and optional username/password for auto-auth on every new connection. pool.available() reports the current idle-connection count.
TLS
javaimport javax.net.ssl.*; import java.security.KeyStore; // Server-only verification SSLContext ctx = SSLContext.getInstance("TLS"); TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); KeyStore ks = KeyStore.getInstance("JKS"); ks.load(new FileInputStream("truststore.jks"), "password".toCharArray()); tmf.init(ks); ctx.init(null, tmf.getTrustManagers(), null); VeltrixDBClient.Config cfg = new VeltrixDBClient.Config(); cfg.host = "veltrix.example.com"; cfg.port = 9443; cfg.sslContext = ctx; VeltrixDBClient c = new VeltrixDBClient(cfg);
Auth
java// Single connection VeltrixDBClient c = new VeltrixDBClient("127.0.0.1", 9000); c.auth("alice", "secret"); c.put("key", "value".getBytes()); // Pool with auto-auth VeltrixDBPool.Config cfg = new VeltrixDBPool.Config(); cfg.username = "alice"; cfg.password = "secret"; VeltrixDBPool pool = new VeltrixDBPool(cfg); // all connections auto-auth on connect
Error handling
javatry { byte[] val = c.get("key"); if (val == null) { // key not found — not an exception } } catch (VeltrixDBException e) { // server returned an error status } catch (java.net.SocketTimeoutException e) { // operation timed out } catch (java.io.EOFException e) { // connection dropped by the server }
VeltrixDBException (extends Exception) is thrown for any non-OK, non-NOT_FOUND status the server returns; it optionally wraps a lower-level Throwable cause. Missing keys and missing hash fields return null rather than throwing — check for null first.