@@ -4,20 +4,41 @@ import (
4
4
"errors"
5
5
"strings"
6
6
7
+ ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
8
+ syncds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync"
7
9
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8
10
11
+ bstore "github.com/ipfs/go-ipfs/blocks/blockstore"
12
+ bserv "github.com/ipfs/go-ipfs/blockservice"
13
+ offline "github.com/ipfs/go-ipfs/exchange/offline"
9
14
dag "github.com/ipfs/go-ipfs/merkledag"
10
15
)
11
16
12
17
type Editor struct {
13
18
root * dag.Node
14
- ds dag.DAGService
19
+
20
+ // tmp is a temporary in memory (for now) dagstore for all of the
21
+ // intermediary nodes to be stored in
22
+ tmp dag.DAGService
23
+
24
+ // src is the dagstore with *all* of the data on it, it is used to pull
25
+ // nodes from for modification (nil is a valid value)
26
+ src dag.DAGService
27
+ }
28
+
29
+ func NewMemoryDagService () dag.DAGService {
30
+ // build mem-datastore for editor's intermediary nodes
31
+ bs := bstore .NewBlockstore (syncds .MutexWrap (ds .NewMapDatastore ()))
32
+ bsrv := bserv .New (bs , offline .Exchange (bs ))
33
+ return dag .NewDAGService (bsrv )
15
34
}
16
35
17
- func NewDagEditor (ds dag.DAGService , root * dag.Node ) * Editor {
36
+ // root is the node to be modified, source is the dagstore to pull nodes from (optional)
37
+ func NewDagEditor (root * dag.Node , source dag.DAGService ) * Editor {
18
38
return & Editor {
19
39
root : root ,
20
- ds : ds ,
40
+ tmp : NewMemoryDagService (),
41
+ src : source ,
21
42
}
22
43
}
23
44
@@ -26,7 +47,7 @@ func (e *Editor) GetNode() *dag.Node {
26
47
}
27
48
28
49
func (e * Editor ) GetDagService () dag.DAGService {
29
- return e .ds
50
+ return e .tmp
30
51
}
31
52
32
53
func addLink (ctx context.Context , ds dag.DAGService , root * dag.Node , childname string , childnd * dag.Node ) (* dag.Node , error ) {
@@ -40,6 +61,8 @@ func addLink(ctx context.Context, ds dag.DAGService, root *dag.Node, childname s
40
61
return nil , err
41
62
}
42
63
64
+ _ = ds .Remove (root )
65
+
43
66
// ensure no link with that name already exists
44
67
_ = root .RemoveNodeLink (childname ) // ignore error, only option is ErrNotFound
45
68
@@ -55,41 +78,51 @@ func addLink(ctx context.Context, ds dag.DAGService, root *dag.Node, childname s
55
78
56
79
func (e * Editor ) InsertNodeAtPath (ctx context.Context , path string , toinsert * dag.Node , create func () * dag.Node ) error {
57
80
splpath := strings .Split (path , "/" )
58
- nd , err := insertNodeAtPath (ctx , e . ds , e .root , splpath , toinsert , create )
81
+ nd , err := e . insertNodeAtPath (ctx , e .root , splpath , toinsert , create )
59
82
if err != nil {
60
83
return err
61
84
}
62
85
e .root = nd
63
86
return nil
64
87
}
65
88
66
- func insertNodeAtPath (ctx context.Context , ds dag. DAGService , root * dag.Node , path []string , toinsert * dag.Node , create func () * dag.Node ) (* dag.Node , error ) {
89
+ func ( e * Editor ) insertNodeAtPath (ctx context.Context , root * dag.Node , path []string , toinsert * dag.Node , create func () * dag.Node ) (* dag.Node , error ) {
67
90
if len (path ) == 1 {
68
- return addLink (ctx , ds , root , path [0 ], toinsert )
91
+ return addLink (ctx , e . tmp , root , path [0 ], toinsert )
69
92
}
70
93
71
- nd , err := root .GetLinkedNode (ctx , ds , path [0 ])
94
+ nd , err := root .GetLinkedNode (ctx , e . tmp , path [0 ])
72
95
if err != nil {
73
96
// if 'create' is true, we create directories on the way down as needed
74
- if err == dag .ErrNotFound && create != nil {
97
+ if err == dag .ErrLinkNotFound && create != nil {
75
98
nd = create ()
76
- } else {
99
+ err = nil // no longer an error case
100
+ } else if err == dag .ErrNotFound {
101
+ // try finding it in our source dagstore
102
+ nd , err = root .GetLinkedNode (ctx , e .src , path [0 ])
103
+ }
104
+
105
+ // if we receive an ErrNotFound, then our second 'GetLinkedNode' call
106
+ // also fails, we want to error out
107
+ if err != nil {
77
108
return nil , err
78
109
}
79
110
}
80
111
81
- ndprime , err := insertNodeAtPath (ctx , ds , nd , path [1 :], toinsert , create )
112
+ ndprime , err := e . insertNodeAtPath (ctx , nd , path [1 :], toinsert , create )
82
113
if err != nil {
83
114
return nil , err
84
115
}
85
116
117
+ _ = e .tmp .Remove (root )
118
+
86
119
_ = root .RemoveNodeLink (path [0 ])
87
120
err = root .AddNodeLinkClean (path [0 ], ndprime )
88
121
if err != nil {
89
122
return nil , err
90
123
}
91
124
92
- _ , err = ds .Add (root )
125
+ _ , err = e . tmp .Add (root )
93
126
if err != nil {
94
127
return nil , err
95
128
}
@@ -99,56 +132,65 @@ func insertNodeAtPath(ctx context.Context, ds dag.DAGService, root *dag.Node, pa
99
132
100
133
func (e * Editor ) RmLink (ctx context.Context , path string ) error {
101
134
splpath := strings .Split (path , "/" )
102
- nd , err := rmLink (ctx , e . ds , e .root , splpath )
135
+ nd , err := e . rmLink (ctx , e .root , splpath )
103
136
if err != nil {
104
137
return err
105
138
}
106
139
e .root = nd
107
140
return nil
108
141
}
109
142
110
- func rmLink (ctx context.Context , ds dag. DAGService , root * dag.Node , path []string ) (* dag.Node , error ) {
143
+ func ( e * Editor ) rmLink (ctx context.Context , root * dag.Node , path []string ) (* dag.Node , error ) {
111
144
if len (path ) == 1 {
112
145
// base case, remove node in question
113
146
err := root .RemoveNodeLink (path [0 ])
114
147
if err != nil {
115
148
return nil , err
116
149
}
117
150
118
- _ , err = ds .Add (root )
151
+ _ , err = e . tmp .Add (root )
119
152
if err != nil {
120
153
return nil , err
121
154
}
122
155
123
156
return root , nil
124
157
}
125
158
126
- nd , err := root .GetLinkedNode (ctx , ds , path [0 ])
159
+ // search for node in both tmp dagstore and source dagstore
160
+ nd , err := root .GetLinkedNode (ctx , e .tmp , path [0 ])
161
+ if err == dag .ErrNotFound {
162
+ nd , err = root .GetLinkedNode (ctx , e .src , path [0 ])
163
+ }
164
+
127
165
if err != nil {
128
166
return nil , err
129
167
}
130
168
131
- nnode , err := rmLink (ctx , ds , nd , path [1 :])
169
+ nnode , err := e . rmLink (ctx , nd , path [1 :])
132
170
if err != nil {
133
171
return nil , err
134
172
}
135
173
174
+ _ = e .tmp .Remove (root )
175
+
136
176
_ = root .RemoveNodeLink (path [0 ])
137
177
err = root .AddNodeLinkClean (path [0 ], nnode )
138
178
if err != nil {
139
179
return nil , err
140
180
}
141
181
142
- _ , err = ds .Add (root )
182
+ _ , err = e . tmp .Add (root )
143
183
if err != nil {
144
184
return nil , err
145
185
}
146
186
147
187
return root , nil
148
188
}
149
189
150
- func (e * Editor ) WriteOutputTo (ds dag.DAGService ) error {
151
- return copyDag (e .GetNode (), e .ds , ds )
190
+ func (e * Editor ) Finalize (ds dag.DAGService ) (* dag.Node , error ) {
191
+ nd := e .GetNode ()
192
+ err := copyDag (nd , e .tmp , ds )
193
+ return nd , err
152
194
}
153
195
154
196
func copyDag (nd * dag.Node , from , to dag.DAGService ) error {
0 commit comments