cachemanager: new active creation
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>docker-18.09
parent
5509c18410
commit
f2739f0728
|
@ -2,12 +2,15 @@ package cachemanager
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/containerd/containerd/mount"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tonistiigi/buildkit_poc/snapshot"
|
||||
)
|
||||
|
@ -45,23 +48,18 @@ type SnapshotRef interface {
|
|||
|
||||
type ActiveRef interface {
|
||||
Mountable
|
||||
Release() (SnapshotRef, error)
|
||||
ReleaseActive() (SnapshotRef, error)
|
||||
ReleaseAndCommit(ctx context.Context) (SnapshotRef, error)
|
||||
Size() (int64, error)
|
||||
}
|
||||
|
||||
type Mountable interface {
|
||||
Mount() (Mount, error)
|
||||
}
|
||||
|
||||
type Mount interface { // replace with containerd.Mount
|
||||
Mount() (string, error)
|
||||
Unmount() error
|
||||
Mount() ([]mount.Mount, error)
|
||||
}
|
||||
|
||||
type CacheAccessor interface {
|
||||
Get(id string) (SnapshotRef, error)
|
||||
New(id string, s SnapshotRef) (ActiveRef, error)
|
||||
New(s SnapshotRef) (ActiveRef, error)
|
||||
GetActive(id string) (ActiveRef, error) // Rebase?
|
||||
}
|
||||
|
||||
|
@ -133,8 +131,25 @@ func (cm *cacheManager) Get(id string) (SnapshotRef, error) {
|
|||
}
|
||||
return rec.ref(), nil
|
||||
}
|
||||
func (cm *cacheManager) New(id string, s SnapshotRef) (ActiveRef, error) {
|
||||
return nil, errors.New("New not implemented")
|
||||
func (cm *cacheManager) New(s SnapshotRef) (ActiveRef, error) {
|
||||
if s != nil {
|
||||
return nil, errors.New("snapshot parents not implemented") // TODO
|
||||
}
|
||||
|
||||
id := generateID()
|
||||
|
||||
if _, err := cm.Snapshotter.Prepare(context.TODO(), id, ""); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to prepare %s", id)
|
||||
}
|
||||
|
||||
rec := &cacheRecord{
|
||||
active: true,
|
||||
id: id,
|
||||
cm: cm,
|
||||
refs: make(map[*snapshotRef]struct{}),
|
||||
}
|
||||
|
||||
return rec.ref(), nil
|
||||
}
|
||||
func (cm *cacheManager) GetActive(id string) (ActiveRef, error) { // Rebase?
|
||||
return nil, errors.New("GetActive not implemented")
|
||||
|
@ -153,9 +168,12 @@ func (cm *cacheManager) GC(ctx context.Context) error {
|
|||
}
|
||||
|
||||
type cacheRecord struct {
|
||||
mu sync.Mutex
|
||||
active bool
|
||||
// meta SnapMeta
|
||||
refs map[*snapshotRef]struct{}
|
||||
id string
|
||||
cm *cacheManager
|
||||
}
|
||||
|
||||
// hold manager lock before calling
|
||||
|
@ -169,14 +187,41 @@ type snapshotRef struct {
|
|||
*cacheRecord
|
||||
}
|
||||
|
||||
func (sr *snapshotRef) Mount() (Mount, error) {
|
||||
return nil, errors.New("Mount not implemented")
|
||||
func (sr *snapshotRef) Mount() ([]mount.Mount, error) {
|
||||
sr.mu.Lock()
|
||||
defer sr.mu.Unlock()
|
||||
|
||||
if sr.active {
|
||||
m, err := sr.cm.Snapshotter.Mounts(context.TODO(), sr.id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to mount %s", sr.id)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("snapshot mount not implemented")
|
||||
}
|
||||
|
||||
func (sr *snapshotRef) Release() error {
|
||||
return errors.New("Release not implemented")
|
||||
}
|
||||
|
||||
func (sr *snapshotRef) ReleaseActive() (SnapshotRef, error) {
|
||||
return nil, errors.New("ReleaseActive not implemented")
|
||||
}
|
||||
|
||||
func (sr *snapshotRef) ReleaseAndCommit(ctx context.Context) (SnapshotRef, error) {
|
||||
return nil, errors.New("ReleaseActive not implemented")
|
||||
}
|
||||
|
||||
func (sr *snapshotRef) Size() (int64, error) {
|
||||
return -1, errors.New("Size not implemented")
|
||||
}
|
||||
|
||||
func generateID() string {
|
||||
b := make([]byte, 32)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
|
|
|
@ -3,9 +3,12 @@ package cachemanager
|
|||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/containerd/snapshot/naive"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tonistiigi/buildkit_poc/snapshot"
|
||||
)
|
||||
|
||||
func TestCacheManager(t *testing.T) {
|
||||
|
@ -13,12 +16,35 @@ func TestCacheManager(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
cm, err := NewCacheManager(CacheManagerOpt{Root: tmpdir})
|
||||
snapshotter, err := naive.NewSnapshotter(filepath.Join(tmpdir, "snapshots"))
|
||||
assert.NoError(t, err)
|
||||
|
||||
cm, err := NewCacheManager(CacheManagerOpt{
|
||||
Root: tmpdir,
|
||||
Snapshotter: snapshotter,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = cm.Get("foobar")
|
||||
assert.Error(t, err)
|
||||
|
||||
active, err := cm.New(nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
m, err := active.Mount()
|
||||
assert.NoError(t, err)
|
||||
|
||||
lm := snapshot.LocalMounter(m)
|
||||
target, err := lm.Mount()
|
||||
assert.NoError(t, err)
|
||||
|
||||
fi, err := os.Stat(target)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, fi.IsDir(), true)
|
||||
|
||||
err = lm.Unmount()
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = cm.Close()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
FROM golang:1.8-alpine AS vndr
|
||||
RUN apk add --no-cache g++
|
||||
WORKDIR /go/src/github.com/tonistiigi/buildkit_poc
|
||||
COPY . .
|
||||
RUN go test ./...
|
|
@ -0,0 +1,59 @@
|
|||
package snapshot
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/containerd/containerd/mount"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Mounter interface {
|
||||
Mount() (string, error)
|
||||
Unmount() error
|
||||
}
|
||||
|
||||
func LocalMounter(m []mount.Mount) Mounter {
|
||||
return &localMounter{m: m}
|
||||
}
|
||||
|
||||
type localMounter struct {
|
||||
mu sync.Mutex
|
||||
m []mount.Mount
|
||||
target string
|
||||
}
|
||||
|
||||
func (lm *localMounter) Mount() (string, error) {
|
||||
lm.mu.Lock()
|
||||
defer lm.mu.Unlock()
|
||||
|
||||
if len(lm.m) == 1 && lm.m[0].Type == "bind" {
|
||||
return lm.m[0].Source, nil
|
||||
}
|
||||
|
||||
dir, err := ioutil.TempDir("", "buildkit-mount")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to create temp dir")
|
||||
}
|
||||
|
||||
if err := mount.MountAll(lm.m, dir); err != nil {
|
||||
os.RemoveAll(dir)
|
||||
return "", err
|
||||
}
|
||||
lm.target = dir
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (lm *localMounter) Unmount() error {
|
||||
lm.mu.Lock()
|
||||
defer lm.mu.Unlock()
|
||||
|
||||
if lm.target != "" {
|
||||
if err := mount.Unmount(lm.target, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
lm.target = ""
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,5 +1,13 @@
|
|||
package snapshot
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/containerd/mount"
|
||||
)
|
||||
|
||||
// Snapshotter defines interface that any snapshot implementation should satisfy
|
||||
type Snapshotter interface {
|
||||
Prepare(ctx context.Context, key, parent string) ([]mount.Mount, error)
|
||||
Mounts(ctx context.Context, key string) ([]mount.Mount, error)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue