{"id":13672492,"url":"https://github.com/arthurprs/sucredb","last_synced_at":"2026-01-03T04:25:02.504Z","repository":{"id":148368646,"uuid":"83230088","full_name":"arthurprs/sucredb","owner":"arthurprs","description":"Distributed KV database with causality tracking","archived":false,"fork":false,"pushed_at":"2018-10-21T11:00:31.000Z","size":830,"stargazers_count":58,"open_issues_count":6,"forks_count":5,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-11-11T10:42:29.905Z","etag":null,"topics":["consistency","crdt","database","dynamo","eventually-consistent","key-value","redis","rust","vector-clocks"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arthurprs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-02-26T18:14:34.000Z","updated_at":"2024-10-02T19:41:44.000Z","dependencies_parsed_at":"2023-05-19T21:45:32.298Z","dependency_job_id":null,"html_url":"https://github.com/arthurprs/sucredb","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arthurprs%2Fsucredb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arthurprs%2Fsucredb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arthurprs%2Fsucredb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arthurprs%2Fsucredb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arthurprs","download_url":"https://codeload.github.com/arthurprs/sucredb/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251219601,"owners_count":21554444,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["consistency","crdt","database","dynamo","eventually-consistent","key-value","redis","rust","vector-clocks"],"created_at":"2024-08-02T09:01:37.169Z","updated_at":"2026-01-03T04:25:02.436Z","avatar_url":"https://github.com/arthurprs.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"# Sucredb\n\n\u003e *A database made of sugar cubes*\n\n[![Build Status](https://travis-ci.org/arthurprs/sucredb.svg?branch=master)](https://travis-ci.org/arthurprs/sucredb)\n\nSucredb is a multi-master key-value distributed database, it provides a dynamo style tunable consistent and causality tracking.\n\nAny node that owns a partition (replicas) can serve both reads and writes. The database tracks causality using vector-clocks and will NOT drop any conflicting writes unlike LWW (last write wins) and other strategies. Conflicts can and do happen due to races between clients and network partitions.\n\nStatus: Alpha quality with missing pieces.\n\n# API \u0026 Clients\n\nTheoretically you can use Sucredb with any Redis Cluster clients.\n\nIt implements a tiny subset of Redis commands. Only basic Key-Value/Sets/Hashes operations are supported at this point.\n\n### Key Value\n\n#### GET\n\n*GET* result(s) is/are returned as an array containing the values (zero, one or more if there's conflicting versions) plus the causal context. The context is an binary string and is always returned as the last item of the array even if no values are present.\n\n`\u003e GET key {consistency}`\n\n`\u003c [{value1}, {value2}, .., context]`\n\n#### MGET\n\n*MGET* takes the # of keys (N) followed by N keys. Results are returned as an array.\n\n\n`\u003e MGET key_count {key1} {key2} {..} {consistency}`\n\n`\u003c [[{value1_1}, {value1_2}, .., context], [{value2_1}, {value2_2}, .., context]]`\n\n#### SET\n\n*SET*, in addition to the key and value, also takes the causal context. If you're sure it don't exist you can actually omit the context, if you're wrong it'll create a conflicting version.\n\n`\u003e SET key value {context} {consistency}`\n\n`\u003c OK`\n\n#### GETSET\n\n*GETSET* is similar to set, but returns the updated value(s) and a new context. Despite the name and the semantics in Redis, the get is always done *after* the set.\n\n`\u003e GETSET key value context {consistency}`\n\n`\u003c [{value1}, {value2}, .., context]`\n\n#### DEL\n\n*DEL* is like set and also requires a context when dealing with basic values.\nFollowing Redis api *del* works for keys with any datastructure, in these cases the context is ignored (you can use an empty string instead).\n\n`\u003e DEL key context {consistency}`\n\n`\u003c 1 OR 0 (if not found)`\n\n### Data structures\n\nSucredb also supports a tiny subset of commands for Hash and Set datatypes in addition to a dedicated Counter type. These types are [CRDTs](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type) and don't require a context to be sent along the operation. Mutations depend on the coordinator version of the value and conflicts are handled as follow:\n\n* Hash: On values conflict the latest write wins.\n* Set: On values conflict add wins.\n* Counter: Deletes may erase non observed increments.\n\n### CGET\n\nReturns the value for a counter or Nil if none is found.\n\n`\u003e GET key {consistency}`\n\n`\u003c 1011`\n\n### CSET\n\nSets the value for a counter.\n\n`\u003e SET key int_value {consistency}`\n\n`\u003c OK`\n\n### INCRBY\n\nIncrements the value for a counter, the delta can be either positive or negative.\n\n`\u003e INCRBY key delta_value {consistency}`\n\n`\u003c resulting_int_value`\n\n#### HGETALL\n\nGets all key value pairs from a hash.\n\n`\u003e HGETALL key {consistency}`\n\n`\u003c [{KA, VA}, {KB, VB}, ...]`\n\n#### HSET\n\nSet key a value pair in a hash.\n\n`\u003e HSET key hash_key value {consistency}`\n\n`\u003c 1 OR 0 (if hash_key already existed) `\n\n#### HDEL\n\nDeletes a key from a hash.\n\n`\u003e HDEL key hash_key {consistency}`\n\n`\u003c 1 OR 0 (if hash_key didn't exist)`\n\n#### SMEMBERS\n\nGets all values from a set.\n\n`\u003e SMEMBERS key {consistency}`\n\n`\u003c [{KA}, {KB}, ...]`\n\n#### SADD\n\nAdds a value from the set.\n\n`\u003e SADD key value {consistency}`\n\n`\u003c 1 OR 0 (if value already existed) `\n\n#### SREM\n\nRemoves a value from the set.\n\n`\u003e SREM key value {consistency}`\n\n`\u003c 1 OR 0 (if value didn't exist) `\n\n### MULTI/EXEC Batches\n\ntodo\n\n### Other parameters\n\n#### `context` parameter\n\nIf you don't have a context (from a previous get or getset) you can send an empty string.\n\n#### `consistency` parameter\n\n`{consistency}` follows the dynamo/cassandra/riak style:\n\n* `1`, `o`, `O`: One\n* `q`, `Q`: Quorum\n* `a`, `A`: All\n\n# Running\n\n**Requirements**\n\n* Needs a reasonably recent Rust (nightly[2])\n* C++ compiler (for Rocksdb).\n\n**Running**\n\n* The following setup will use the default settings.\n* Clone the repo and enter repository root\n* `cargo install .` [3]\n* `sucredb --help`\n\nSingle/First instance\n\n`sucredb -d datadir1 -l 127.0.0.1:6379 -f 127.0.0.1:16379 init`\n\nThe command above will initialize a new cluster containing this node. The cluster will have the default name, partition count and replication factor.\n\nSecond instance\n\n`sucredb -d datadir2 -l 127.0.0.1:6378 -f 127.0.0.1:16378 -s 127.0.0.1:16379`\n\nThe second instance joins the cluster using the first instance as a seed.\n\nQuick test\n\n`redis-cli CLUSTER SLOTS`\n\n#### Example\n\nQuick example using *redis-cli*\n\n```\n➜  ~ redis-cli\n127.0.0.1:6379\u003e GET there\n1) \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n127.0.0.1:6379\u003e SET there 1 \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\nOK\n127.0.0.1:6379\u003e GET there\n1) \"1\"\n2) \"\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00P\\xb0n\\x83g\\xef`\\n\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n127.0.0.1:6379\u003e SET there 2\nOK\n127.0.0.1:6379\u003e GET there 1\n1) \"1\"\n2) \"2\"\n3) \"\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00P\\xb0n\\x83g\\xef`\\n\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n127.0.0.1:6379\u003e SET there 3 \"\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00P\\xb0n\\x83g\\xef`\\n\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\nOK\n127.0.0.1:6379\u003e GET there\n1) \"3\"\n2) \"\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00P\\xb0n\\x83g\\xef`\\n\\x03\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n127.0.0.1:6379\u003e GETSET there 4 \"\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00P\\xb0n\\x83g\\xef`\\n\\x03\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n1) \"4\"\n2) \"\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00P\\xb0n\\x83g\\xef`\\n\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n127.0.0.1:6379\u003e DEL there \"\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00P\\xb0n\\x83g\\xef`\\n\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n1\n127.0.0.1:6379\u003e GET there q\n1) \"\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00P\\xb0n\\x83g\\xef`\\n\\x05\\x00\\x00\\x00\\x00\\x00\\x00\\x00\n```\n\n# Configuration\n\nSee `sucredb.yaml`\n\nTo use configuration file use: `sucredb -c sucredb.yaml`\n\n# CAP theorem\n\nIt behaves mostly like an AP system but not exactly.\n\nSucredb doesn't use sloppy quorum or hinted handoff so it can't serve requests that don't satisfy the requested/default consistency level.\n\n# Performance\n\nAlmost every single new thing claims to be fast or blazing fast. Sucredb makes no claims at this point, but it's probably fast.\n\nThe data structure operations move the entire collection around the cluster so it's *not* suitable for large values/collections.\n\n# Ideas worth exploring\n\n* Improve the data model with a range/clustering key.\n\n# Background\n\nStorage takes advantage of RocksDB.\n\nIt uses a variant of version clocks to track causality. The actual algorithm is heavily inspired by [1].\n\n----\n\n[1] Gonçalves, Ricardo, et al. \"Concise server-wide causality management for eventually consistent data stores.\"\n\n[2] Mostly due to the try_from and impl trait features that should be stable soon.\n\n[3] Be patient.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farthurprs%2Fsucredb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farthurprs%2Fsucredb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farthurprs%2Fsucredb/lists"}