Skip to content

gc: Determine CLI design for manual cleaning #13060

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ehuss opened this issue Nov 28, 2023 · 6 comments
Open

gc: Determine CLI design for manual cleaning #13060

ehuss opened this issue Nov 28, 2023 · 6 comments
Labels
Command-clean S-needs-design Status: Needs someone to work further on the design for the feature or fix. NOT YET accepted. Z-gc Nightly: garbage collection

Comments

@ehuss
Copy link
Contributor

ehuss commented Nov 28, 2023

The current implementation from #12634 exposes a cargo clean gc subcommand to handle manually cleaning cache data. It is not clear what the final CLI design should be (and it is not clear exactly what the user scenarios are for when they would want to take manual control). This issue is tracking for determining what the CLI should look like. There are few different considerations:

  • What should the actual subcommand be called? There were a few different considerations:
    • cargo cache is already in use by a third-party command
    • cargo gc (reserved by a third-party, but unused), was part of early proposals (cargo doesn't handle unstable top-level subcommands very well)
    • cargo clean gc — the current implementation
    • cargo clean — just fold the functionality into a single command which handles cleaning caches. @epage has concerns that this is overloading a subcommand used for different types of caches (local vs global, etc.).
    • cargo maintenance — just an idea stolen from git
  • How does this evolve with cleaning target directories, global build caches, etc.?
  • Which flags should be exposed? Currently it exposes a large number of low-level flags. Ideally I would like to only stabilize a small number of higher-level flags. But I don't know what the high-level user scenarios might be, so I'm uncertain exactly what to expose.
    • For example, one idea is to have a flag for "things that can be recreated" and another for "things that require downloading".
    • Also bikeshed the names of the options.
@ehuss ehuss added Command-clean S-needs-design Status: Needs someone to work further on the design for the feature or fix. NOT YET accepted. Z-gc Nightly: garbage collection labels Nov 28, 2023
@epage
Copy link
Contributor

epage commented Nov 28, 2023

Potential sources of prior of other tools with cache management

Apparently buck2 and Turborepo grow unbounded

@epage
Copy link
Contributor

epage commented Nov 28, 2023

Quick scan of brew

  • autoremove
  • cleanup
    • "Removes all downloads more than 120 days old. This can be adjusted with HOMEBREW_CLEANUP_MAX_AGE_DAYS."
  • HOMEBREW_CLEANUP_PERIODIC_FULL_DAYS (default 30 days)

One complaint that came up was "brew cleanup has not been run in 30 days, running now" ... and then proceeds to run an interminable process in the middle of you attempting to do something else." (mastadon)

@epage
Copy link
Contributor

epage commented Nov 28, 2023

We should probably step back and enumerate what the required use cases are and the "if it works" use cases.

@juliusl
Copy link

juliusl commented May 30, 2024

I like the way pnpm approaches this,

https://pnpm.io/cli/store

Running pnpm store prune is not harmful and has no side effects on your projects. If future installations require removed packages, pnpm will download them again.

It is best practice to run pnpm store prune occasionally to clean up the store, but not too frequently. Sometimes, unreferenced packages become required again. This could occur when switching branches and installing older dependencies, in which case pnpm would need to re-download all removed packages, briefly slowing down the installation process.

@juliusl
Copy link

juliusl commented May 30, 2024

Regarding the concern of deleting crates that might still be in use, I like how rushjs asks you to pass an --unsafe flag to it's purge command,

https://rushjs.io/pages/commands/rush_purge/

 --unsafe    (UNSAFE!) Also delete shared files such as the package manager
              instances stored in the ".rush" folder in the user's home
              directory. This is a more aggressive fix that is NOT SAFE to
              run in a live environment because it will cause other
              concurrent Rush processes to fail.

@epage
Copy link
Contributor

epage commented May 30, 2024

@juliusl

https://pnpm.io/cli/store

it sounds like pnpm store prune removes everything that isn't referenced, regardless of age or size.

In #13137 I bring up the idea to build on top of the work to track workspaces in #13136 so we pin entries not in current lockfiles.

To extend this to clean up everything has the risk is if a project is transient (e.g. removable media) or moved but a new command wasn't run to register the new location. If its manually done with a command, rather than part of the auto-gc, then that might be reasonable, especially if we swap the logic and have a --execute flag rather than a --dry-run flag.

Regarding the concern of deleting crates that might still be in use, I like how rushjs asks you to pass an --unsafe flag to it's purge command,

I don't think an --unsafe flag is as relevant. For any shared directories, we use filesystem locks to ensure consistent reads/writes.

Any "in use" concerns we have are more about "relevant to the user" and not "file descriptors are open" and is mostly relevant for slow networks/systems and offline usage (I don't want a rarely used dependency being removed just before I go on an airplane to do development offline).

github-merge-queue bot pushed a commit that referenced this issue Apr 27, 2025
This proposes to stabilize automatic garbage collection of Cargo's
global cache data in the cargo home directory.

### What is being stabilized?

This PR stabilizes automatic garbage collection, which is triggered at
most once per day by default. This automatic gc will delete old, unused
files in cargo's home directory.

It will delete files that need to be downloaded from the network after 3
months, and files that can be generated without network access after 1
month. These thresholds are intended to balance the intent of reducing
cargo's disk usage versus deleting too often forcing cargo to do extra
work when files are missing.

Tracking of the last-use data is stored in a sqlite database in the
cargo home directory. Cargo updates timestamps in that database whenever
it accesses a file in the cache. This part is already stabilized.

This PR also stabilizes the `gc.auto.frequency` configuration option.
The primary use case for when a user may want to set that is to set it
to "never" to disable gc should the need arise to avoid it.

When gc is initiated, and there are files to delete, there will be a
progress bar while it is deleting them. The progress bar will disappear
when it finishes. If the user runs with `-v` verbose option, then cargo
will also display which files it deletes.

If there is an error while cleaning, cargo will only display a warning,
and otherwise continue.

### What is not being stabilized?

The manual garbage collection option (via `cargo clean gc`) is not
proposed to be stabilized at this time. That still needs some design
work. This is tracked in
#13060.

Additionally, there are several low-level config options currently
implemented which define the thresholds for when it will delete files. I
think these options are probably too low-level and specific. This is
tracked in #13061.

Garbage collection of build artifacts is not yet implemented, and
tracked in #13136.

### Background

This feature is tracked in
#12633 and was implemented in a
variety of PRs, primarily #12634.

The tests for this feature are located in
https://github.com/rust-lang/cargo/blob/master/tests/testsuite/global_cache_tracker.rs.

Cargo started tracking the last-use data on stable via
#13492 in 1.78 which was released
2024-05-02. This PR is proposing to stabilize automatic deletion in 1.82
which will be released in 2024-10-17.

### Risks

Users who frequently use versions of Rust older than 1.78 will not have
the last-use data tracking updated. If they infrequently use 1.78 or
newer, and use the same cache files, then the last-use tracking will
only be updated by the newer versions. If that time frame is more than 1
month (or 3 months for downloaded data), then cargo will delete files
that the older versions are still using. This means the next time they
run the older version, it will have to re-download or re-extract the
files.

The effects of deleting cache data in environments where cargo's cache
is modified by external tools is not fully known. For example, CI
caching systems may save and restore cargo's cache. Similarly, things
like Docker images that try to save the cache in a layer, or mount the
cache in a read-only filesystem may have undesirable interactions.

The once-a-day performance hit might be noticeable to some people. I've
been using this for several months, and almost never notice it. However,
slower systems, or situations where there is a lot of data to delete
might take a while (on the order of seconds hopefully).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Command-clean S-needs-design Status: Needs someone to work further on the design for the feature or fix. NOT YET accepted. Z-gc Nightly: garbage collection
Projects
None yet
Development

No branches or pull requests

3 participants