{"id":13580541,"url":"https://github.com/hawkw/sharded-slab","last_synced_at":"2025-04-11T03:29:43.869Z","repository":{"id":35143499,"uuid":"209183899","full_name":"hawkw/sharded-slab","owner":"hawkw","description":"a lock-free concurrent slab (experimental)","archived":false,"fork":false,"pushed_at":"2024-12-26T19:25:33.000Z","size":492,"stargazers_count":280,"open_issues_count":31,"forks_count":25,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-04-03T21:37:09.025Z","etag":null,"topics":["concurrent","lock-free","rust","slab"],"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/hawkw.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":["hawkw"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2019-09-18T00:45:44.000Z","updated_at":"2025-03-04T07:07:02.000Z","dependencies_parsed_at":"2024-06-18T18:27:42.753Z","dependency_job_id":"3bf8120a-27be-4a23-9625-10078b1dfff5","html_url":"https://github.com/hawkw/sharded-slab","commit_stats":{"total_commits":119,"total_committers":7,"mean_commits":17.0,"dds":0.1512605042016807,"last_synced_commit":"ee45b4cfa79408fc46893a67f2d3005f79e4e04c"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hawkw%2Fsharded-slab","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hawkw%2Fsharded-slab/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hawkw%2Fsharded-slab/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hawkw%2Fsharded-slab/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hawkw","download_url":"https://codeload.github.com/hawkw/sharded-slab/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248335258,"owners_count":21086545,"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":["concurrent","lock-free","rust","slab"],"created_at":"2024-08-01T15:01:52.835Z","updated_at":"2025-04-11T03:29:43.848Z","avatar_url":"https://github.com/hawkw.png","language":"Rust","funding_links":["https://github.com/sponsors/hawkw"],"categories":["Rust"],"sub_categories":[],"readme":"# sharded-slab\n\nA lock-free concurrent slab.\n\n[![Crates.io][crates-badge]][crates-url]\n[![Documentation][docs-badge]][docs-url]\n[![CI Status][ci-badge]][ci-url]\n[![GitHub License][license-badge]][license]\n![maintenance status][maint-badge]\n\n[crates-badge]: https://img.shields.io/crates/v/sharded-slab.svg\n[crates-url]: https://crates.io/crates/sharded-slab\n[docs-badge]: https://docs.rs/sharded-slab/badge.svg\n[docs-url]: https://docs.rs/sharded-slab/latest\n[ci-badge]: https://github.com/hawkw/sharded-slab/workflows/CI/badge.svg\n[ci-url]: https://github.com/hawkw/sharded-slab/actions?workflow=CI\n[license-badge]: https://img.shields.io/crates/l/sharded-slab\n[license]: LICENSE\n[maint-badge]: https://img.shields.io/badge/maintenance-experimental-blue.svg\n\nSlabs provide pre-allocated storage for many instances of a single data\ntype. When a large number of values of a single type are required,\nthis can be more efficient than allocating each item individually. Since the\nallocated items are the same size, memory fragmentation is reduced, and\ncreating and removing new items can be very cheap.\n\nThis crate implements a lock-free concurrent slab, indexed by `usize`s.\n\n**Note**: This crate is currently experimental. Please feel free to use it in\nyour projects, but bear in mind that there's still plenty of room for\noptimization, and there may still be some lurking bugs.\n\n## Usage\n\nFirst, add this to your `Cargo.toml`:\n\n```toml\nsharded-slab = \"0.1.7\"\n```\n\nThis crate provides two types, [`Slab`] and [`Pool`], which provide slightly\ndifferent APIs for using a sharded slab. \n\n[`Slab`] implements a slab for _storing_ small types, sharing them between\nthreads, and accessing them by index. New entries are allocated by [inserting]\ndata, moving it in by value. Similarly, entries may be deallocated by [taking]\nfrom the slab, moving the value out. This API is similar to a `Vec\u003cOption\u003cT\u003e\u003e`,\nbut allowing lock-free concurrent insertion and removal.\n\nIn contrast, the [`Pool`] type provides an [object pool] style API for\n_reusing storage_. Rather than constructing values and moving them into\nthe pool, as with [`Slab`], [allocating an entry][create] from the pool\ntakes a closure that's provided with a mutable reference to initialize\nthe entry in place. When entries are deallocated, they are [cleared] in\nplace. Types which own a heap allocation can be cleared by dropping any\n_data_ they store, but retaining any previously-allocated capacity. This\nmeans that a [`Pool`] may be used to reuse a set of existing heap\nallocations, reducing allocator load.\n\n[`Slab`]: https://docs.rs/sharded-slab/0.1.4/sharded_slab/struct.Slab.html\n[inserting]: https://docs.rs/sharded-slab/0.1.4/sharded_slab/struct.Slab.html#method.insert\n[taking]: https://docs.rs/sharded-slab/0.1.4/sharded_slab/struct.Slab.html#method.take\n[`Pool`]: https://docs.rs/sharded-slab/0.1.4/sharded_slab/struct.Pool.html\n[create]: https://docs.rs/sharded-slab/0.1.4/sharded_slab/struct.Pool.html#method.create\n[cleared]: https://docs.rs/sharded-slab/0.1.4/sharded_slab/trait.Clear.html\n[object pool]: https://en.wikipedia.org/wiki/Object_pool_pattern\n\n### Examples\n\nInserting an item into the slab, returning an index:\n\n```rust\nuse sharded_slab::Slab;\nlet slab = Slab::new();\n\nlet key = slab.insert(\"hello world\").unwrap();\nassert_eq!(slab.get(key).unwrap(), \"hello world\");\n```\n\nTo share a slab across threads, it may be wrapped in an `Arc`:\n\n```rust\nuse sharded_slab::Slab;\nuse std::sync::Arc;\nlet slab = Arc::new(Slab::new());\n\nlet slab2 = slab.clone();\nlet thread2 = std::thread::spawn(move || {\n    let key = slab2.insert(\"hello from thread two\").unwrap();\n    assert_eq!(slab2.get(key).unwrap(), \"hello from thread two\");\n    key\n});\n\nlet key1 = slab.insert(\"hello from thread one\").unwrap();\nassert_eq!(slab.get(key1).unwrap(), \"hello from thread one\");\n\n// Wait for thread 2 to complete.\nlet key2 = thread2.join().unwrap();\n\n// The item inserted by thread 2 remains in the slab.\nassert_eq!(slab.get(key2).unwrap(), \"hello from thread two\");\n```\n\nIf items in the slab must be mutated, a `Mutex` or `RwLock` may be used for\neach item, providing granular locking of items rather than of the slab:\n\n```rust\nuse sharded_slab::Slab;\nuse std::sync::{Arc, Mutex};\nlet slab = Arc::new(Slab::new());\n\nlet key = slab.insert(Mutex::new(String::from(\"hello world\"))).unwrap();\n\nlet slab2 = slab.clone();\nlet thread2 = std::thread::spawn(move || {\n    let hello = slab2.get(key).expect(\"item missing\");\n    let mut hello = hello.lock().expect(\"mutex poisoned\");\n    *hello = String::from(\"hello everyone!\");\n});\n\nthread2.join().unwrap();\n\nlet hello = slab.get(key).expect(\"item missing\");\nlet mut hello = hello.lock().expect(\"mutex poisoned\");\nassert_eq!(hello.as_str(), \"hello everyone!\");\n```\n\n## Comparison with Similar Crates\n\n- [`slab`][slab crate]: Carl Lerche's `slab` crate provides a slab implementation with a\n  similar API, implemented by storing all data in a single vector.\n\n  Unlike `sharded-slab`, inserting and removing elements from the slab requires\n  mutable access. This means that if the slab is accessed concurrently by\n  multiple threads, it is necessary for it to be protected by a `Mutex` or\n  `RwLock`. Items may not be inserted or removed (or accessed, if a `Mutex` is\n  used) concurrently, even when they are unrelated. In many cases, the lock can\n  become a significant bottleneck. On the other hand, `sharded-slab` allows\n  separate indices in the slab to be accessed, inserted, and removed\n  concurrently without requiring a global lock. Therefore, when the slab is\n  shared across multiple threads, this crate offers significantly better\n  performance than `slab`.\n\n  However, the lock free slab introduces some additional constant-factor\n  overhead. This means that in use-cases where a slab is _not_ shared by\n  multiple threads and locking is not required, `sharded-slab` will likely\n  offer slightly worse performance.\n\n  In summary: `sharded-slab` offers significantly improved performance in\n  concurrent use-cases, while `slab` should be preferred in single-threaded\n  use-cases.\n\n[slab crate]: https://crates.io/crates/slab\n\n## Safety and Correctness\n\nMost implementations of lock-free data structures in Rust require some\namount of unsafe code, and this crate is not an exception. In order to catch\npotential bugs in this unsafe code, we make use of [`loom`], a\npermutation-testing tool for concurrent Rust programs. All `unsafe` blocks\nthis crate occur in accesses to `loom` `UnsafeCell`s. This means that when\nthose accesses occur in this crate's tests, `loom` will assert that they are\nvalid under the C11 memory model across multiple permutations of concurrent\nexecutions of those tests.\n\nIn order to guard against the [ABA problem][aba], this crate makes use of\n_generational indices_. Each slot in the slab tracks a generation counter\nwhich is incremented every time a value is inserted into that slot, and the\nindices returned by `Slab::insert` include the generation of the slot when\nthe value was inserted, packed into the high-order bits of the index. This\nensures that if a value is inserted, removed,  and a new value is inserted\ninto the same slot in the slab, the key returned by the first call to\n`insert` will not map to the new value.\n\nSince a fixed number of bits are set aside to use for storing the generation\ncounter, the counter will wrap  around after being incremented a number of\ntimes. To avoid situations where a returned index lives long enough to see the\ngeneration counter wrap around to the same value, it is good to be fairly\ngenerous when configuring the allocation of index bits.\n\n[`loom`]: https://crates.io/crates/loom\n[aba]: https://en.wikipedia.org/wiki/ABA_problem\n\n## Performance\n\nThese graphs were produced by [benchmarks] of the sharded slab implementation,\nusing the [`criterion`] crate.\n\nThe first shows the results of a benchmark where an increasing number of\nitems are inserted and then removed into a slab concurrently by five\nthreads. It compares the performance of the sharded slab implementation\nwith a `RwLock\u003cslab::Slab\u003e`:\n\n\u003cimg width=\"1124\" alt=\"Screen Shot 2019-10-01 at 5 09 49 PM\" src=\"https://user-images.githubusercontent.com/2796466/66078398-cd6c9f80-e516-11e9-9923-0ed6292e8498.png\"\u003e\n\nThe second graph shows the results of a benchmark where an increasing\nnumber of items are inserted and then removed by a _single_ thread. It\ncompares the performance of the sharded slab implementation with an\n`RwLock\u003cslab::Slab\u003e` and a `mut slab::Slab`.\n\n\u003cimg width=\"925\" alt=\"Screen Shot 2019-10-01 at 5 13 45 PM\" src=\"https://user-images.githubusercontent.com/2796466/66078469-f0974f00-e516-11e9-95b5-f65f0aa7e494.png\"\u003e\n\nThese benchmarks demonstrate that, while the sharded approach introduces\na small constant-factor overhead, it offers significantly better\nperformance across concurrent accesses.\n\n[benchmarks]: https://github.com/hawkw/sharded-slab/blob/master/benches/bench.rs\n[`criterion`]: https://crates.io/crates/criterion\n\n## License\n\nThis project is licensed under the [MIT license](LICENSE).\n\n### Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in this project by you, shall be licensed as MIT, without any\nadditional terms or conditions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhawkw%2Fsharded-slab","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhawkw%2Fsharded-slab","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhawkw%2Fsharded-slab/lists"}