Skip to content

Commit 4f35dbf

Browse files
committed
add new command to remove useless layers
1 parent 05f18cc commit 4f35dbf

File tree

2 files changed

+98
-0
lines changed

2 files changed

+98
-0
lines changed

daemon/cmd/garbage_collection.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package cmd
2+
3+
import (
4+
//"database/sql"
5+
"fmt"
6+
"os"
7+
8+
"github.com/spf13/cobra"
9+
10+
"github.com/cvmfs/docker-graphdriver/daemon/lib"
11+
)
12+
13+
func init() {
14+
rootCmd.AddCommand(garbageCollectionCmd)
15+
}
16+
17+
var garbageCollectionCmd = &cobra.Command{
18+
Use: "garbage-collection",
19+
Short: "Removes layers that are not necessary anymore",
20+
Aliases: []string{"gc"},
21+
Run: func(cmd *cobra.Command, args []string) {
22+
fmt.Println("Start")
23+
lib.RemoveUselessLayers()
24+
os.Exit(0)
25+
},
26+
}

daemon/lib/garbage_collection.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package lib
2+
3+
import (
4+
"fmt"
5+
"path/filepath"
6+
"strings"
7+
)
8+
9+
func getAllLayers() []string {
10+
path := filepath.Join("/", "cvmfs", "*", subDirInsideRepo, "*")
11+
paths, _ := filepath.Glob(path)
12+
return paths
13+
}
14+
15+
// this function is based on an "homegrow" implementation of a set intersection, go, since it does not provide generics, does not provides also generic datastructures like sets
16+
func findToRemoveLayers(all_layers, needed_layers []string) (removes []string) {
17+
all := map[string]bool{}
18+
needed := map[string]bool{}
19+
to_remove := map[string]bool{}
20+
21+
for _, layer := range all_layers {
22+
all[layer] = true
23+
}
24+
for _, layer := range needed_layers {
25+
needed[layer] = true
26+
}
27+
for layer, _ := range all {
28+
_, isNeeded := needed[layer]
29+
if !isNeeded {
30+
to_remove[layer] = true
31+
}
32+
}
33+
for layer := range to_remove {
34+
removes = append(removes, layer)
35+
}
36+
return
37+
}
38+
39+
func RemoveUselessLayers() error {
40+
all_layers := getAllLayers()
41+
needed_layers, err := GetAllNeededLayers()
42+
if err != nil {
43+
return err
44+
}
45+
to_remove := findToRemoveLayers(all_layers, needed_layers)
46+
// to_remove is now a slice of paths that we wish to remove from the
47+
// repository.
48+
// However those paths are "complete":
49+
// `/cvmfs/$repo.name/layers/fffbbbaaa`
50+
// we need to group them by the repository they belong to, and then
51+
// extract only the last part of the path we care about:
52+
// `layers/fffbbbaaa`
53+
paths := map[string][]string{}
54+
for _, path := range to_remove {
55+
pathSplitted := strings.Split(path, "/")
56+
repoName := pathSplitted[2]
57+
paths[repoName] = append(paths[repoName], strings.Join(pathSplitted[3:], "/"))
58+
}
59+
fmt.Println(paths)
60+
// possible optimization
61+
// batch the delete of layers, not all together that it will lock the repo for quite too long
62+
// but few of them like 10 or 20 together is something very reasonable.
63+
for repoName, layers := range paths {
64+
for _, layer := range layers {
65+
err = ExecCommand("cvmfs_server", "ingest", "--delete", layer, repoName)
66+
if err != nil {
67+
LogE(err).Warning("Error in deleting the layer")
68+
}
69+
}
70+
}
71+
return nil
72+
}

0 commit comments

Comments
 (0)