{"id":28604023,"url":"https://github.com/uber/simple-store","last_synced_at":"2025-06-11T17:40:19.786Z","repository":{"id":35388239,"uuid":"158618423","full_name":"uber/simple-store","owner":"uber","description":"Simple yet performant asynchronous file storage for Android","archived":false,"fork":false,"pushed_at":"2024-01-24T07:25:31.000Z","size":1750,"stargazers_count":81,"open_issues_count":9,"forks_count":13,"subscribers_count":8,"default_branch":"main","last_synced_at":"2024-05-09T07:59:02.493Z","etag":null,"topics":["incubation"],"latest_commit_sha":null,"homepage":"https://uber.github.io/simple-store/","language":"Java","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/uber.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-11-21T23:37:27.000Z","updated_at":"2024-03-31T14:21:46.000Z","dependencies_parsed_at":"2024-01-20T02:37:59.046Z","dependency_job_id":null,"html_url":"https://github.com/uber/simple-store","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/uber/simple-store","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uber%2Fsimple-store","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uber%2Fsimple-store/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uber%2Fsimple-store/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uber%2Fsimple-store/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uber","download_url":"https://codeload.github.com/uber/simple-store/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uber%2Fsimple-store/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259308163,"owners_count":22837974,"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":["incubation"],"created_at":"2025-06-11T17:40:11.675Z","updated_at":"2025-06-11T17:40:19.781Z","avatar_url":"https://github.com/uber.png","language":"Java","readme":"# Simple Store\n![CI](https://github.com/uber/simple-store/workflows/CI/badge.svg?branch=main)\n[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3000/badge)](https://bestpractices.coreinfrastructure.org/projects/3000)\n[![Maven Central](https://img.shields.io/maven-central/v/com.uber.simplestore/simplestore.svg)](https://search.maven.org/artifact/com.uber.simplestore/simplestore)\n[![Maven Central](https://img.shields.io/maven-central/v/com.uber.simplestore/simplestore-proto.svg)](https://search.maven.org/artifact/com.uber.simplestore/simplestore-proto)\n\nThis project is stable and being incubated for long-term support.\n\nSimple yet performant asynchronous file storage for Android.\n\nSimpleStore aims to provide developers an extremely robust and performant solution for storing key-value data on disk asynchronously. It is built using only Android and Java primitives and avoids taking on external dependencies making it ideal for critical startup storage. It has no opinion on how data is serialized, only storing `string`-`byte[]` pairs of small to moderate size. The core library only exposes a thread-safe, executor-explicit async API ensuring clear thread selection and no UI jank.\n\nAll values are stored on disk as plain files that are “namespaced” in a matching on-disk folder structure. The library also supports configuring a namespace to store data on a cache or transient partition.\n\n## Basic usage\n\nTo include in a gradle project, add to your dependencies:\n\n```groovy\ndependencies {\n    implementation 'com.uber.simplestore:simplestore:0.0.9'\n    // If using protocol buffers, also add:\n    implementation 'com.uber.simplestore:simplestore-proto:0.0.9'\n}\n```\n\nOut of the box, SimpleStore uses `ListenableFuture` to store `byte[]`, `String`, primitives and protocol buffers on internal storage. \n```java\nSimpleStore simpleStore = SimpleStoreFactory.create(this, \"\u003csome-uuid-or-name\u003e\");\nListenableFuture\u003cString\u003e put = simpleStore.putString(\"some_key\", \"Foo value\");\nFutures.addCallback(\n        put,\n        new FutureCallback\u003cString\u003e() {\n          @Override\n          public void onSuccess(@NonNull String s) {\n            \n          }\n\n          @Override\n          public void onFailure(@NonNull Throwable t) {\n            Log.e(\"MyActivity\", \"Save failure\", t);\n          }\n        },\n        mainExecutor());\nsimpleStore.close();\n```\n\nNote that if you use RxJava, Rx comes with a `fromFuture` method that allows you to wrap `ListenableFuture`:\n\n```java\nSingle\u003cString\u003e value = Single.fromFuture(simpleStore.getString(\"some_key\"));\n\n```\n\n## Fundamentally Async\nIO operations are fundamentally async, and any storage solution should be async all the way through.\n\nThe implementation is written using async work queues. This allows us to implement under-the-hood optimizations that do not block consumers such as prefetching and pruning old cached values.\n\n`Futures.get` from Guava is available for consumers who wish to run synchronously.\n\n## Interface\nOnly one interface is exposed for general use. Implementations of the interface provide a factory method for instantiating any variations.\n\nUsage:\n```java\nSimpleStore store = SimpleStoreFactory.create(context, “feature/mystuff”, NamespaceConfig.DEFAULT);\nListenableFuture\u003cString\u003e value = store.putString(\"some_key\", value);\n```\n\nThe interface is designed to allow composition with higher level wrappers such as a protocol buffers, Rx, or ListenableFuture transforms. \n\nListenableFuture was chosen over Rx for the implementation as: \n* Future transformations require explicit assignment to an Executor, making it difficult to accidentally perform IO operations in the incorrect pool. \n* Executors do not suffer from the round-robin scheduler design of Rx, making deadlock between IO work impossible.\n* AndroidX and most Google libraries already ship ListenableFuture and associated Guava classes with them, so most Android apps can take on ListenableFuture without increasing binary size.\n* Interop with Futures is built into Rx via `Observables.fromFuture`.\n\nThe base interface and implementation purposely leave out a synchronous API as disk IO is fundamentally async. A safe-ish synchronous API can be obtained via `Futures#getChecked` if absolutely needed for compatibility reasons, but most users who think they need sync will probably find the Futures helpers adequate for their needs.\n\n## Closing a namespace\n\nSimpleStore is closable per namespace, and may only have one open instance per namespace process-wide. When a namespace is closed, the in-memory cache is destroyed. The store will deliver failures to all pending callbacks when closed. This ensures that the consumer is always notified if data does not make it to disk and can handle the failure appropriately such as logging a non-fatal. Any reads or writes attempted on the store after closure will result in an exception.\n\nIn the future, we can arbitrarily clear portions of the memory cache of an open namespace when desired such as when the OS informs of a trim level. Since the API is fully async, consumers will not be janked and will just see original load latencies.\n\n## Threading\n\nAll operations are guaranteed to be executed in-order within the same namespace. A singular cached thread pool backs all stores process wide, and can be replaced with a custom executor via a static configuration method. It is safe to enqueue any operation from any thread, including the main thread. All future callbacks are paired with an executor to be run on, this forces parsing or other processing actions to get out of the way of ordered disk I/O.\n\nThis model makes deadlock across namespaces impossible, as even a blockingGet cannot be issued on the ordered IO executor. Adopting this model leaves us room to experiment later with using explicit thread priority for different namespaces.\n\n## License\n\n    Copyright (C) 2020 Uber Technologies\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n\n","funding_links":[],"categories":["数据库"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuber%2Fsimple-store","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuber%2Fsimple-store","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuber%2Fsimple-store/lists"}