[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-81794":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":16,"stars30d":17,"stars90d":15,"forks30d":15,"starsTrendScore":18,"compositeScore":19,"rankGlobal":10,"rankLanguage":10,"license":10,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":25,"readmeContent":26,"aiSummary":27,"trendingCount":15,"starSnapshotCount":15,"syncStatus":13,"lastSyncTime":28,"discoverSource":29},81794,"fast-nix-gc","Mic92\u002Ffast-nix-gc","Mic92","A faster nix-collect-garbage.","",null,"Rust",51,2,1,0,8,9,4,43.33,false,"main",true,[24],"build-with-buildbot","2026-06-12 04:01:35","# fast-nix-gc\n\nFaster `nix-collect-garbage` and `nix-store --optimise`. See\n[real-world timings](#real-world-timings) for a rough idea of how much\nfaster.\n\n## fast-nix-gc\n\nThe stock GC issues one SQLite query per store path while traversing the\nreference graph. With ~100K paths this means ~100K B-tree seeks and a lot\nof statement-cache churn. fast-nix-gc instead reads `ValidPaths` and `Refs`\nonce into a CSR adjacency list and runs the liveness BFS over integer node\nids. On a real store with ~30K dead paths this brings the dry-run from\n~20s down to ~1s. Disk deletion and `.links` cleanup are parallelized\nwith rayon.\n\n```\nfast-nix-gc [OPTIONS]\n\n  -d, --delete-old              Remove old profile generations\n      --delete-older-than SPEC  Delete generations older than SPEC (e.g. 30d, 4h)\n      --dry-run                 Show what would be done\n      --ensure-free SIZE        Free until SIZE is available (e.g. 50G)\n      --keep-recent SPEC        Keep paths registered within SPEC (e.g. 1d)\n      --store-dir PATH          Nix store directory [default: \u002Fnix\u002Fstore]\n      --state-dir PATH          Nix state directory [default: \u002Fnix\u002Fvar\u002Fnix]\n```\n\n## fast-nix-optimise\n\nHardlink-based store dedup, on-disk compatible with `nix-store --optimise`:\nsame `.links\u002F` layout, same NAR-SHA-256 filenames, the two can be mixed\nfreely. Hashing and linking run as concurrent tokio tasks; a steady-state\nstore where most files are already deduped is skipped via `d_ino` from\nreaddir without rehashing. ~2x faster than upstream on a warm store.\n\n```\nfast-nix-optimise [OPTIONS]\n\n      --dry-run             Show what would be done\n      --min-size BYTES      Skip files smaller than BYTES\n  -j, --jobs N              Concurrency [default: num CPUs]\n      --store-dir PATH      Nix store directory [default: \u002Fnix\u002Fstore]\n      --state-dir PATH      Nix state directory [default: \u002Fnix\u002Fvar\u002Fnix]\n```\n\nBoth tools take a shared `gc.lock` so they don't race each other or Nix.\nWhile fast-nix-gc deletes, it serves the GC roots socket\n(`state\u002Fgc-socket\u002Fsocket`, same protocol as `nix-store --gc`), so concurrent\n`nix build`s register temp roots without blocking on the lock.\n`--store-dir`\u002F`--state-dir` let you point at a separate store for testing.\n\n## NixOS module\n\nReplaces `nix.gc` and `nix.optimise`:\n\n```nix\n{\n  inputs.fast-nix-gc.url = \"github:Mic92\u002Ffast-nix-gc\";\n\n  outputs = { nixpkgs, fast-nix-gc, ... }: {\n    nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {\n      modules = [\n        fast-nix-gc.nixosModules.default\n        {\n          services.fast-nix-gc = {\n            enable = true;\n            automatic = true;\n            dates = \"weekly\";\n            deleteOlderThan = \"30d\";\n            ensureFree = \"50G\";\n            keepRecent = \"1d\";\n          };\n          services.fast-nix-optimise = {\n            enable = true;\n            automatic = true;\n            dates = \"weekly\";\n          };\n        }\n      ];\n    };\n  };\n}\n```\n\n`services.fast-nix-gc` options:\n\n| Option | Default | Description |\n|---|---|---|\n| `enable` | `false` | Enable the systemd service |\n| `automatic` | `false` | Run on a schedule via systemd timer |\n| `dates` | `\"03:15\"` | When to run (`systemd.time(7)` calendar event) |\n| `randomizedDelaySec` | `\"0\"` | Random delay before each run |\n| `persistent` | `true` | Run on next boot if a scheduled run was missed |\n| `deleteOlderThan` | `null` | Remove profile generations older than e.g. `\"30d\"` |\n| `ensureFree` | `null` | Stop once this much disk is free, e.g. `\"50G\"` |\n| `keepRecent` | `null` | Pin paths registered within e.g. `\"1d\"` |\n| `package` | this flake's package | Override the binary |\n| `extraArgs` | `[ ]` | Extra CLI arguments |\n\n`services.fast-nix-optimise` options:\n\n| Option | Default | Description |\n|---|---|---|\n| `enable` | `false` | Enable the systemd service |\n| `automatic` | `false` | Run on a schedule via systemd timer |\n| `dates` | `\"04:15\"` | When to run; ordered after fast-nix-gc.service when both run |\n| `randomizedDelaySec` | `\"0\"` | Random delay before each run |\n| `persistent` | `true` | Run on next boot if a scheduled run was missed |\n| `minSize` | `null` | Skip files smaller than this many bytes |\n| `jobs` | `null` | Concurrency, defaults to the CPU count |\n| `package` | `services.fast-nix-gc.package` | Override the binary |\n| `extraArgs` | `[ ]` | Extra CLI arguments |\n\nWithout flakes, import `nix\u002Fmodule.nix` directly.\n\n## Building\n\n    nix build\n\nor `nix develop -c cargo build --release`. Without flakes:\n`nix-build` (uses `default.nix`).\n\n## Testing\n\n    cargo test       # against a synthetic store in a tempdir\n    cargo bench      # throughput across several synthetic store sizes\n\n## Behavior\n\nRoots are gathered from `gcroots\u002F`, `profiles\u002F`, `temproots\u002F`, and running\nprocesses (`\u002Fproc` on Linux; `libproc` syscalls on macOS instead of\nshelling out to `lsof`). Stale temp-root files and dangling auto-roots are\nremoved. `keep-derivations` and `keep-outputs` are honored, including for\ncontent-addressed derivations (via the `DerivationOutputs` table). The\nstore is remounted read-write on NixOS where it's bind-mounted read-only.\n`tmp-*` build dirs are skipped if a builder still holds the lock.\n\nThe GC takes the same `gc.lock` Nix does, so it won't race with\n`nix-build` or another GC. If interrupted mid-run the DB stays\nconservative: paths gone from the DB but still on disk are picked up as\nunknown entries by the next GC.\n\n## FAQ\n\n**Could this have been implemented in upstream Nix?**\n\nYes, but C++ and concurrency is a scary combination,\nwhich is why I went with this implementation first.\n\n## Real-world timings\n\nThis is not a scientific benchmark, just `journalctl` data from a few of my\nmachines after switching the daily GC timer from `nix-gc.service` to\n`fast-nix-gc.service`. Workloads differ between runs, sample sizes are\nsmall, and hardware varies. Take it as a rough indication of scale, not a\ncontrolled measurement.\n\n| Host | Store profile | `nix-gc` wall clock | `fast-nix-gc` wall clock | Rough speedup |\n| --- | --- | --- | --- | --- |\n| Laptop (large store, daily dev churn) | ~100k+ paths | 1m25s – 19m, median ≈ 7m | 5s – 20s | ~25–60× |\n| Build server (huge store, CI churn) | very large | 19m – 30m, avg ≈ 22m | 7s – 17s | ~80–180× |\n| Small VPS (tiny store) | small | 4s – 23s | 15s | ~1–1.5× |\n\nThe speedup grows with store size: stock `nix-gc` pays a large fixed cost\nwalking the whole live closure even when there's almost nothing to delete\n(near-idle runs still took minutes on the bigger machines), while\n`fast-nix-gc` stays in the single-digit-seconds range. On a tiny store\nthe overhead is negligible either way and the two are roughly comparable.\n","fast-nix-gc 是一个用于加速 Nix 垃圾回收和存储优化的工具。它通过将路径信息一次性读入到 CSR 邻接列表中，并在整数节点 ID 上运行存活广度优先搜索，显著减少了 SQLite 查询次数，从而大幅提升了处理速度。同时，该工具使用 rayon 库并行化磁盘删除和链接清理操作，进一步提高了效率。此外，项目还提供了与原生 Nix 工具兼容的存储去重功能 fast-nix-optimise，能够以更高的并发性和更少的重复计算实现更快的优化过程。此工具非常适合需要频繁进行垃圾回收或优化 Nix 存储环境的场景，如持续集成系统或开发者的日常工作中，以保持系统的高效运行。","2026-06-11 04:06:43","CREATED_QUERY"]