Skip to content

Commit 7b77e31

Browse files
authored
fix(blooms): Clean block directories recursively on startup (#12895)
Any empty directories in the block directory cache directory should recursively be removed to avoid a lot of dangling, empty directories. Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
1 parent 738c274 commit 7b77e31

File tree

2 files changed

+69
-12
lines changed

2 files changed

+69
-12
lines changed

‎pkg/storage/stores/shipper/bloomshipper/cache.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,29 @@ func LoadBlocksDirIntoCache(paths []string, c Cache, logger log.Logger) error {
4545
return err.Err()
4646
}
4747

48+
func removeRecursively(root, path string) error {
49+
if path == root {
50+
// stop when reached root directory
51+
return nil
52+
}
53+
54+
entries, err := os.ReadDir(path)
55+
if err != nil {
56+
// stop in case of error
57+
return err
58+
}
59+
60+
if len(entries) == 0 {
61+
base := filepath.Dir(path)
62+
if err := os.RemoveAll(path); err != nil {
63+
return err
64+
}
65+
return removeRecursively(root, base)
66+
}
67+
68+
return nil
69+
}
70+
4871
func loadBlockDirectories(root string, logger log.Logger) (keys []string, values []BlockDirectory) {
4972
resolver := NewPrefixedResolver(root, defaultKeyResolver{})
5073
_ = filepath.WalkDir(root, func(path string, dirEntry fs.DirEntry, e error) error {
@@ -57,6 +80,15 @@ func loadBlockDirectories(root string, logger log.Logger) (keys []string, values
5780
return nil
5881
}
5982

83+
// Remove empty directories recursively
84+
// filepath.WalkDir() does not support depth-first traversal,
85+
// so this is not very efficient
86+
err := removeRecursively(root, path)
87+
if err != nil {
88+
level.Warn(logger).Log("msg", "failed to remove directory", "path", path, "err", err)
89+
return nil
90+
}
91+
6092
ref, err := resolver.ParseBlockKey(key(path))
6193
if err != nil {
6294
return nil

‎pkg/storage/stores/shipper/bloomshipper/cache_test.go

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package bloomshipper
22

33
import (
44
"context"
5+
"io/fs"
56
"os"
67
"path/filepath"
78
"sync"
@@ -66,19 +67,24 @@ func Test_LoadBlocksDirIntoCache(t *testing.T) {
6667
fp.Close()
6768

6869
// invalid directory
69-
_ = os.MkdirAll(filepath.Join(wd, "not/a/valid/blockdir"), 0o755)
70+
invalidDir := "not/a/valid/blockdir"
71+
_ = os.MkdirAll(filepath.Join(wd, invalidDir), 0o755)
7072

71-
// empty block directory
72-
fn1 := "bloom/table_1/tenant/blocks/0000000000000000-000000000000ffff/0-3600000-abcd"
73-
_ = os.MkdirAll(filepath.Join(wd, fn1), 0o755)
73+
// empty block directories
74+
emptyDir1 := "bloom/table_1/tenant/blocks/0000000000000000-000000000000ffff/0-3600000-abcd"
75+
_ = os.MkdirAll(filepath.Join(wd, emptyDir1), 0o755)
76+
emptyDir2 := "bloom/table_1/tenant/blocks/0000000000010000-000000000001ffff/0-3600000-ef01"
77+
_ = os.MkdirAll(filepath.Join(wd, emptyDir2), 0o755)
78+
emptyDir3 := "bloom/table_1/tenant/blocks/0000000000020000-000000000002ffff/0-3600000-2345"
79+
_ = os.MkdirAll(filepath.Join(wd, emptyDir3), 0o755)
7480

7581
// valid block directory
76-
fn2 := "bloom/table_2/tenant/blocks/0000000000010000-000000000001ffff/0-3600000-abcd"
77-
_ = os.MkdirAll(filepath.Join(wd, fn2), 0o755)
78-
fp, _ = os.Create(filepath.Join(wd, fn2, "bloom"))
79-
fp.Close()
80-
fp, _ = os.Create(filepath.Join(wd, fn2, "series"))
81-
fp.Close()
82+
validDir := "bloom/table_2/tenant/blocks/0000000000010000-000000000001ffff/0-3600000-abcd"
83+
_ = os.MkdirAll(filepath.Join(wd, validDir), 0o755)
84+
for _, fn := range []string{"bloom", "series"} {
85+
fp, _ = os.Create(filepath.Join(wd, validDir, fn))
86+
fp.Close()
87+
}
8288

8389
cfg := config.BlocksCacheConfig{
8490
SoftLimit: 1 << 20,
@@ -93,9 +99,28 @@ func Test_LoadBlocksDirIntoCache(t *testing.T) {
9399

94100
require.Equal(t, 1, len(c.entries))
95101

96-
key := filepath.Join(wd, fn2) + ".tar.gz"
102+
key := filepath.Join(wd, validDir) + ".tar.gz"
97103
elem, found := c.entries[key]
98104
require.True(t, found)
99105
blockDir := elem.Value.(*Entry).Value
100-
require.Equal(t, filepath.Join(wd, fn2), blockDir.Path)
106+
require.Equal(t, filepath.Join(wd, validDir), blockDir.Path)
107+
108+
// check cleaned directories
109+
dirs := make([]string, 0, 6)
110+
_ = filepath.WalkDir(wd, func(path string, dirEntry fs.DirEntry, _ error) error {
111+
if !dirEntry.IsDir() {
112+
return nil
113+
}
114+
dirs = append(dirs, path)
115+
return nil
116+
})
117+
require.Equal(t, []string{
118+
filepath.Join(wd),
119+
filepath.Join(wd, "bloom/"),
120+
filepath.Join(wd, "bloom/table_2/"),
121+
filepath.Join(wd, "bloom/table_2/tenant/"),
122+
filepath.Join(wd, "bloom/table_2/tenant/blocks/"),
123+
filepath.Join(wd, "bloom/table_2/tenant/blocks/0000000000010000-000000000001ffff"),
124+
filepath.Join(wd, "bloom/table_2/tenant/blocks/0000000000010000-000000000001ffff/0-3600000-abcd"),
125+
}, dirs)
101126
}

0 commit comments

Comments
 (0)