Implement file cache through artifact cache

This commit is contained in:
Fedor Korotkiy 2020-03-29 23:35:58 +03:00
parent 872752d3ef
commit 9f9efa18c0
4 changed files with 118 additions and 14 deletions

View file

@ -92,5 +92,5 @@ func (h *HeartbeatHandler) Register(mux *http.ServeMux) {
} }
func (h *HeartbeatHandler) heartbeat(w http.ResponseWriter, r *http.Request) { func (h *HeartbeatHandler) heartbeat(w http.ResponseWriter, r *http.Request) {
panic("implement me")
} }

View file

@ -14,9 +14,9 @@ import (
) )
var ( var (
ErrNotFound = errors.New("file not found") ErrNotFound = errors.New("artifact not found")
ErrWriteLocked = errors.New("file is locked for write") ErrWriteLocked = errors.New("artifact is locked for write")
ErrReadLocked = errors.New("file is locked for read") ErrReadLocked = errors.New("artifact is locked for read")
) )
type Cache struct { type Cache struct {

View file

@ -2,11 +2,12 @@ package filecache
import ( import (
"errors" "errors"
"fmt"
"io" "io"
"net/http" "net/http"
"os" "os"
"path/filepath"
"gitlab.com/slon/shad-go/distbuild/pkg/artifact"
"gitlab.com/slon/shad-go/distbuild/pkg/build" "gitlab.com/slon/shad-go/distbuild/pkg/build"
) )
@ -16,33 +17,95 @@ var (
ErrReadLocked = errors.New("file is locked for read") ErrReadLocked = errors.New("file is locked for read")
) )
const fileName = "file"
func convertErr(err error) error {
switch {
case errors.Is(err, artifact.ErrNotFound):
return ErrNotFound
case errors.Is(err, artifact.ErrWriteLocked):
return ErrWriteLocked
case errors.Is(err, artifact.ErrReadLocked):
return ErrReadLocked
default:
return err
}
}
type Cache struct { type Cache struct {
rootDir string cache *artifact.Cache
} }
func New(rootDir string) (*Cache, error) { func New(rootDir string) (*Cache, error) {
if err := os.MkdirAll(rootDir, 0777); err != nil { cache, err := artifact.NewCache(rootDir)
return nil, fmt.Errorf("error creating filecache: %w", err) if err != nil {
return nil, err
} }
c := &Cache{rootDir: rootDir} c := &Cache{cache: cache}
return c, nil return c, nil
} }
func (c *Cache) Range(fileFn func(file build.ID) error) error { func (c *Cache) Range(fileFn func(file build.ID) error) error {
panic("implement me") return c.cache.Range(fileFn)
} }
func (c *Cache) Remove(file build.ID) error { func (c *Cache) Remove(file build.ID) error {
panic("implement me") return convertErr(c.cache.Remove(file))
} }
func (c *Cache) Write(file build.ID) (w io.WriteCloser, abort func(), err error) { type fileWriter struct {
panic("implement me") f *os.File
commit func() error
}
func (f *fileWriter) Write(p []byte) (int, error) {
return f.f.Write(p)
}
func (f *fileWriter) Close() error {
closeErr := f.f.Close()
commitErr := f.commit()
if closeErr != nil {
return closeErr
}
return commitErr
}
func (c *Cache) Write(file build.ID) (w io.WriteCloser, abort func() error, err error) {
path, commit, abortDir, err := c.cache.Create(file)
if err != nil {
err = convertErr(err)
return
}
f, err := os.Create(filepath.Join(path, fileName))
if err != nil {
_ = abort()
return
}
w = &fileWriter{f: f, commit: commit}
abort = func() error {
closeErr := f.Close()
abortErr := abortDir()
if closeErr != nil {
return closeErr
}
return abortErr
}
return
} }
func (c *Cache) Get(file build.ID) (path string, unlock func(), err error) { func (c *Cache) Get(file build.ID) (path string, unlock func(), err error) {
panic("implement me") root, unlock, err := c.cache.Get(file)
path = filepath.Join(root, fileName)
err = convertErr(err)
return
} }
func NewHandler(c *Cache) http.Handler { func NewHandler(c *Cache) http.Handler {

View file

@ -0,0 +1,41 @@
package filecache
import (
"errors"
"io/ioutil"
"testing"
"github.com/stretchr/testify/require"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
func TestFileCache(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "filecache")
require.NoError(t, err)
cache, err := New(tmpDir)
require.NoError(t, err)
_, abort, err := cache.Write(build.ID{01})
require.NoError(t, err)
require.NoError(t, abort())
_, _, err = cache.Get(build.ID{01})
require.Truef(t, errors.Is(err, ErrNotFound), "real error: %v", err)
f, _, err := cache.Write(build.ID{02})
require.NoError(t, err)
_, err = f.Write([]byte("foo bar"))
require.NoError(t, err)
require.NoError(t, f.Close())
path, unlock, err := cache.Get(build.ID{02})
require.NoError(t, err)
defer unlock()
content, err := ioutil.ReadFile(path)
require.NoError(t, err)
require.Equal(t, []byte("foo bar"), content)
}