From 0e309e08c79debe67a2531eae4c3dd117523411c Mon Sep 17 00:00:00 2001 From: b5 Date: Mon, 16 Nov 2020 20:02:39 -0500 Subject: [PATCH] feat(CAFS): repurpose CAFS acronym as a filesystem property add an interface that allows Filesytems to distinguish when they use refer-by-hash by opting into the CAFS interface. In the future we may want to expand this interface with values for working with hashes, but for now just distinguishing which Filesystems are content-addressed is enough. --- fs.go | 8 ++++++++ mem.go | 28 +++++++++++++++++----------- qipfs/filestore.go | 4 ++++ 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/fs.go b/fs.go index 162561b..2e55435 100644 --- a/fs.go +++ b/fs.go @@ -79,6 +79,14 @@ type PinningFS interface { Unpin(ctx context.Context, key string, recursive bool) error } +// CAFS stands for "content-addressed filesystem". Filesystem that implement +// this interface declare that all paths to persisted content are reference-by +// -hash. +// TODO (b5) - write up a spec test suite for CAFS conformance +type CAFS interface { + IsContentAddressedFilesystem() +} + // AbsPath adjusts the provided string to a path lib functions can work with // because paths for Qri can come from the local filesystem, an http url, or // the distributed web, Absolutizing is a little tricky diff --git a/mem.go b/mem.go index 8a3e464..a5d4e53 100644 --- a/mem.go +++ b/mem.go @@ -53,19 +53,25 @@ type MemFS struct { Files map[string]filer } -// compile-time assertion that MemFS satisfies the Filesystem interface -var _ Filesystem = (*MemFS)(nil) +var ( + // compile-time assertion that MemFS satisfies the Filesystem interface + _ Filesystem = (*MemFS)(nil) + // assert MemFS implements the CAFS interface + _ CAFS = (*MemFS)(nil) +) // MemFilestoreType uniquely identifies the mem filestore const MemFilestoreType = "mem" // Type distinguishes this filesystem from others by a unique string prefix -func (m MemFS) Type() string { +func (m *MemFS) Type() string { return MemFilestoreType } +func (m *MemFS) IsContentAddressedFilesystem() {} + // Print converts the store to a string -func (m MemFS) Print() (string, error) { +func (m *MemFS) Print() (string, error) { m.filesLk.Lock() defer m.filesLk.Unlock() @@ -90,7 +96,7 @@ func (m MemFS) Print() (string, error) { } // ObjectCount returns the number of content-addressed objects in the store -func (m MemFS) ObjectCount() (objects int) { +func (m *MemFS) ObjectCount() (objects int) { for range m.Files { objects++ } @@ -241,7 +247,7 @@ func (m *MemFS) getLocal(key string) (File, error) { } // Has returns whether the store has a File with the key -func (m MemFS) Has(ctx context.Context, key string) (exists bool, err error) { +func (m *MemFS) Has(ctx context.Context, key string) (exists bool, err error) { if _, err := m.getLocal(key); err == nil { return true, nil } @@ -249,7 +255,7 @@ func (m MemFS) Has(ctx context.Context, key string) (exists bool, err error) { } // Delete removes the file from the store with the key -func (m MemFS) Delete(ctx context.Context, key string) error { +func (m *MemFS) Delete(ctx context.Context, key string) error { key = strings.TrimPrefix(key, fmt.Sprintf("/%s/", MemFilestoreType)) // key may be of the form /mem/QmFoo/file.json but MemFS indexes its maps @@ -321,7 +327,7 @@ func (m *MemFS) AddConnection(other *MemFS) { } type adder struct { - fs MemFS + fs *MemFS pin bool out chan AddedFile root string @@ -329,7 +335,7 @@ type adder struct { } // NewAdder returns an Adder for the store -func (m MemFS) NewAdder(ctx context.Context, pin, wrap bool) (Adder, error) { +func (m *MemFS) NewAdder(ctx context.Context, pin, wrap bool) (Adder, error) { addedOut := make(chan AddedFile, 9) return &adder{ fs: m, @@ -373,7 +379,7 @@ func (a *adder) AddFile(ctx context.Context, f File) (err error) { if f.IsDirectory() { var dir fsDir - hash, dir = node.toDir(&a.fs) + hash, dir = node.toDir(a.fs) if err != nil { return err } @@ -413,7 +419,7 @@ func (a *adder) Finalize() (string, error) { log.Debugf("adding root directory") root := NewMemdir("/") node := a.addNode(root) - hash, dir := node.toDir(&a.fs) + hash, dir := node.toDir(a.fs) a.fs.filesLk.Lock() a.fs.Files[hash] = dir a.fs.filesLk.Unlock() diff --git a/qipfs/filestore.go b/qipfs/filestore.go index 778c3d6..6ab4d2e 100644 --- a/qipfs/filestore.go +++ b/qipfs/filestore.go @@ -50,6 +50,7 @@ type Filestore struct { var ( _ qfs.ReleasingFilesystem = (*Filestore)(nil) _ cafs.Fetcher = (*Filestore)(nil) + _ qfs.CAFS = (*Filestore)(nil) ) // NewFilesystem creates a new local filesystem PathResolver @@ -150,6 +151,9 @@ func (fst Filestore) Type() string { return FilestoreType } +// IsContentAddressedFilesystem declares qipfs is content-addressed +func (fst Filestore) IsContentAddressedFilesystem() {} + // Done implements the qfs.ReleasingFilesystem interface func (fst *Filestore) Done() <-chan struct{} { return fst.doneCh