The docker exec listing and the HTTP door go; held and the sweep's index skip ask the seat's list too. The store's address file is the image seat's reach, used for the catalogue's definitions only. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
132 lines
3.3 KiB
Go
132 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"sort"
|
|
)
|
|
|
|
// View is the store at one moment, as its seats list it (listed.go).
|
|
type View struct {
|
|
L *Listing
|
|
// M is each manifest read, by Key.
|
|
M map[string]*Manifest
|
|
// Unread is each manifest that could not be read, by Key, with why.
|
|
Unread map[string]string
|
|
// Held is each manifest a hold on its seat keeps from retention, by Key.
|
|
Held map[string]bool
|
|
}
|
|
|
|
// Marks are the blobs one manifest keeps from the store's collector: its own content, its
|
|
// configuration and its layers, and for an index the manifests it lists. A manifest that could not be
|
|
// read marks only itself here, and the answers that rest on it say so.
|
|
func (v *View) Marks(repo, digest string) []string {
|
|
out := []string{digest}
|
|
if m := v.M[Key(repo, digest)]; m != nil {
|
|
out = append(out, m.Refs...)
|
|
out = append(out, m.Children...)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// Marked is every blob some manifest marks, leaving out the manifests named in without — the
|
|
// collector's own mark, and the mark it would make once those are gone.
|
|
func (v *View) Marked(without map[string]bool) map[string]bool {
|
|
marked := map[string]bool{}
|
|
for name, r := range v.L.Repos {
|
|
for d := range r.Revisions {
|
|
if without[Key(name, d)] {
|
|
continue
|
|
}
|
|
for _, b := range v.Marks(name, d) {
|
|
marked[b] = true
|
|
}
|
|
}
|
|
}
|
|
return marked
|
|
}
|
|
|
|
// Bytes is the size of these blobs, as the store holds them; a blob the store does not hold counts
|
|
// nothing.
|
|
func (v *View) Bytes(blobs map[string]bool) int64 {
|
|
var n int64
|
|
for b := range blobs {
|
|
n += v.L.Blobs[b]
|
|
}
|
|
return n
|
|
}
|
|
|
|
// Total is the size of every blob the store holds.
|
|
func (v *View) Total() int64 {
|
|
var n int64
|
|
for _, s := range v.L.Blobs {
|
|
n += s
|
|
}
|
|
return n
|
|
}
|
|
|
|
// Unmarked is the bytes and count of the blobs no manifest marks, once the manifests in without are
|
|
// gone: what the nightly collector frees.
|
|
func (v *View) Unmarked(without map[string]bool) (int64, int) {
|
|
marked := v.Marked(without)
|
|
var n int64
|
|
count := 0
|
|
for b, s := range v.L.Blobs {
|
|
if !marked[b] {
|
|
n += s
|
|
count++
|
|
}
|
|
}
|
|
return n, count
|
|
}
|
|
|
|
// RepoBlobs are the blobs one repository's manifests mark.
|
|
func (v *View) RepoBlobs(name string) map[string]bool {
|
|
out := map[string]bool{}
|
|
if r := v.L.Repos[name]; r != nil {
|
|
for d := range r.Revisions {
|
|
for _, b := range v.Marks(name, d) {
|
|
out[b] = true
|
|
}
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// Shared are the blobs that the manifests of more than one repository mark.
|
|
func (v *View) Shared() map[string]bool {
|
|
seen := map[string]string{}
|
|
shared := map[string]bool{}
|
|
for _, name := range v.L.RepoNames() {
|
|
for b := range v.RepoBlobs(name) {
|
|
if first, ok := seen[b]; ok && first != name {
|
|
shared[b] = true
|
|
} else {
|
|
seen[b] = name
|
|
}
|
|
}
|
|
}
|
|
return shared
|
|
}
|
|
|
|
// tagsOf is a repository's tags, in order, with what each names.
|
|
func tagsOf(r *Repo) []map[string]string {
|
|
names := make([]string, 0, len(r.Tags))
|
|
for t := range r.Tags {
|
|
names = append(names, t)
|
|
}
|
|
sort.Strings(names)
|
|
out := make([]map[string]string, 0, len(names))
|
|
for _, t := range names {
|
|
out = append(out, map[string]string{"tag": t, "digest": r.Tags[t]})
|
|
}
|
|
return out
|
|
}
|
|
|
|
// taggedDigests are the manifests some tag names, in one repository.
|
|
func taggedDigests(r *Repo) map[string]bool {
|
|
out := map[string]bool{}
|
|
for _, d := range r.Tags {
|
|
out[d] = true
|
|
}
|
|
return out
|
|
}
|