Skip to content

Commit 432e1f0

Browse files
committed
Fix concurrent writesto fs cache
1 parent 50f741c commit 432e1f0

1 file changed

Lines changed: 75 additions & 49 deletions

File tree

pkg/storage/fs.go

Lines changed: 75 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ package storage
22

33
import (
44
"errors"
5+
"fmt"
56
"io/ioutil"
67
"log"
78
"os"
89
"path/filepath"
910
"strings"
11+
"sync"
1012

1113
"github.com/Bitspark/go-funk"
1214
"github.com/Bitspark/slang/pkg/core"
@@ -18,9 +20,9 @@ import (
1820
var FILE_ENDINGS = []string{".yaml", ".yml", ".json"} // Order of endings matters!
1921

2022
type FileSystem struct {
21-
root string
22-
cache map[uuid.UUID]*core.Blueprint
23-
uuids []uuid.UUID
23+
root string
24+
cache map[uuid.UUID]*core.Blueprint
25+
cacheLock sync.Mutex
2426
}
2527

2628
type WritableFileSystem struct {
@@ -39,12 +41,22 @@ func cleanPath(p string) string {
3941

4042
func NewWritableFileSystem(root string) *WritableFileSystem {
4143
p := cleanPath(root)
42-
return &WritableFileSystem{FileSystem: FileSystem{p, make(map[uuid.UUID]*core.Blueprint), nil}}
44+
return &WritableFileSystem{
45+
FileSystem{
46+
p,
47+
make(map[uuid.UUID]*core.Blueprint),
48+
sync.Mutex{},
49+
},
50+
}
4351
}
4452

4553
func NewReadOnlyFileSystem(root string) *FileSystem {
4654
p := cleanPath(root)
47-
return &FileSystem{p, make(map[uuid.UUID]*core.Blueprint), nil}
55+
return &FileSystem{
56+
p,
57+
make(map[uuid.UUID]*core.Blueprint),
58+
sync.Mutex{},
59+
}
4860
}
4961

5062
func (fs *FileSystem) Has(opId uuid.UUID) bool {
@@ -53,44 +65,13 @@ func (fs *FileSystem) Has(opId uuid.UUID) bool {
5365
}
5466

5567
func (fs *FileSystem) List() ([]uuid.UUID, error) {
56-
if fs.uuids != nil {
57-
return fs.uuids, nil
68+
fmt.Println(">", fs.root)
69+
fmt.Println(funk.Keys(fs.cache))
70+
if len(fs.cache) == 0 {
71+
fs.loadBlueprintFiles()
5872
}
5973

60-
opsFilePathSet := make(map[uuid.UUID]bool)
61-
62-
_ = filepath.Walk(fs.root, func(path string, info os.FileInfo, err error) error {
63-
if err != nil {
64-
log.Printf("cannot read file %s: %s", path, err)
65-
return nil
66-
}
67-
68-
// Prevent recursive walk. Just read files within fs.root
69-
if info.IsDir() && path != fs.root {
70-
return filepath.SkipDir
71-
}
72-
73-
if info.IsDir() ||
74-
strings.HasPrefix(info.Name(), ".") ||
75-
!fs.hasSupportedSuffix(info.Name()) {
76-
return nil
77-
}
78-
79-
blueprint, err := fs.readBlueprintFile(path)
80-
81-
if err != nil {
82-
log.Printf("cannot read file %s: %s", path, err)
83-
return nil
84-
}
85-
86-
opsFilePathSet[blueprint.Id] = true
87-
88-
return nil
89-
})
90-
91-
fs.uuids = funk.Keys(opsFilePathSet).([]uuid.UUID)
92-
93-
return fs.List()
74+
return funk.Keys(fs.cache).([]uuid.UUID), nil
9475
}
9576

9677
func (fs *FileSystem) Load(opId uuid.UUID) (*core.Blueprint, error) {
@@ -103,12 +84,15 @@ func (fs *FileSystem) Load(opId uuid.UUID) (*core.Blueprint, error) {
10384
return nil, err
10485
}
10586

106-
fs.cache[opId], err = fs.readBlueprintFile(blueprintFile)
87+
blueprint, err := fs.readBlueprintFile(blueprintFile)
88+
10789
if err != nil {
10890
return nil, err
10991
}
11092

111-
return fs.Load(opId)
93+
fs.cacheThis(blueprint)
94+
95+
return blueprint, nil
11296
}
11397

11498
func (fs *WritableFileSystem) Save(blueprint core.Blueprint) (uuid.UUID, error) {
@@ -122,8 +106,7 @@ func (fs *WritableFileSystem) Save(blueprint core.Blueprint) (uuid.UUID, error)
122106
return opId, err
123107
}
124108

125-
delete(fs.cache, opId)
126-
fs.uuids = append(fs.uuids, opId)
109+
fs.cacheThis(&blueprint)
127110

128111
blueprintYaml, err := yaml.Marshal(&blueprint)
129112

@@ -141,19 +124,31 @@ func (fs *WritableFileSystem) Save(blueprint core.Blueprint) (uuid.UUID, error)
141124

142125
func (fs *WritableFileSystem) List() ([]uuid.UUID, error) {
143126
// force to reload writable/local blueprints
144-
fs.clearCache()
127+
fs.clearCache(nil)
145128
return fs.FileSystem.List()
146129
}
147130

148131
func (fs *WritableFileSystem) Load(opId uuid.UUID) (*core.Blueprint, error) {
149132
// force to reload writable/local blueprints
150-
delete(fs.cache, opId)
133+
fs.clearCache(&opId)
151134
return fs.FileSystem.Load(opId)
152135
}
153136

154-
func (fs *WritableFileSystem) clearCache() {
137+
func (fs *FileSystem) cacheThis(blueprint *core.Blueprint) {
138+
fs.cacheLock.Lock()
139+
fs.cache[blueprint.Id] = blueprint
140+
fs.cacheLock.Unlock()
141+
}
142+
143+
func (fs *WritableFileSystem) clearCache(blueprintId *uuid.UUID) {
144+
fs.cacheLock.Lock()
145+
if blueprintId != nil {
146+
delete(fs.cache, *blueprintId)
147+
fs.cacheLock.Unlock()
148+
return
149+
}
155150
fs.cache = make(map[uuid.UUID]*core.Blueprint)
156-
fs.uuids = nil
151+
fs.cacheLock.Unlock()
157152
}
158153

159154
func (fs *FileSystem) hasSupportedSuffix(filePath string) bool {
@@ -168,6 +163,37 @@ func (fs *FileSystem) getFilePath(opId uuid.UUID) (string, error) {
168163
return utils.FileWithFileEnding(filepath.Join(fs.root, opId.String()), FILE_ENDINGS)
169164
}
170165

166+
func (fs *FileSystem) loadBlueprintFiles() {
167+
_ = filepath.Walk(fs.root, func(path string, info os.FileInfo, err error) error {
168+
if err != nil {
169+
log.Printf("cannot read file %s: %s", path, err)
170+
return nil
171+
}
172+
173+
// Prevent recursive walk. Just read files within fs.root
174+
if info.IsDir() && path != fs.root {
175+
return filepath.SkipDir
176+
}
177+
178+
if info.IsDir() ||
179+
strings.HasPrefix(info.Name(), ".") ||
180+
!fs.hasSupportedSuffix(info.Name()) {
181+
return nil
182+
}
183+
184+
blueprint, err := fs.readBlueprintFile(path)
185+
186+
if err != nil {
187+
log.Printf("cannot read file %s: %s", path, err)
188+
return nil
189+
}
190+
191+
fs.cacheThis(blueprint)
192+
193+
return nil
194+
})
195+
}
196+
171197
func (fs *FileSystem) readBlueprintFile(blueprintFile string) (*core.Blueprint, error) {
172198
b, err := ioutil.ReadFile(blueprintFile)
173199
if err != nil {

0 commit comments

Comments
 (0)