{"id":24065231,"url":"https://github.com/makindotcc/airomem-rs","last_synced_at":"2025-09-16T00:32:06.250Z","repository":{"id":225744730,"uuid":"766737921","full_name":"makindotcc/airomem-rs","owner":"makindotcc","description":"Simple persistence library inspired by Prevayler and motivated by @jarekratajski","archived":false,"fork":false,"pushed_at":"2024-10-09T20:13:42.000Z","size":123,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-02T03:12:49.724Z","etag":null,"topics":["persistent-storage","storage"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/airomem","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/makindotcc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2024-03-04T02:59:06.000Z","updated_at":"2024-10-09T20:13:46.000Z","dependencies_parsed_at":"2024-03-18T17:20:24.968Z","dependency_job_id":null,"html_url":"https://github.com/makindotcc/airomem-rs","commit_stats":null,"previous_names":["makindotcc/airomem-rs"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makindotcc%2Fairomem-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makindotcc%2Fairomem-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makindotcc%2Fairomem-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/makindotcc%2Fairomem-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/makindotcc","download_url":"https://codeload.github.com/makindotcc/airomem-rs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233177318,"owners_count":18636736,"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":["persistent-storage","storage"],"created_at":"2025-01-09T10:55:01.943Z","updated_at":"2025-09-16T00:32:00.932Z","avatar_url":"https://github.com/makindotcc.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Airomem-rs\r\n\r\n[Release at crates.io](https://crates.io/crates/airomem) \\\r\n(Toy) persistence library for Rust inspired by [prevayler for java](https://prevayler.org/) and named after its wrapper [airomem](https://github.com/airomem/airomem).\r\n\r\n\u003e It is an implementation of the Prevalent System design pattern, in which business objects are kept live in memory and transactions are journaled for system recovery.\r\n\r\n## Assumptions\r\n\r\n- All data lives in memory guarded with `tokio::sync::RwLock`, reads are fast and concurrent safe.\r\n- By default every transaction is saved to append-only journal file and immediately [fsynced](https://man7.org/linux/man-pages/man2/fsync.2.html).\r\n  By that, individual writes are slow, but they SHOULD survive crashes (e.g. power outage, software panic). \\\r\n  However, you can set periodic sync or manual. See `JournalFlushPolicy` for more info.\r\n  Recommended for data that may be lost (e.g. cache, http session storage).\r\n- I don't guarantee durability, it's created for toy projects or non-relevant data like http authorization tokens/cookies. https://www.postgresql.org/docs/9.4/wal-reliability.html\r\n\r\n## Features\r\n\r\n- [x] - saving executed transactions to append only file\r\n- [x] - split journal log file if too big - while restoring data, all journal logs are loaded at once from disk to maximise throughput (and for simplicity reasons)\r\n- [x] - snapshots for faster recovery\r\n- [ ] - stable api\r\n\r\n## Resources\r\n\r\n- [Jaroslaw Ratajski - DROP DATABASE - galactic story](https://www.youtube.com/watch?v=m_uIROLGrN4)\r\n- https://github.com/killertux/prevayler-rs\r\n\r\n## Example\r\n\r\n```rust\r\ntype UserId = usize;\r\ntype SessionsStore = JsonStore\u003cSessions, SessionsTx\u003e;\r\n\r\n#[derive(Serialize, Deserialize, Default)]\r\npub struct Sessions {\r\n    tokens: HashMap\u003cString, UserId\u003e,\r\n    operations: usize,\r\n}\r\n\r\nMergeTx!(pub SessionsTx\u003cSessions\u003e = CreateSession | DeleteSession);\r\n\r\n#[derive(Serialize, Deserialize)]\r\npub struct CreateSession {\r\n    token: String,\r\n    user_id: UserId,\r\n}\r\n\r\nimpl Tx\u003cSessions\u003e for CreateSession {\r\n    fn execute(self, data: \u0026mut Sessions) {\r\n        data.operations += 1;\r\n        data.tokens.insert(self.token, self.user_id);\r\n    }\r\n}\r\n\r\n#[derive(Serialize, Deserialize)]\r\npub struct DeleteSession {\r\n    token: String,\r\n}\r\n\r\nimpl Tx\u003cSessions, Option\u003cUserId\u003e\u003e for DeleteSession {\r\n    fn execute(self, data: \u0026mut Sessions) -\u003e Option\u003cUserId\u003e {\r\n        data.operations += 1;\r\n        data.tokens.remove(\u0026self.token)\r\n    }\r\n}\r\n\r\n#[tokio::test]\r\nasync fn test_mem_commit() {\r\n    let dir = tempdir().unwrap();\r\n    let mut store: SessionsStore =\r\n        Store::open(JsonSerializer, StoreOptions::default(), dir.into_path())\r\n            .await\r\n            .unwrap();\r\n    let example_token = \"access_token\".to_string();\r\n    let example_uid = 1;\r\n    store\r\n        .commit(CreateSession {\r\n            token: example_token.clone(),\r\n            user_id: example_uid,\r\n        })\r\n        .await\r\n        .unwrap();\r\n\r\n    let mut expected_tokens = HashMap::new();\r\n    expected_tokens.insert(example_token.clone(), example_uid);\r\n    assert_eq!(store.query().await.unwrap().tokens, expected_tokens);\r\n\r\n    let deleted_uid = store\r\n        .commit(DeleteSession {\r\n            token: example_token,\r\n        })\r\n        .await\r\n        .unwrap();\r\n    assert_eq!(deleted_uid, Some(example_uid));\r\n}\r\n```\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmakindotcc%2Fairomem-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmakindotcc%2Fairomem-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmakindotcc%2Fairomem-rs/lists"}