@cryptotaxi247 / kubo / commits / 08922d239

mfs: make `Root` value a `Directory`

Make `Root` value explicitly a `Directory` structure instead of the `FSNode` interface (which also allowed the `File` type). This helps to make the code easier to reason about: the root of an MFS layout is always a directory, not a (single) file. Rename `GetValue()` to `GetDirectory()` to also make it more explicit, the renamed function now returns a `Directory` so there is no need for type assertions that were previously done on the `FSNode` interface to check that it was actually a `Directory`. `NewRoot()` now doesn't allow to create `Root` structures from DAG nodes that contain UnixFS files. License: MIT Signed-off-by: Lucas Molas <schomatis@gmail.com>

Lucas Molas committed Jun 29, 2018 at 10:57 UTC 08922d239d3c866ea886d5e6ebec8cb4f9ba94a4
6 files changed +33 -51
core/corerepo/gc.go
+1 -1
@@ -71,7 +71,7 @@ func NewGC(n *core.IpfsNode) (*GC, error) {
71 }
72
73 func BestEffortRoots(filesRoot *mfs.Root) ([]*cid.Cid, error) {
74 - rootDag, err := filesRoot.GetValue().GetNode()
74 + rootDag, err := filesRoot.GetDirectory().GetNode()
75 if err != nil {
76 return nil, err
77 }
core/coreunix/add.go
+4 -6
@@ -144,7 +144,7 @@ func (adder *Adder) RootNode() (ipld.Node, error) {
144 if err != nil {
145 return nil, err
146 }
147 - root, err := mr.GetValue().GetNode()
147 + root, err := mr.GetDirectory().GetNode()
148 if err != nil {
149 return nil, err
150 }
@@ -199,7 +199,8 @@ func (adder *Adder) Finalize() (ipld.Node, error) {
199 if err != nil {
200 return nil, err
201 }
202 - root := mr.GetValue()
202 + var root mfs.FSNode
203 + root = mr.GetDirectory()
204
205 err = root.Flush()
206 if err != nil {
@@ -224,10 +225,7 @@ func (adder *Adder) Finalize() (ipld.Node, error) {
225 return nil, err
226 }
227
227 - dir, ok := mr.GetValue().(*mfs.Directory)
228 - if !ok {
229 - return nil, fmt.Errorf("root is not a directory")
230 - }
228 + dir := mr.GetDirectory()
229
230 root, err = dir.Child(name)
231 if err != nil {
fuse/ipns/ipns_unix.go
+1 -8
@@ -118,14 +118,7 @@ func loadRoot(ctx context.Context, rt *keyRoot, ipfs *core.IpfsNode, name string
118
119 rt.root = root
120
121 - switch val := root.GetValue().(type) {
122 - case *mfs.Directory:
123 - return &Directory{dir: val}, nil
124 - case *mfs.File:
125 - return &FileNode{fi: val}, nil
126 - default:
127 - return nil, errors.New("unrecognized type")
128 - }
121 + return &Directory{dir: root.GetDirectory()}, nil
122 }
123
124 type keyRoot struct {
mfs/mfs_test.go
+11 -11
@@ -213,7 +213,7 @@ func TestBasic(t *testing.T) {
213 defer cancel()
214 ds, rt := setupRoot(ctx, t)
215
216 - rootdir := rt.GetValue().(*Directory)
216 + rootdir := rt.GetDirectory()
217
218 // test making a basic dir
219 _, err := rootdir.Mkdir("a")
@@ -243,7 +243,7 @@ func TestMkdir(t *testing.T) {
243 defer cancel()
244 _, rt := setupRoot(ctx, t)
245
246 - rootdir := rt.GetValue().(*Directory)
246 + rootdir := rt.GetDirectory()
247
248 dirsToMake := []string{"a", "B", "foo", "bar", "cats", "fish"}
249 sort.Strings(dirsToMake) // sort for easy comparing later
@@ -281,7 +281,7 @@ func TestDirectoryLoadFromDag(t *testing.T) {
281 defer cancel()
282 ds, rt := setupRoot(ctx, t)
283
284 - rootdir := rt.GetValue().(*Directory)
284 + rootdir := rt.GetDirectory()
285
286 nd := getRandFile(t, ds, 1000)
287 err := ds.Add(ctx, nd)
@@ -373,7 +373,7 @@ func TestMfsFile(t *testing.T) {
373 defer cancel()
374 ds, rt := setupRoot(ctx, t)
375
376 - rootdir := rt.GetValue().(*Directory)
376 + rootdir := rt.GetDirectory()
377
378 fisize := 1000
379 nd := getRandFile(t, ds, 1000)
@@ -686,7 +686,7 @@ func actorReadFile(d *Directory) error {
686 }
687
688 func testActor(rt *Root, iterations int, errs chan error) {
689 - d := rt.GetValue().(*Directory)
689 + d := rt.GetDirectory()
690 for i := 0; i < iterations; i++ {
691 switch rand.Intn(5) {
692 case 0:
@@ -763,7 +763,7 @@ func TestConcurrentWriteAndFlush(t *testing.T) {
763 defer cancel()
764 ds, rt := setupRoot(ctx, t)
765
766 - d := mkdirP(t, rt.GetValue().(*Directory), "foo/bar/baz")
766 + d := mkdirP(t, rt.GetDirectory(), "foo/bar/baz")
767 fn := fileNodeFromReader(t, ds, bytes.NewBuffer(nil))
768 err := d.AddChild("file", fn)
769 if err != nil {
@@ -786,7 +786,7 @@ func TestConcurrentWriteAndFlush(t *testing.T) {
786 }()
787
788 for i := 0; i < nloops; i++ {
789 - _, err := rt.GetValue().GetNode()
789 + _, err := rt.GetDirectory().GetNode()
790 if err != nil {
791 t.Fatal(err)
792 }
@@ -800,7 +800,7 @@ func TestFlushing(t *testing.T) {
800 defer cancel()
801 _, rt := setupRoot(ctx, t)
802
803 - dir := rt.GetValue().(*Directory)
803 + dir := rt.GetDirectory()
804 c := mkdirP(t, dir, "a/b/c")
805 d := mkdirP(t, dir, "a/b/d")
806 e := mkdirP(t, dir, "a/b/e")
@@ -901,7 +901,7 @@ func TestConcurrentReads(t *testing.T) {
901
902 ds, rt := setupRoot(ctx, t)
903
904 - rootdir := rt.GetValue().(*Directory)
904 + rootdir := rt.GetDirectory()
905
906 path := "a/b/c"
907 d := mkdirP(t, rootdir, path)
@@ -976,7 +976,7 @@ func TestConcurrentWrites(t *testing.T) {
976
977 ds, rt := setupRoot(ctx, t)
978
979 - rootdir := rt.GetValue().(*Directory)
979 + rootdir := rt.GetDirectory()
980
981 path := "a/b/c"
982 d := mkdirP(t, rootdir, path)
@@ -1011,7 +1011,7 @@ func TestFileDescriptors(t *testing.T) {
1011 defer cancel()
1012
1013 ds, rt := setupRoot(ctx, t)
1014 - dir := rt.GetValue().(*Directory)
1014 + dir := rt.GetDirectory()
1015
1016 nd := dag.NodeWithData(ft.FilePBData(nil, 0))
1017 fi, err := NewFile("test", nd, dir, ds)
mfs/ops.go
+5 -7
@@ -1,7 +1,6 @@
1 package mfs
2
3 import (
4 - "errors"
4 "fmt"
5 "os"
6 gopath "path"
@@ -129,7 +128,7 @@ func Mkdir(r *Root, pth string, opts MkdirOpts) error {
128 return fmt.Errorf("cannot create directory '/': Already exists")
129 }
130
132 - cur := r.GetValue().(*Directory)
131 + cur := r.GetDirectory()
132 for i, d := range parts[:len(parts)-1] {
133 fsn, err := cur.Child(d)
134 if err == os.ErrNotExist && opts.Mkparents {
@@ -172,12 +171,11 @@ func Mkdir(r *Root, pth string, opts MkdirOpts) error {
171 return nil
172 }
173
174 +// Lookup extracts the root directory and performs a lookup under it.
175 +// TODO: Now that the root is always a directory, can this function
176 +// be collapsed with `DirLookup`? Or at least be made a method of `Root`?
177 func Lookup(r *Root, path string) (FSNode, error) {
176 - dir, ok := r.GetValue().(*Directory)
177 - if !ok {
178 - log.Errorf("root not a dir: %#v", r.GetValue())
179 - return nil, errors.New("root was not a directory")
180 - }
178 + dir := r.GetDirectory()
179
180 return DirLookup(dir, path)
181 }
mfs/system.go
+11 -18
@@ -53,8 +53,8 @@ type Root struct {
53 // node is the merkledag root.
54 node *dag.ProtoNode
55
56 - // val represents the node. It can either be a File or a Directory.
57 - val FSNode
56 + // Root directory of the MFS layout.
57 + dir *Directory
58
59 repub *Republisher
60
@@ -90,33 +90,29 @@ func NewRoot(parent context.Context, ds ipld.DAGService, node *dag.ProtoNode, pf
90
91 switch pbn.GetType() {
92 case ft.TDirectory, ft.THAMTShard:
93 - rval, err := NewDirectory(parent, node.String(), node, root, ds)
93 + newDir, err := NewDirectory(parent, node.String(), node, root, ds)
94 if err != nil {
95 return nil, err
96 }
97
98 - root.val = rval
98 + root.dir = newDir
99 case ft.TFile, ft.TMetadata, ft.TRaw:
100 - fi, err := NewFile(node.String(), node, root, ds)
101 - if err != nil {
102 - return nil, err
103 - }
104 - root.val = fi
100 + return nil, fmt.Errorf("root can't be a file (unixfs type: %s)", pbn.GetType())
101 default:
102 return nil, fmt.Errorf("unrecognized unixfs type: %s", pbn.GetType())
103 }
104 return root, nil
105 }
106
111 -// GetValue returns the value of Root.
112 -func (kr *Root) GetValue() FSNode {
113 - return kr.val
107 +// GetDirectory returns the root directory.
108 +func (kr *Root) GetDirectory() *Directory {
109 + return kr.dir
110 }
111
112 // Flush signals that an update has occurred since the last publish,
113 // and updates the Root republisher.
114 func (kr *Root) Flush() error {
119 - nd, err := kr.GetValue().GetNode()
115 + nd, err := kr.GetDirectory().GetNode()
116 if err != nil {
117 return err
118 }
@@ -136,10 +132,7 @@ func (kr *Root) Flush() error {
132 // A better implemented mfs system (one that does smarter internal caching and
133 // refcounting) shouldnt need this method.
134 func (kr *Root) FlushMemFree(ctx context.Context) error {
139 - dir, ok := kr.GetValue().(*Directory)
140 - if !ok {
141 - return fmt.Errorf("invalid mfs structure, root should be a directory")
142 - }
135 + dir := kr.GetDirectory()
136
137 if err := dir.Flush(); err != nil {
138 return err
@@ -172,7 +165,7 @@ func (kr *Root) closeChild(name string, nd ipld.Node, sync bool) error {
165 }
166
167 func (kr *Root) Close() error {
175 - nd, err := kr.GetValue().GetNode()
168 + nd, err := kr.GetDirectory().GetNode()
169 if err != nil {
170 return err
171 }