{"id":16153892,"url":"https://github.com/hinto-janai/someday","last_synced_at":"2025-03-18T19:32:52.123Z","repository":{"id":195960711,"uuid":"619836989","full_name":"hinto-janai/someday","owner":"hinto-janai","description":"Lock-free MVCC primitive","archived":false,"fork":false,"pushed_at":"2024-03-28T19:36:55.000Z","size":809,"stargazers_count":10,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-16T23:21:46.116Z","etag":null,"topics":["atomic","concurrency","data","lock-free","mvcc","rust"],"latest_commit_sha":null,"homepage":"https://docs.rs/someday","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/hinto-janai.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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-27T14:17:03.000Z","updated_at":"2024-08-02T17:24:04.000Z","dependencies_parsed_at":"2023-09-27T19:09:15.816Z","dependency_job_id":"b59ea035-9b55-4be7-81bd-29a997c6b036","html_url":"https://github.com/hinto-janai/someday","commit_stats":null,"previous_names":["hinto-janai/someday"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hinto-janai%2Fsomeday","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hinto-janai%2Fsomeday/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hinto-janai%2Fsomeday/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hinto-janai%2Fsomeday/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hinto-janai","download_url":"https://codeload.github.com/hinto-janai/someday/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244289190,"owners_count":20429157,"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":["atomic","concurrency","data","lock-free","mvcc","rust"],"created_at":"2024-10-10T01:14:50.736Z","updated_at":"2025-03-18T19:32:47.114Z","avatar_url":"https://github.com/hinto-janai.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `someday`\n[![CI](https://github.com/hinto-janai/someday/actions/workflows/ci.yml/badge.svg)](https://github.com/hinto-janai/someday/actions/workflows/ci.yml) [![crates.io](https://img.shields.io/crates/v/someday.svg)](https://crates.io/crates/someday) [![docs.rs](https://docs.rs/someday/badge.svg)](https://docs.rs/someday)\n\n`someday` is a [multi-version concurrency control](https://en.wikipedia.org/wiki/Multiversion_concurrency_control) primitive.\n\nA lock-free, but more memory hungry alternative to `Mutex\u003cT\u003e` or `RwLock\u003cT\u003e`.\n\n## Lock-free\n[`Reader`](https://docs.rs/someday/latest/someday/struct.Reader.html)'s are [lock-free](https://en.wikipedia.org/wiki/Non-blocking_algorithm#Lock-freedom) and most of the time [wait-free](https://en.wikipedia.org/wiki/Non-blocking_algorithm#Wait-freedom).\n\nThe single [`Writer`](https://docs.rs/someday/latest/someday/struct.Writer.html) is [lock-free](https://en.wikipedia.org/wiki/Non-blocking_algorithm#Lock-freedom), but may clone data.\n\nWhen the `Writer` wants to [`push()`](https://docs.rs/someday/latest/someday/struct.Writer.html#method.push) updates to `Reader`'s, it must:\n1. Atomically update a pointer, at which point all _future_ readers will see the new data\n2. Re-apply the patches to the old reclaimed data OR clone the data if it cannot be reclaimed\n\nThe old data _can_ be cheaply reclaimed and re-used by the `Writer` if there are no `Reader`'s hanging onto old [`Commit`](https://docs.rs/someday/latest/someday/commit/type.CommitRef.html)'s.\n\nIf there are still `Reader`'s hanging onto old data, the `Writer` will clone the data such that it can continue.\n\n## Use-case\n`someday` is best in situations where:\n\nYour data:\n- Is relatively cheap to clone and/or de-duplicated\n\nand if you have **many** readers who:\n- Want to acquire a copy of data, lock-free\n- Hold onto data (for a little while or forever)\n\nand a writer that:\n- Wants to mutate data, lock-free\n- Wants to push changes ASAP to new readers, lock-free\n- Doesn't mutate data that often (relative to read operations)\n- Is normally in contention with readers using normal locks (`Mutex`, `RwLock`)\n\n## Tradeoffs\n- **Increased memory use:** The `Writer` keeps at least two copies of the backing data structure, and `Reader`'s can keep an infinite amount (as long as they continue to hold onto references)\n\n- **Deterministic patches:** The patches/functions applied to your data must be deterministic, since the `Writer` may apply them twice\n\n- **Slow writes:** Writes are slower than they would be directly against the backing data structure\n\n## API\n`someday`'s API is similar to [`git`](https://git-scm.com) and semantically does similar actions.\n\nThe `Writer`:\n1. Calls [`add()`](https://docs.rs/someday/latest/someday/struct.Writer.html#method.add) to add a [`Patch`](https://docs.rs/someday/latest/someday/enum.Patch.html) (function) to their data\n2. Actually executes those changes by [`commit()`](https://docs.rs/someday/latest/someday/struct.Writer.html#commit.add)'ing\n3. Can see local or remote (reader) data whenever\n4. Can atomically [`push()`](https://docs.rs/someday/latest/someday/struct.Writer.html#method.push) those changes to the `Reader`'s\n5. Can continue writing without having to wait on `Reader`'s\n\nThe `Reader(s)`:\n1. Can continually call [`head()`](https://docs.rs/someday/latest/someday/struct.Reader.html#method.head) to cheaply acquire the latest \"head\" `Commit`\n2. Can hang onto those `Commit` objects forever (although at the peril of memory-usage)\n3. Will eventually catch up whenever the `Writer` calls `push()`\n\n## Example\n\u003cimg src=\"https://github.com/hinto-janai/someday/assets/101352116/b190db72-c56b-4336-a601-78296040d044\" width=\"60%\"/\u003e\n\nThis example shows the typical use case where the `Writer`:\n1. Adds some changes\n2. Reads their local changes\n3. Locks in those changes by calling `commit()`\n4. Finally reveals those changes to the readers by calling `push()`\n\nand the `Reader`:\n1. Continually reads their latest head `Commit` of the current data\n2. Eventually catches up when the `Writer` publishes with `push()`\n\nThe code:\n```rust\nuse someday::{\n\tPatch,\n\tWriter,Reader,\n\tCommit,CommitRef,\n\tCommitInfo,PushInfo,\n};\n\n// Create Reader/Writer for the string \"hello\".\nlet (r, mut w) = someday::new(\"hello\".to_string());\n\n// The readers see the data.\nlet commit: CommitRef\u003cString\u003e = r.head();\nassert_eq!(commit.data, \"hello\");\nassert_eq!(commit.timestamp, 0);\n\n// Writer writes some data, but does not commit.\nw.add(Patch::Ptr(|w, _| w.push_str(\" world\")));\n// Nothing committed, data still the same everywhere.\nlet data: \u0026String = w.data();\nassert_eq!(*data, \"hello\");\n// Patches not yet committed:\nassert_eq!(w.staged().len(), 1);\n\n// Readers still see old data.\nassert_eq!(r.head().data, \"hello\");\n\n// Writer writes some more data.\nw.add(Patch::Ptr(|w, _| w.push_str(\"!\")));\n// Readers still see old data.\nassert_eq!(r.head().data, \"hello\");\n\n// Writer commits their patches.\nlet commit_info: CommitInfo = w.commit();\n// The 2 operation were committed locally\n// (only the Writer sees them).\nassert_eq!(commit_info.patches, 2);\n\n// Readers still see old data.\nassert_eq!(r.head().data, \"hello\");\n\n// Writer finally reveals those\n// changes by calling `push()`.\nlet push_info: PushInfo = w.push();\nassert_eq!(push_info.commits, 1);\n\n// Now readers see updates.\nlet commit: CommitRef\u003cString\u003e = r.head();\nassert_eq!(commit.data, \"hello world!\");\n// Each call to `.commit()` added 1 to the timestamp.\nassert_eq!(commit.timestamp, 1);\n```\n\n## Feature Flags\nThese features are for (de)serialization.\n\nYou can directly (de)serialize your data `T` from a:\n- `Writer\u003cT\u003e`\n- `Reader\u003cT\u003e`\n- `Commit\u003cT\u003e`\n\n| Feature Flag | Purpose |\n|--------------|---------|\n| `serde`      | Enables [`serde`](https://docs.rs/serde)'s `Serialize` \u0026 `Deserialize`\n| `bincode`    | Enables [`bincode 2.0.0-rc.3`](https://docs.rs/bincode/2.0.0-rc.3/bincode/index.html)'s `Encode` \u0026 `Decode`\n| `borsh`      | Enables [`borsh`](https://docs.rs/borsh)'s `BorshSerialize` \u0026 `BorshDeserialize`\n\n## MSRV\nThe Minimum Supported Rust Version is `1.70.0`.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhinto-janai%2Fsomeday","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhinto-janai%2Fsomeday","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhinto-janai%2Fsomeday/lists"}