diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-06-01 14:51:40 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-06-02 13:28:24 +0900 |
| commit | fbd2329d50a9ef2b15c0a6b62e9aa24635c2662a (patch) | |
| tree | 2c8b0c8c8d16412681c9e758e9121dab022cc008 /internal/pkg/clean.go | |
| parent | f398f71fa947dbf03587b1a28d314a969aa6b351 (diff) | |
internal/pkg: garbage collection
This destroys cache entries not referred to by user-specified artifacts and optionally their inputs.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/pkg/clean.go')
| -rw-r--r-- | internal/pkg/clean.go | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/internal/pkg/clean.go b/internal/pkg/clean.go new file mode 100644 index 00000000..addcd32d --- /dev/null +++ b/internal/pkg/clean.go @@ -0,0 +1,138 @@ +package pkg + +import ( + "errors" + "os" + "unique" +) + +// Clean destroys checksum backing entries without any identifier or substitute +// entry referring to it. If at least one keep [Artifact] is specified, +// identifier and substitute entries not kept alive by them are destroyed first. +func (c *Cache) Clean(dry, inputs bool, keep ...Artifact) ( + []unique.Handle[ID], + []unique.Handle[Checksum], + error, +) { + c.identMu.Lock() + defer c.identMu.Unlock() + + c.checksumMu.Lock() + defer c.checksumMu.Unlock() + + dents, err := os.ReadDir(c.base.Append(dirChecksum).String()) + if err != nil { + return nil, nil, err + } + checksums := make(map[unique.Handle[Checksum]]string, len(dents)) + var buf Checksum + for _, dent := range dents { + name := dent.Name() + if err = Decode(&buf, name); err != nil { + return nil, nil, err + } + checksums[unique.Make(buf)] = name + } + + type identPair struct { + id unique.Handle[ID] + name string + } + dents, err = os.ReadDir(c.base.Append(dirIdentifier).String()) + if err != nil { + return nil, nil, err + } + + keepIdents := make(map[unique.Handle[ID]]struct{}) + if inputs { + for _, id := range Inputs((*Collect)(&keep)) { + keepIdents[id] = struct{}{} + } + } else { + for _, a := range keep { + keepIdents[c.Ident(a)] = struct{}{} + } + } + + idents := make([]identPair, 0, len(dents)) + for _, dent := range dents { + name := dent.Name() + if err = Decode(&buf, name); err != nil { + return nil, nil, err + } + id := unique.Make(ID(buf)) + + if _, ok := keepIdents[id]; len(keep) == 0 || ok { + if err = readlinkChecksum(c.base.Append( + dirIdentifier, + name, + ), &buf); err != nil { + return nil, nil, err + } + delete(checksums, unique.Make(buf)) + continue + } + + c.msg.Verbosef("arranging for destruction of %s...", name) + idents = append(idents, identPair{id, name}) + } + + destroyedIdents := make([]unique.Handle[ID], 0, len(idents)) + for _, pair := range idents { + if !dry { + if err = os.Remove(c.base.Append( + dirIdentifier, + pair.name, + ).String()); err != nil { + return destroyedIdents, nil, err + } + } + destroyedIdents = append(destroyedIdents, pair.id) + } + + destroyedChecksums := make([]unique.Handle[Checksum], 0, len(checksums)) + for checksum, name := range checksums { + if err = c.parent.Err(); err != nil { + return destroyedIdents, destroyedChecksums, err + } + c.msg.Verbosef("destroying checksum %s...", name) + if !dry { + if err = errors.Join(removeAll(c.base.Append( + dirChecksum, + name, + ))); err != nil { + return destroyedIdents, destroyedChecksums, err + } + } + destroyedChecksums = append(destroyedChecksums, checksum) + } + + dents, err = os.ReadDir(c.base.Append(dirSubstitute).String()) + if err != nil { + return destroyedIdents, destroyedChecksums, err + } + for _, dent := range dents { + name := dent.Name() + if err = readlinkChecksum(c.base.Append( + dirSubstitute, + name, + ), &buf); err != nil { + return destroyedIdents, destroyedChecksums, err + } + if _, ok := checksums[unique.Make(buf)]; !ok { + continue + } + + c.msg.Verbosef("destroying substitute %s...", name) + if !dry { + if err = os.Remove(c.base.Append( + dirSubstitute, + name, + ).String()); err != nil { + return destroyedIdents, destroyedChecksums, err + } + } + } + + return destroyedIdents, destroyedChecksums, nil +} |
