{"id":16092278,"url":"https://github.com/alecthomas/localcache","last_synced_at":"2025-03-16T08:32:22.131Z","repository":{"id":39870838,"uuid":"429427864","full_name":"alecthomas/localcache","owner":"alecthomas","description":"Local file-based atomic cache manager","archived":false,"fork":false,"pushed_at":"2025-03-12T22:44:27.000Z","size":39,"stargazers_count":44,"open_issues_count":2,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-12T23:28:30.223Z","etag":null,"topics":["cache","filesystem","go","golang"],"latest_commit_sha":null,"homepage":"","language":"Go","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/alecthomas.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":"2021-11-18T12:49:35.000Z","updated_at":"2024-10-12T16:08:48.000Z","dependencies_parsed_at":"2024-02-16T05:23:38.435Z","dependency_job_id":"db1697db-ed04-49a1-b291-f434e36bf662","html_url":"https://github.com/alecthomas/localcache","commit_stats":{"total_commits":14,"total_committers":3,"mean_commits":4.666666666666667,"dds":0.2857142857142857,"last_synced_commit":"08a585791ca76cfba6bef99df9dc9b03f82137b1"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alecthomas%2Flocalcache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alecthomas%2Flocalcache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alecthomas%2Flocalcache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alecthomas%2Flocalcache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alecthomas","download_url":"https://codeload.github.com/alecthomas/localcache/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243806070,"owners_count":20350775,"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":["cache","filesystem","go","golang"],"created_at":"2024-10-09T16:06:33.589Z","updated_at":"2025-03-16T08:32:21.630Z","avatar_url":"https://github.com/alecthomas.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Local file-based atomic cache manager\n\nI repeatedly find myself writing partitioned keyed caching systems, akin to Go's module cache. To DRY myself I created\nthis.\n\nIt provides:\n\n- Partitioned cache entries: `\u003croot\u003e/\u003cpartition\u003e/\u003ckey\u003e`\n- Atomic creation, replacement and deletion of single files.\n- Atomic creation, replacement and deletion of directory hierarchies.\n\n## Usage\n\n```go\ncache, err := localcache.New(\"myapp\")\n\n// Create a temporarily unaddressable file in the cache.\ntx, f, err := cache.Create(\"some-key\")\n// Write to f\n\n// Commit the file to the cache.\nerr = cache.Commit(tx)\n\n// Load the cache entry back.\ndata, err := cache.ReadFile(\"some-key\")\n\n// Open the cache entry for reading.\ndata, err := cache.Open(\"some-key\")\n\n// Create a temporarily unaddressable directory with the same key as the previous file.\ntx, dir, err := cache.Mkdir(\"some-key\")\n\n// Atomically replace the previous file with the new directory.\nerr := cache.Commit(tx)\n```\n\n## Implementation\n\nThe cache manager maintains transactionality/atomicity by relying on two aspects of Unix filesystems:\n\n1. File renames are atomic.\n2. Symlinks can be atomically overwritten by a rename.\n\nThe process is then:\n\n1. Create a file or directory `F = \u003cpartition\u003e/\u003chash\u003e.\u003ctimestamp\u003e`.\n2. User writes to the file or populates the directory.\n3. Create a symlink `L = \u003cpartition\u003e/\u003chash\u003e.\u003ctimestamp\u003e -\u003e F`\n4. Rename `L` to `\u003cpartition\u003e/\u003chash\u003e`, the final \"committed\" name for the entry.\n\neg.\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003cth\u003eCode\u003c/th\u003e\n\u003cth\u003eFilesystem\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```go\ntx, f, err := cache.Create(\"my-key\")\nf.WriteString(\"hello\")\nf.Close()\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```\n5e/5e78…f732.67e7996297ee\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\nStep 1\n\n```go\ncache.Commit(tx)\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```\n5e/5e78…f732.67e799629823 -\u003e 5e78…f732.67e7996297ee\n5e/5e78…f732.67e7996297ee\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\nStep 2\n\n```go\ncache.Commit(tx)\n```\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n```\n5e/5e78…f732 -\u003e 5e78…f732.67e7996297ee\n5e/5e78…f732.67e7996297ee\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falecthomas%2Flocalcache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falecthomas%2Flocalcache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falecthomas%2Flocalcache/lists"}