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 }