@@ -262,27 +262,39 @@ func (rw *RefWriter) writeRefsRecursive(n ipld.Node, depth int) (int, error) {
262
262
for i , ng := range ipld .GetDAG (rw .Ctx , rw .DAG , n ) {
263
263
lc := n .Links ()[i ].Cid
264
264
goDeeper , shouldWrite := rw .visit (lc , depth + 1 ) // The children are at depth+1
265
- if shouldWrite {
266
- if err := rw .WriteEdge (nc , lc , n .Links ()[i ].Name ); err != nil {
267
- return count , err
268
- }
269
- }
265
+ count ++
270
266
271
- if ! goDeeper {
267
+ // Avoid "Get()" on the node. We did a Get on it before
268
+ // (we printed it) and must not go deeper. This is an
269
+ // optimization for pruned branches.
270
+ if ! shouldWrite && ! goDeeper {
272
271
continue
273
272
}
274
273
274
+ // We must write it because it's new, or go deeper. In any case
275
+ // we need to make sure this node is fetched and stored.
275
276
nd , err := ng .Get (rw .Ctx )
276
277
if err != nil {
277
278
return count , err
278
279
}
279
280
280
- c , err := rw .writeRefsRecursive (nd , depth + 1 )
281
- count += c
282
- if err != nil {
283
- return count , err
281
+ // Output this node if we we should
282
+ if shouldWrite {
283
+ if err := rw .WriteEdge (nc , lc , n .Links ()[i ].Name ); err != nil {
284
+ return count , err
285
+ }
286
+ }
287
+
288
+ // Keep going deeper if we should
289
+ if goDeeper {
290
+ c , err := rw .writeRefsRecursive (nd , depth + 1 )
291
+ count += c
292
+ if err != nil {
293
+ return count , err
294
+ }
284
295
}
285
296
}
297
+
286
298
return count , nil
287
299
}
288
300
@@ -292,28 +304,45 @@ func (rw *RefWriter) writeRefsRecursive(n ipld.Node, depth int) (int, error) {
292
304
//
293
305
// visit will do branch pruning depending on rw.MaxDepth, previously visited
294
306
// cids and whether rw.Unique is set. i.e. rw.Unique = false and
295
- // rw.MaxDepth = 1 disables any pruning. But setting rw.Unique to true will
296
- // prune already visited branches.
307
+ // rw.MaxDepth = -1 disables any pruning. But setting rw.Unique to true will
308
+ // prune already visited branches at the cost of keeping as set of visited
309
+ // CIDs in memory.
297
310
func (rw * RefWriter ) visit (c * cid.Cid , depth int ) (bool , bool ) {
311
+ atMaxDepth := rw .MaxDepth >= 0 && depth == rw .MaxDepth
298
312
overMaxDepth := rw .MaxDepth >= 0 && depth > rw .MaxDepth
299
313
300
- // The two cases where we can shortcut right away are:
301
- // - When not unique: we print when not overMaxDepth and continue
302
- // in that case
303
- // - When overMaxDepth: we do not continue and do not print
304
- if ! rw .Unique || overMaxDepth {
305
- return ! overMaxDepth , ! overMaxDepth
314
+ // Shortcut when we are over max depth. In practice, this
315
+ // only applies when calling refs with --maxDepth=0, as root's
316
+ // children are already over max depth. Otherwise nothing should
317
+ // hit this.
318
+ if overMaxDepth {
319
+ return false , false
320
+ }
321
+
322
+ // We can shortcut right away if we don't need unique output:
323
+ // - we keep traversing when not atMaxDepth
324
+ // - always print
325
+ if ! rw .Unique {
326
+ return ! atMaxDepth , true
306
327
}
307
328
308
329
// Unique == true from this point.
309
330
// Thus, we keep track of seen Cids, and their depth.
310
331
if rw .seen == nil {
311
332
rw .seen = make (map [string ]int )
312
333
}
313
-
314
334
key := string (c .Bytes ())
315
335
oldDepth , ok := rw .seen [key ]
316
336
337
+ // We can shortcut when atMaxDepth:
338
+ // - do not keep traversing
339
+ // - print only if not seen before
340
+ if atMaxDepth {
341
+ return false , ! ok
342
+ }
343
+
344
+ // Unique == true && depth < MaxDepth (or unlimited) from this point
345
+
317
346
// Branch pruning cases:
318
347
// - We saw the Cid before and either:
319
348
// - Depth is unlimited (MaxDepth = -1)
0 commit comments