Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Okstad <pokstad@gitlab.com>2019-08-16 14:03:28 +0300
committerJacob Vosmaer <jacob@gitlab.com>2019-08-16 14:03:28 +0300
commitdb21dcb0bef6af6234b073dcfae545d3f1951daf (patch)
tree1ec42733826958d3889145f23c3ab4b85647e861 /internal/cache
parent37d86913ab56267e40d2adaf15605a828b13109a (diff)
Disk cache object directory initial clear
Diffstat (limited to 'internal/cache')
-rw-r--r--internal/cache/export_test.go3
-rw-r--r--internal/cache/keyer.go9
-rw-r--r--internal/cache/walker.go76
-rw-r--r--internal/cache/walker_test.go72
4 files changed, 134 insertions, 26 deletions
diff --git a/internal/cache/export_test.go b/internal/cache/export_test.go
index cb1f65b67..287072118 100644
--- a/internal/cache/export_test.go
+++ b/internal/cache/export_test.go
@@ -5,6 +5,9 @@ import "sync"
var (
ExportMockRemovalCounter = new(mockCounter)
ExportMockCheckCounter = new(mockCounter)
+
+ ExportDisableMoveAndClear = &disableMoveAndClear
+ ExportDisableWalker = &disableWalker
)
type mockCounter struct {
diff --git a/internal/cache/keyer.go b/internal/cache/keyer.go
index 20acbd414..b8d4609d0 100644
--- a/internal/cache/keyer.go
+++ b/internal/cache/keyer.go
@@ -213,14 +213,7 @@ func newPendingLease(repo *gitalypb.Repository) (string, error) {
// cacheDir is $STORAGE/+gitaly/cache
func cacheDir(repo *gitalypb.Repository) (string, error) {
- storagePath, err := helper.GetStorageByName(repo.StorageName)
- if err != nil {
- return "", err
- }
-
- absPath := filepath.Join(storagePath, tempdir.CachePrefix)
-
- return absPath, nil
+ return tempdir.CacheDir(repo.GetStorageName())
}
func currentLeases(repo *gitalypb.Repository) ([]os.FileInfo, error) {
diff --git a/internal/cache/walker.go b/internal/cache/walker.go
index 4bbff532d..e70ee8846 100644
--- a/internal/cache/walker.go
+++ b/internal/cache/walker.go
@@ -6,6 +6,7 @@
package cache
import (
+ "io/ioutil"
"os"
"path/filepath"
"time"
@@ -15,8 +16,11 @@ import (
"gitlab.com/gitlab-org/gitaly/internal/tempdir"
)
-func cleanWalk(storagePath string) error {
- cachePath := filepath.Join(storagePath, tempdir.CachePrefix)
+func cleanWalk(storageName string) error {
+ cachePath, err := tempdir.CacheDir(storageName)
+ if err != nil {
+ return err
+ }
err := filepath.Walk(cachePath, func(path string, info os.FileInfo, err error) error {
if err != nil {
@@ -40,6 +44,7 @@ func cleanWalk(storagePath string) error {
// have deleted the file already
return nil
}
+
return err
}
@@ -58,21 +63,86 @@ func cleanWalk(storagePath string) error {
const cleanWalkFrequency = 10 * time.Minute
func startCleanWalker(storage config.Storage) {
+ if disableWalker {
+ return
+ }
+
logrus.WithField("storage", storage.Name).Info("Starting disk cache object walker")
walkTick := time.NewTicker(cleanWalkFrequency)
go func() {
for {
- if err := cleanWalk(storage.Path); err != nil {
+ if err := cleanWalk(storage.Name); err != nil {
logrus.WithField("storage", storage.Name).Error(err)
}
+
<-walkTick.C
}
}()
}
+var (
+ disableMoveAndClear bool // only used to disable move and clear in tests
+ disableWalker bool // only used to disable object walker in tests
+)
+
+// moveAndClear will move the cache to the storage location's
+// temporary folder, and then remove its contents asynchronously
+func moveAndClear(storage config.Storage) error {
+ if disableMoveAndClear {
+ return nil
+ }
+
+ logger := logrus.WithField("storage", storage.Name)
+ logger.Info("clearing disk cache object folder")
+
+ cachePath, err := tempdir.CacheDir(storage.Name)
+ if err != nil {
+ return err
+ }
+
+ tempPath, err := tempdir.TempDir(storage.Name)
+ if err != nil {
+ return err
+ }
+
+ if err := os.MkdirAll(tempPath, 0755); err != nil {
+ return err
+ }
+
+ tmpDir, err := ioutil.TempDir(tempPath, "diskcache")
+ if err != nil {
+ return err
+ }
+
+ logger.Infof("moving disk cache object folder to %s", tmpDir)
+ if err := os.Rename(cachePath, filepath.Join(tmpDir, "moved")); err != nil {
+ if os.IsNotExist(err) {
+ logger.Info("disk cache object folder doesn't exist, no need to remove")
+ return nil
+ }
+
+ return err
+ }
+
+ go func() {
+ start := time.Now()
+ if err := os.RemoveAll(tmpDir); err != nil {
+ logger.Errorf("unable to remove disk cache objects: %q", err)
+ }
+
+ logger.Infof("cleared all cache object files in %s after %s", tmpDir, time.Since(start))
+ }()
+
+ return nil
+}
+
func init() {
config.RegisterHook(func() error {
for _, storage := range config.Config.Storages {
+ if err := moveAndClear(storage); err != nil {
+ return err
+ }
+
startCleanWalker(storage)
}
return nil
diff --git a/internal/cache/walker_test.go b/internal/cache/walker_test.go
index ef6f9b9e3..b3d3044d6 100644
--- a/internal/cache/walker_test.go
+++ b/internal/cache/walker_test.go
@@ -12,23 +12,12 @@ import (
"gitlab.com/gitlab-org/gitaly/internal/cache"
"gitlab.com/gitlab-org/gitaly/internal/config"
"gitlab.com/gitlab-org/gitaly/internal/tempdir"
+ "gitlab.com/gitlab-org/gitaly/internal/testhelper"
)
func TestDiskCacheObjectWalker(t *testing.T) {
- tmpPath, err := ioutil.TempDir("", t.Name())
- require.NoError(t, err)
- defer func() { require.NoError(t, os.RemoveAll(tmpPath)) }()
-
- oldStorages := config.Config.Storages
- config.Config.Storages = []config.Storage{
- {
- Name: t.Name(),
- Path: tmpPath,
- },
- }
- defer func() { config.Config.Storages = oldStorages }()
-
- satisfyConfigValidation(tmpPath)
+ cleanup := setupDiskCacheWalker(t)
+ defer cleanup()
var shouldExist, shouldNotExist []string
@@ -42,7 +31,10 @@ func TestDiskCacheObjectWalker(t *testing.T) {
{"2b/ancient", 24 * time.Hour, true},
{"cd/baby", time.Second, false},
} {
- path := filepath.Join(tmpPath, tempdir.CachePrefix, tt.name)
+ cacheDir, err := tempdir.CacheDir(t.Name()) // test name is storage name
+ require.NoError(t, err)
+
+ path := filepath.Join(cacheDir, tt.name)
require.NoError(t, os.MkdirAll(filepath.Dir(path), 0755))
f, err := os.Create(path)
@@ -61,6 +53,11 @@ func TestDiskCacheObjectWalker(t *testing.T) {
expectChecks := cache.ExportMockCheckCounter.Count() + 4
expectRemovals := cache.ExportMockRemovalCounter.Count() + 2
+ // disable the initial move-and-clear function since we are only
+ // evaluating the walker
+ *cache.ExportDisableMoveAndClear = true
+ defer func() { *cache.ExportDisableMoveAndClear = false }()
+
require.NoError(t, config.Validate()) // triggers walker
pollCountersUntil(t, expectChecks, expectRemovals)
@@ -75,6 +72,51 @@ func TestDiskCacheObjectWalker(t *testing.T) {
}
}
+func TestDiskCacheInitialClear(t *testing.T) {
+ cleanup := setupDiskCacheWalker(t)
+ defer cleanup()
+
+ cacheDir, err := tempdir.CacheDir(t.Name()) // test name is storage name
+ require.NoError(t, err)
+
+ canary := filepath.Join(cacheDir, "canary.txt")
+ require.NoError(t, os.MkdirAll(filepath.Dir(canary), 0755))
+ require.NoError(t, ioutil.WriteFile(canary, []byte("chirp chirp"), 0755))
+
+ // disable the background walkers since we are only
+ // evaluating the initial move-and-clear function
+ *cache.ExportDisableWalker = true
+ defer func() { *cache.ExportDisableWalker = false }()
+
+ // validation will run cache walker hook which synchronously
+ // runs the move-and-clear function
+ require.NoError(t, config.Validate())
+
+ testhelper.AssertFileNotExists(t, canary)
+}
+
+func setupDiskCacheWalker(t testing.TB) func() {
+ tmpPath, err := ioutil.TempDir("", t.Name())
+ require.NoError(t, err)
+
+ oldStorages := config.Config.Storages
+ config.Config.Storages = []config.Storage{
+ {
+ Name: t.Name(),
+ Path: tmpPath,
+ },
+ }
+
+ satisfyConfigValidation(tmpPath)
+
+ cleanup := func() {
+ config.Config.Storages = oldStorages
+ require.NoError(t, os.RemoveAll(tmpPath))
+ }
+
+ return cleanup
+}
+
// satisfyConfigValidation puts garbage values in the config file to satisfy
// validation
func satisfyConfigValidation(tmpPath string) {