Key/Value API
The key/value API provides a distributed, consistent data store for arbitrary binary data organized within namespaces. Built on Raft consensus, all operations guarantee strong consistency across the cluster, ensuring reads always return the most recently committed value.
Features
Section titled “Features”- Strong Consistency: All operations are linearizable through Raft consensus
- Namespace Isolation: Complete tenant separation with per-namespace authentication
- TTL Support: Automatic key expiration with background cleanup
- Atomic Operations: Compare-and-swap for optimistic concurrency control
- High Performance: Microsecond read latency with in-memory caching
- Durability: All writes replicated across majority of cluster nodes
create_namespace
Section titled “create_namespace”Creates a new namespace registered to the calling credential. The call is idempotent; requesting an existing namespace succeeds without modifying it.
message CreateNamespaceRequest { string namespace = 1;}
message CreateNamespaceResponse { string namespace = 1; Status status = 2;}
get_key
Section titled “get_key”Fetches the value for a key. Returns a NOT_FOUND
error if the key does not exist.
message GetKeyRequest { string key = 1; string namespace = 2;}
message GetKeyResponse { string key = 1; string namespace = 2; bytes value = 3; Status status = 4;}
put_key
Section titled “put_key”Stores or updates a key. Optional TTL expiry can be provided in milliseconds. A TTL of 0
means the value never expires. Writes are atomic and overwrite any existing value.
message PutKeyRequest { string key = 1; string namespace = 2; bytes value = 3; optional uint64 ttl_ms = 4; // Time to live in milliseconds}
message PutKeyResponse { string key = 1; Status status = 2;}
delete_key
Section titled “delete_key”Removes a key from the namespace. Deleting a missing key is treated as success so the operation is idempotent.
message DeleteKeyRequest { string key = 1; string namespace = 2;}
message DeleteKeyResponse { string key = 1; Status status = 2;}
list_keys
Section titled “list_keys”Returns the names of keys in the namespace. A prefix can be supplied to filter the results and limit
restricts the number of keys returned.
message ListKeysRequest { string prefix = 1; string namespace = 2; optional uint64 limit = 3; // Max number of keys to return}
message ListKeysResponse { repeated string keys = 1; Status status = 2;}
compare_and_swap
Section titled “compare_and_swap”Atomically update a key only if its current value matches the expected bytes. This can be used to implement optimistic concurrency for small payloads.
message CompareAndSwapRequest { string key = 1; string namespace = 2; bytes expected = 3; bytes newValue = 4;}
message CompareAndSwapResponse { string key = 1; string namespace = 2; bool swapped = 3; Status status = 4;}
SDK Examples
Section titled “SDK Examples”Python SDK
Section titled “Python SDK”import primatomic
# Connect to Primatomic Cloudclient = primatomic.Client("your-workspace.primatomic.com:443", jwt_token="your-api-token")
# Create namespace and store dataclient.create_namespace("myapp")
# Retrieve dataprofile = client.get_key("myapp", "user:123:profile")print(profile.decode('utf-8'))
# Atomic compare-and-swap for optimistic updatescurrent_value = client.get_key("myapp", "counter")success = client.compare_and_swap( namespace="myapp", key="counter", expected_value=current_value, new_value=str(int(current_value) + 1).encode())
# List keys with prefixuser_keys = client.list_keys("myapp", prefix="user:", limit=100)for key in user_keys: print(f"Found user key: {key}")
# TTL expiration (expire after 1 hour)client.put_key("myapp", "session:abc123", b"user_data", ttl_ms=3600000)
JavaScript SDK
Section titled “JavaScript SDK”Coming soon - JavaScript SDK is in development. For early access, contact us.
Error Handling
Section titled “Error Handling”Common error codes returned by the key/value API:
NOT_FOUND
: Requested key does not exist in the namespacePERMISSION_DENIED
: Invalid credential ID or insufficient namespace accessALREADY_EXISTS
: Namespace creation failed because it already existsDEADLINE_EXCEEDED
: Operation timeout, typically during cluster unavailabilityUNAVAILABLE
: Cluster is not ready or no leader elected
Performance Considerations
Section titled “Performance Considerations”- Batch Operations: Use concurrent requests for multiple independent operations
- Key Design: Choose meaningful prefixes for efficient listing and organization
- TTL Usage: Prefer TTL over manual deletion for temporary data
- Size Limits: Key names limited to 1KB, values limited to 16MB per operation
- Concurrent Access: Use compare-and-swap for conflict resolution instead of explicit locking