- rename Go module, binary, systemd unit, PG_DATABASE default, frontend package and docs from shared-album to galo - add theme-aware halo emblem and favicon (new ui-branding capability) - add make build-release (versioned, stripped, static binary) and run the binary from the repo root
75 lines
2.0 KiB
Go
75 lines
2.0 KiB
Go
// Package reconcile computes the difference between the object storage and the
|
|
// metadata journal so orphaned blobs can be reported and, on request, removed.
|
|
package reconcile
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"galo/internal/storage"
|
|
)
|
|
|
|
// Result holds the two kinds of divergence between storage and the journal.
|
|
type Result struct {
|
|
// Orphans are keys present in storage but absent from the journal; they are
|
|
// candidates for deletion.
|
|
Orphans []string
|
|
// Missing are keys present in the journal but absent from storage; they are
|
|
// reported only and never modified.
|
|
Missing []string
|
|
}
|
|
|
|
// Classify compares the listed storage objects with the journaled keys.
|
|
func Classify(objects []storage.ObjectInfo, journaled []string) Result {
|
|
have := make(map[string]struct{}, len(journaled))
|
|
for _, k := range journaled {
|
|
have[k] = struct{}{}
|
|
}
|
|
seen := make(map[string]struct{}, len(objects))
|
|
var orphans []string
|
|
for _, o := range objects {
|
|
if _, dup := seen[o.Key]; dup {
|
|
continue
|
|
}
|
|
seen[o.Key] = struct{}{}
|
|
if _, ok := have[o.Key]; !ok {
|
|
orphans = append(orphans, o.Key)
|
|
}
|
|
}
|
|
var missing []string
|
|
for _, k := range journaled {
|
|
if _, ok := seen[k]; !ok {
|
|
missing = append(missing, k)
|
|
}
|
|
}
|
|
sort.Strings(orphans)
|
|
sort.Strings(missing)
|
|
return Result{Orphans: orphans, Missing: missing}
|
|
}
|
|
|
|
// Deletable selects orphaned keys that are safe to remove: within prefix and
|
|
// older than minAge (a guard against racing an in-flight upload whose row is
|
|
// not written yet).
|
|
func Deletable(objects []storage.ObjectInfo, res Result, prefix string, minAge time.Duration, now time.Time) []string {
|
|
orphans := make(map[string]struct{}, len(res.Orphans))
|
|
for _, k := range res.Orphans {
|
|
orphans[k] = struct{}{}
|
|
}
|
|
var out []string
|
|
for _, o := range objects {
|
|
if _, ok := orphans[o.Key]; !ok {
|
|
continue
|
|
}
|
|
if prefix != "" && !strings.HasPrefix(o.Key, prefix) {
|
|
continue
|
|
}
|
|
if now.Sub(o.ModTime) < minAge {
|
|
continue
|
|
}
|
|
out = append(out, o.Key)
|
|
}
|
|
sort.Strings(out)
|
|
return out
|
|
}
|