{"id":13563856,"url":"https://github.com/lucaong/cubdb","last_synced_at":"2025-05-15T11:05:55.366Z","repository":{"id":39790368,"uuid":"192218862","full_name":"lucaong/cubdb","owner":"lucaong","description":"Elixir embedded key/value database","archived":false,"fork":false,"pushed_at":"2024-10-02T13:51:05.000Z","size":11888,"stargazers_count":592,"open_issues_count":13,"forks_count":28,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-04-03T21:43:24.344Z","etag":null,"topics":["acid","atomic-transactions","database","elixir","embedded","key-value","key-value-store","mvcc","nerves"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lucaong.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-06-16T17:32:50.000Z","updated_at":"2025-03-31T12:29:29.000Z","dependencies_parsed_at":"2024-11-20T11:29:12.014Z","dependency_job_id":null,"html_url":"https://github.com/lucaong/cubdb","commit_stats":{"total_commits":416,"total_committers":8,"mean_commits":52.0,"dds":0.09855769230769229,"last_synced_commit":"4024767153a856e938e77561a4d80fb247015350"},"previous_names":[],"tags_count":41,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lucaong%2Fcubdb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lucaong%2Fcubdb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lucaong%2Fcubdb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lucaong%2Fcubdb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lucaong","download_url":"https://codeload.github.com/lucaong/cubdb/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248441906,"owners_count":21104099,"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":["acid","atomic-transactions","database","elixir","embedded","key-value","key-value-store","mvcc","nerves"],"created_at":"2024-08-01T13:01:23.994Z","updated_at":"2025-04-11T16:39:22.831Z","avatar_url":"https://github.com/lucaong.png","language":"Elixir","funding_links":[],"categories":["Miscellaneous","Tools"],"sub_categories":["Mesh networks"],"readme":"\u003cp align=\"center\"\u003e\u003cimg src=\"assets/cubdb_banner.png\" width=\"80%\"/\u003e\u003c/p\u003e\n\n[![Build Status](https://github.com/lucaong/cubdb/workflows/CI%20Build/badge.svg)](https://github.com/lucaong/cubdb/actions)\n[![Coverage Status](https://coveralls.io/repos/github/lucaong/cubdb/badge.svg?branch=master\u0026cachebust=3)](https://coveralls.io/github/lucaong/cubdb?branch=master)\n[![Module Version](https://img.shields.io/hexpm/v/cubdb.svg)](https://hex.pm/packages/cubdb)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-blue.svg)](https://hexdocs.pm/cubdb/)\n[![License](https://img.shields.io/hexpm/l/cubdb.svg)](https://github.com/lucaong/cubdb/blob/master/LICENSE)\n\n`CubDB` is an embedded key-value database for the Elixir language. It is\ndesigned for robustness, and for minimal need of resources.\n\nHead to the [API reference](https://hexdocs.pm/cubdb/CubDB.html) for usage\ndetails, or read the [Frequently Asked\nQuestions](https://hexdocs.pm/cubdb/faq.html) and the [How To\nsection](https://hexdocs.pm/cubdb/howto.html) for more information.\n\n\n## Features\n\n  - Both keys and values can be any Elixir (or Erlang) term.\n\n  - Basic `get`, `put`, and `delete` operations, selection of ranges of entries\n    sorted by key with `select`.\n\n  - Atomic, Consistent, Isolated, Durable (ACID) transactions.\n\n  - Multi version concurrency control (MVCC) allowing concurrent read\n    operations, that do not block nor are blocked by writes.\n\n  - Unexpected shutdowns or crashes won't corrupt the database or break\n    atomicity of transactions.\n\n  - Manual or automatic compaction to reclaim disk space.\n\nTo ensure consistency, performance, and robustness to data corruption, `CubDB`\ndatabase file uses an append-only, immutable B-tree data structure. Entries are\nnever changed in-place, and read operations are performed on zero cost immutable\nsnapshots.\n\n\n## Usage\n\nStart `CubDB` by specifying a directory for its database file (if not existing,\nit will be created):\n\n```elixir\n{:ok, db} = CubDB.start_link(data_dir: \"my/data/directory\")\n```\n\n\u003e #### Important {: .warning}\n\u003e\n\u003e Avoid starting multiple `CubDB` processes on the same data\n\u003e directory. Only one `CubDB` process should use a specific data directory at any\n\u003e time.\n\n`get`, `put`, and `delete` operations work as you probably expect:\n\n```elixir\nCubDB.put(db, :foo, \"some value\")\n#=\u003e :ok\n\nCubDB.get(db, :foo)\n#=\u003e \"some value\"\n\nCubDB.delete(db, :foo)\n#=\u003e :ok\n\nCubDB.get(db, :foo)\n#=\u003e nil\n```\n\nMultiple operations can be performed atomically with the `transaction` function\nand the `CubDB.Tx` module:\n\n```elixir\n# Swapping `:a` and `:b` atomically:\nCubDB.transaction(db, fn tx -\u003e\n  a = CubDB.Tx.get(tx, :a)\n  b = CubDB.Tx.get(tx, :b)\n\n  tx = CubDB.Tx.put(tx, :a, b)\n  tx = CubDB.Tx.put(tx, :b, a)\n\n  {:commit, tx, :ok}\nend)\n#=\u003e :ok\n```\n\nAlternatively, it is possible to use `put_multi`, `delete_multi`, and the other\n`[...]_multi` functions, which also guarantee atomicity:\n\n```elixir\nCubDB.put_multi(db, [a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8])\n#=\u003e :ok\n```\n\nRange of entries sorted by key are retrieved using `select`:\n\n```elixir\nCubDB.select(db, min_key: :b, max_key: :e) |\u003e Enum.to_list()\n#=\u003e [b: 2, c: 3, d: 4, e: 5]\n```\n\nThe `select` function can select entries in normal or reverse order, and returns\na lazy stream, so one can use functions in the `Stream` and `Enum` modules to\nmap, filter, and transform the result, only fetching from the database the\nrelevant entries:\n\n```elixir\n# Take the sum of the last 3 even values:\nCubDB.select(db, reverse: true) # select entries in reverse order\n|\u003e Stream.map(fn {_key, value} -\u003e value end) # discard the key and keep only the value\n|\u003e Stream.filter(fn value -\u003e is_integer(value) \u0026\u0026 Integer.is_even(value) end) # filter only even integers\n|\u003e Stream.take(3) # take the first 3 values\n|\u003e Enum.sum() # sum the values\n#=\u003e 18\n```\n\nRead-only snapshots are useful when one needs to perform several reads or\nselects, ensuring isolation from concurrent writes, but without blocking them.\nWhen nothing needs to be written, using a snapshot is preferable to using a\ntransaction, because it will not block writes.\n\nSnapshots come at no cost: nothing is actually copied or written on disk or in\nmemory, apart from some small internal bookkeeping. After obtaining a snapshot\nwith `with_snapshot`, one can read from it using the functions in the\n`CubDB.Snapshot` module:\n\n```elixir\n# the key of y depends on the value of x, so we ensure consistency by getting\n# both entries from the same snapshot, isolating from the effects of concurrent\n# writes\n{x, y} = CubDB.with_snapshot(db, fn snap -\u003e\n  x = CubDB.Snapshot.get(snap, :x)\n  y = CubDB.Snapshot.get(snap, x)\n\n  {x, y}\nend)\n```\n\nThe functions that read multiple entries like `get_multi`, `select`, etc. are\ninternally using a snapshot, so they always ensure consistency and isolation\nfrom concurrent writes, implementing multi version concurrency control (MVCC).\n\nFor more details, read the [API documentation](https://hexdocs.pm/cubdb/CubDB.html).\n\n## Installation\n\n`CubDB` can be installed by adding `:cubdb` to your list of dependencies in\n`mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:cubdb, \"~\u003e 2.0.2\"}\n  ]\nend\n```\n\n## Acknowledgement\n\nThe file data structure used by `CubDB` is inspired by\n[CouchDB](http://couchdb.apache.org). A big thanks goes to the CouchDB\nmaintainers for the readable codebase and extensive documentation.\n\n## Copyright and License\n\nCopyright 2022 Luca Ongaro\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flucaong%2Fcubdb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flucaong%2Fcubdb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flucaong%2Fcubdb/lists"}