Repository navigation
Expand file tree
/
Copy pathexecution_cache.go
More file actions
123 lines (95 loc) · 2.88 KB
/
Copy pathexecution_cache.go
File metadata and controls
123 lines (95 loc) · 2.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package executor
import (
"context"
"encoding/json"
"os"
"path/filepath"
"github.com/sourcegraph/sourcegraph/lib/errors"
"github.com/sourcegraph/sourcegraph/lib/batches/execution"
"github.com/sourcegraph/sourcegraph/lib/batches/execution/cache"
)
func NewDiskCache(dir string) cache.Cache {
if dir == "" {
return &ExecutionNoOpCache{}
}
return &ExecutionDiskCache{dir}
}
type ExecutionDiskCache struct {
Dir string
}
const cacheFileExt = ".json"
func (c ExecutionDiskCache) cacheFilePath(key cache.Keyer) (string, error) {
keyString, err := key.Key()
if err != nil {
return "", errors.Wrap(err, "calculating execution cache key")
}
return filepath.Join(c.Dir, key.Slug(), keyString+cacheFileExt), nil
}
func readCacheFile(path string, result any) (bool, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
return false, nil
}
data, err := os.ReadFile(path)
if err != nil {
return false, err
}
if err := json.Unmarshal(data, result); err != nil {
// Delete the invalid data to avoid causing an error for next time.
if err := os.Remove(path); err != nil {
return false, errors.Wrap(err, "while deleting cache file with invalid JSON")
}
return false, errors.Wrapf(err, "reading cache file %s", path)
}
return true, nil
}
func (c ExecutionDiskCache) writeCacheFile(path string, result any) error {
raw, err := json.Marshal(result)
if err != nil {
return errors.Wrap(err, "serializing cache content to JSON")
}
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
return err
}
return os.WriteFile(path, raw, 0600)
}
func (c ExecutionDiskCache) Clear(ctx context.Context, key cache.Keyer) error {
path, err := c.cacheFilePath(key)
if err != nil {
return err
}
if _, err := os.Stat(path); os.IsNotExist(err) {
return nil
}
return os.Remove(path)
}
func (c ExecutionDiskCache) Get(ctx context.Context, key cache.Keyer) (execution.AfterStepResult, bool, error) {
var result execution.AfterStepResult
path, err := c.cacheFilePath(key)
if err != nil {
return result, false, err
}
found, err := readCacheFile(path, &result)
if err != nil {
return result, false, err
}
return result, found, nil
}
func (c ExecutionDiskCache) Set(ctx context.Context, key cache.Keyer, result execution.AfterStepResult) error {
path, err := c.cacheFilePath(key)
if err != nil {
return err
}
return c.writeCacheFile(path, &result)
}
// ExecutionNoOpCache is an implementation of ExecutionCache that does not store or
// retrieve cache entries.
type ExecutionNoOpCache struct{}
func (ExecutionNoOpCache) Clear(ctx context.Context, key cache.Keyer) error {
return nil
}
func (ExecutionNoOpCache) Set(ctx context.Context, key cache.Keyer, result execution.AfterStepResult) error {
return nil
}
func (ExecutionNoOpCache) Get(ctx context.Context, key cache.Keyer) (execution.AfterStepResult, bool, error) {
return execution.AfterStepResult{}, false, nil
}