@cryptotaxi247 / kubo / commits / f679127d8

comments! and cleanup

Jeromy committed Mar 15, 2015 at 11:13 UTC f679127d835563a1dd29f787fc58a063314f88c6
4 files changed +70 -18
core/core.go
+6 -3
@@ -296,13 +296,16 @@ func (n *IpfsNode) teardown() error {
296 n.Repo,
297 }
298
299 - if n.Blocks != nil {
300 - closers = append(closers, n.Blocks)
301 - }
299 + // Filesystem needs to be closed before network, dht, and blockservice
300 + // so it can use them as its shutting down
301 if n.IpnsFs != nil {
302 closers = append(closers, n.IpnsFs)
303 }
304
305 + if n.Blocks != nil {
306 + closers = append(closers, n.Blocks)
307 + }
308 +
309 if n.Bootstrapper != nil {
310 closers = append(closers, n.Bootstrapper)
311 }
ipnsfs/dir.go
+2 -4
@@ -70,10 +70,8 @@ func (d *Directory) Open(tpath []string, mode int) (*File, error) {
70 return dir.Open(tpath[1:], mode)
71 }
72
73 -type childCloser interface {
74 - closeChild(string, *dag.Node) error
75 -}
76 -
73 +// closeChild updates the child by the given name to the dag node 'nd'
74 +// and changes its own dag node, then propogates the changes upward
75 func (d *Directory) closeChild(name string, nd *dag.Node) error {
76 _, err := d.fs.dserv.Add(nd)
77 if err != nil {
ipnsfs/file.go
+14
@@ -21,6 +21,7 @@ type File struct {
21 lock sync.Mutex
22 }
23
24 +// NewFile returns a NewFile object with the given parameters
25 func NewFile(name string, node *dag.Node, parent childCloser, fs *Filesystem) (*File, error) {
26 dmod, err := mod.NewDagModifier(context.Background(), node, fs.dserv, fs.pins.GetManual(), chunk.DefaultSplitter)
27 if err != nil {
@@ -35,6 +36,7 @@ func NewFile(name string, node *dag.Node, parent childCloser, fs *Filesystem) (*
36 }, nil
37 }
38
39 +// Write writes the given data to the file at its current offset
40 func (fi *File) Write(b []byte) (int, error) {
41 fi.Lock()
42 defer fi.Unlock()
@@ -42,12 +44,15 @@ func (fi *File) Write(b []byte) (int, error) {
44 return fi.mod.Write(b)
45 }
46
47 +// Read reads into the given buffer from the current offset
48 func (fi *File) Read(b []byte) (int, error) {
49 fi.Lock()
50 defer fi.Unlock()
51 return fi.mod.Read(b)
52 }
53
54 +// Close flushes, then propogates the modified dag node up the directory structure
55 +// and signals a republish to occur
56 func (fi *File) Close() error {
57 fi.Lock()
58 defer fi.Unlock()
@@ -75,18 +80,21 @@ func (fi *File) Close() error {
80 return nil
81 }
82
83 +// Flush flushes the changes in the file to disk
84 func (fi *File) Flush() error {
85 fi.Lock()
86 defer fi.Unlock()
87 return fi.mod.Flush()
88 }
89
90 +// Seek implements io.Seeker
91 func (fi *File) Seek(offset int64, whence int) (int64, error) {
92 fi.Lock()
93 defer fi.Unlock()
94 return fi.mod.Seek(offset, whence)
95 }
96
97 +// Write At writes the given bytes at the offset 'at'
98 func (fi *File) WriteAt(b []byte, at int64) (int, error) {
99 fi.Lock()
100 defer fi.Unlock()
@@ -94,18 +102,21 @@ func (fi *File) WriteAt(b []byte, at int64) (int, error) {
102 return fi.mod.WriteAt(b, at)
103 }
104
105 +// Size returns the size of this file
106 func (fi *File) Size() (int64, error) {
107 fi.Lock()
108 defer fi.Unlock()
109 return fi.mod.Size()
110 }
111
112 +// GetNode returns the dag node associated with this file
113 func (fi *File) GetNode() (*dag.Node, error) {
114 fi.Lock()
115 defer fi.Unlock()
116 return fi.mod.GetNode()
117 }
118
119 +// Truncate truncates the file to size
120 func (fi *File) Truncate(size int64) error {
121 fi.Lock()
122 defer fi.Unlock()
@@ -113,14 +124,17 @@ func (fi *File) Truncate(size int64) error {
124 return fi.mod.Truncate(size)
125 }
126
127 +// Type returns the type FSNode this is
128 func (fi *File) Type() NodeType {
129 return TFile
130 }
131
132 +// Lock the file
133 func (fi *File) Lock() {
134 fi.lock.Lock()
135 }
136
137 +// Unlock the file
138 func (fi *File) Unlock() {
139 fi.lock.Unlock()
140 }
ipnsfs/system.go
+48 -11
@@ -1,3 +1,13 @@
1 +// package ipnsfs implements an in memory model of a mutable ipns filesystem,
2 +// to be used by the fuse filesystem.
3 +//
4 +// It consists of four main structs:
5 +// 1) The Filesystem
6 +// The filesystem serves as a container and entry point for the ipns filesystem
7 +// 2) KeyRoots
8 +// KeyRoots represent the root of the keyspace controlled by a given keypair
9 +// 3) Directories
10 +// 4) Files
11 package ipnsfs
12
13 import (
@@ -5,6 +15,7 @@ import (
15 "fmt"
16 "os"
17 "strings"
18 + "sync"
19 "time"
20
21 dag "github.com/jbenet/go-ipfs/merkledag"
@@ -33,6 +44,7 @@ type Filesystem struct {
44 roots map[string]*KeyRoot
45 }
46
47 +// NewFilesystem instantiates an ipns filesystem using the given parameters and locally owned keys
48 func NewFilesystem(ctx context.Context, ds dag.DAGService, nsys namesys.NameSystem, pins pin.Pinner, keys ...ci.PrivKey) (*Filesystem, error) {
49 roots := make(map[string]*KeyRoot)
50 fs := &Filesystem{
@@ -47,7 +59,7 @@ func NewFilesystem(ctx context.Context, ds dag.DAGService, nsys namesys.NameSyst
59 return nil, err
60 }
61
50 - root, err := fs.NewKeyRoot(ctx, k)
62 + root, err := fs.newKeyRoot(ctx, k)
63 if err != nil {
64 return nil, err
65 }
@@ -57,6 +69,7 @@ func NewFilesystem(ctx context.Context, ds dag.DAGService, nsys namesys.NameSyst
69 return fs, nil
70 }
71
72 +// Open opens a file at the given path
73 func (fs *Filesystem) Open(tpath string, mode int) (*File, error) {
74 pathelem := strings.Split(tpath, "/")
75 r, ok := fs.roots[pathelem[0]]
@@ -68,15 +81,23 @@ func (fs *Filesystem) Open(tpath string, mode int) (*File, error) {
81 }
82
83 func (fs *Filesystem) Close() error {
84 + wg := sync.WaitGroup{}
85 for _, r := range fs.roots {
72 - err := r.Publish(context.TODO())
73 - if err != nil {
74 - return err
75 - }
86 + wg.Add(1)
87 + go func(r *KeyRoot) {
88 + defer wg.Done()
89 + err := r.Publish(context.TODO())
90 + if err != nil {
91 + log.Error(err)
92 + return
93 + }
94 + }(r)
95 }
96 + wg.Wait()
97 return nil
98 }
99
100 +// GetRoot returns the KeyRoot of the given name
101 func (fs *Filesystem) GetRoot(name string) (*KeyRoot, error) {
102 r, ok := fs.roots[name]
103 if ok {
@@ -85,6 +106,10 @@ func (fs *Filesystem) GetRoot(name string) (*KeyRoot, error) {
106 return nil, os.ErrNotExist
107 }
108
109 +type childCloser interface {
110 + closeChild(string, *dag.Node) error
111 +}
112 +
113 type NodeType int
114
115 const (
@@ -92,6 +117,7 @@ const (
117 TDir
118 )
119
120 +// FSNode represents any node (directory, root, or file) in the ipns filesystem
121 type FSNode interface {
122 GetNode() (*dag.Node, error)
123 Type() NodeType
@@ -115,7 +141,9 @@ type KeyRoot struct {
141 repub *Republisher
142 }
143
118 -func (fs *Filesystem) NewKeyRoot(parent context.Context, k ci.PrivKey) (*KeyRoot, error) {
144 +// newKeyRoot creates a new KeyRoot for the given key, and starts up a republisher routine
145 +// for it
146 +func (fs *Filesystem) newKeyRoot(parent context.Context, k ci.PrivKey) (*KeyRoot, error) {
147 hash, err := k.GetPublic().Hash()
148 if err != nil {
149 return nil, err
@@ -180,14 +208,14 @@ func (kr *KeyRoot) GetValue() FSNode {
208
209 func (kr *KeyRoot) Open(tpath []string, mode int) (*File, error) {
210 if kr.val == nil {
183 - // No entry here... what should we do?
184 - panic("nyi")
211 + // No entry here. KeyRoot was created incorrectly
212 + panic("nil keyroot.val, improperly constructed keyroot")
213 }
214 if len(tpath) > 0 {
215 // Make sure our root is a directory
216 dir, ok := kr.val.(*Directory)
217 if !ok {
190 - return nil, fmt.Errorf("no such file or directory: %s", tpath[0])
218 + return nil, os.ErrNotExist
219 }
220
221 return dir.Open(tpath, mode)
@@ -222,6 +250,7 @@ func (kr *KeyRoot) Publish(ctx context.Context) error {
250 return err
251 }
252
253 + // Holding this lock so our child doesnt change out from under us
254 child.Lock()
255 k, err := kr.fs.dserv.Add(nd)
256 if err != nil {
@@ -230,6 +259,8 @@ func (kr *KeyRoot) Publish(ctx context.Context) error {
259 }
260 child.Unlock()
261 // Dont want to hold the lock while we publish
262 + // otherwise we are holding the lock through a costly
263 + // network operation
264
265 fmt.Println("Publishing!")
266 return kr.fs.nsys.Publish(ctx, kr.key, k)
@@ -243,6 +274,8 @@ type Republisher struct {
274 root *KeyRoot
275 }
276
277 +// NewRepublisher creates a new Republisher object to republish the given keyroot
278 +// using the given short and long time intervals
279 func NewRepublisher(root *KeyRoot, tshort, tlong time.Duration) *Republisher {
280 return &Republisher{
281 TimeoutShort: tshort,
@@ -252,6 +285,9 @@ func NewRepublisher(root *KeyRoot, tshort, tlong time.Duration) *Republisher {
285 }
286 }
287
288 +// Touch signals that an update has occurred since the last publish.
289 +// Multiple consecutive touches may extend the time period before
290 +// the next Publish occurs in order to more efficiently batch updates
291 func (np *Republisher) Touch() {
292 select {
293 case np.Publish <- struct{}{}:
@@ -259,6 +295,7 @@ func (np *Republisher) Touch() {
295 }
296 }
297
298 +// Run is the main republisher loop
299 func (np *Republisher) Run(ctx context.Context) {
300 for {
301 select {
@@ -268,13 +305,13 @@ func (np *Republisher) Run(ctx context.Context) {
305
306 wait:
307 select {
271 - case <-quick:
272 - case <-longer:
308 case <-ctx.Done():
309 return
310 case <-np.Publish:
311 quick = time.After(np.TimeoutShort)
312 goto wait
313 + case <-quick:
314 + case <-longer:
315 }
316
317 log.Info("Publishing Changes!")