The store had no working tools: its TypeScript client was never built, and nothing could count what the store holds that no record names. A Go bundle lists the store's files through its own container, reads each manifest through its door, and sets that beside the controller's records. Collection is asked of the controller, which decides and records; the store's tools never delete. The image.pushed event was declared and never emitted, and nothing consumes it, so it goes.
130 lines
3.2 KiB
Go
130 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"sort"
|
|
)
|
|
|
|
// View is the store at one moment: its files, and every manifest's content that could be read.
|
|
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
|
|
}
|
|
|
|
// 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
|
|
}
|