Skip to content

Commit 9e9c78d

Browse files
committed
Add support to client for full-tile fallback.
1 parent 7773276 commit 9e9c78d

File tree

1 file changed

+39
-5
lines changed

1 file changed

+39
-5
lines changed

client/client.go

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,13 +163,23 @@ func GetEntryBundle(ctx context.Context, f EntryBundleFetcherFunc, i, logSize ui
163163
span.SetAttributes(indexKey.Int64(otel.Clamp64(i)), logSizeKey.Int64(otel.Clamp64(logSize)))
164164

165165
bundle := api.EntryBundle{}
166-
sRaw, err := f(ctx, i, layout.PartialTileSize(0, i, logSize))
167-
if err != nil {
168-
if errors.Is(err, os.ErrNotExist) {
169-
return bundle, fmt.Errorf("leaf bundle at index %d not found: %v", i, err)
166+
p := layout.PartialTileSize(0, i, logSize)
167+
sRaw, err := f(ctx, i, p)
168+
switch {
169+
case errors.Is(err, os.ErrNotExist) && p == 0:
170+
return bundle, fmt.Errorf("full leaf bundle at index %d not found: %v", i, err)
171+
case errors.Is(err, os.ErrNotExist) && p > 0:
172+
// It could be that the partial bundle was removed as the tree has grown and a full bundle is now present, so try
173+
// falling back to that.
174+
sRaw, err = f(ctx, i, 0)
175+
if err != nil {
176+
return bundle, fmt.Errorf("partial bundle at %[1]d.p/%[2]d and full bundle at %[1]d both not found: %[3]w", i, p, err)
170177
}
178+
case err != nil:
171179
return bundle, fmt.Errorf("failed to fetch leaf bundle at index %d: %v", i, err)
180+
default:
172181
}
182+
173183
if err := bundle.UnmarshalText(sRaw); err != nil {
174184
return bundle, fmt.Errorf("failed to parse EntryBundle at index %d: %v", i, err)
175185
}
@@ -403,7 +413,8 @@ func (n *nodeCache) GetNode(ctx context.Context, id compact.NodeID) ([]byte, err
403413
t, ok := n.tiles[tKey]
404414
if !ok {
405415
span.AddEvent("cache miss")
406-
tileRaw, err := n.getTile(ctx, tileLevel, tileIndex, layout.PartialTileSize(tileLevel, tileIndex, n.logSize))
416+
p := layout.PartialTileSize(tileLevel, tileIndex, n.logSize)
417+
tileRaw, err := fetchPartialOrFullTile(ctx, n.getTile, tileLevel, tileIndex, p)
407418
if err != nil {
408419
return nil, fmt.Errorf("failed to fetch tile: %v", err)
409420
}
@@ -430,3 +441,26 @@ func (n *nodeCache) GetNode(ctx context.Context, id compact.NodeID) ([]byte, err
430441
}
431442
return r.GetRootHash(nil)
432443
}
444+
445+
// fetchPartialOrFullTile attempts to fetch the tile at the provided coordinates.
446+
// If no tile is found, and the coordinates refer to a partial tile, fallback to trying the corresponding
447+
// full tile.
448+
func fetchPartialOrFullTile(ctx context.Context, f TileFetcherFunc, l, i uint64, p uint8) ([]byte, error) {
449+
sRaw, err := f(ctx, l, i, p)
450+
switch {
451+
case errors.Is(err, os.ErrNotExist) && p == 0:
452+
return sRaw, fmt.Errorf("full tile at index %d not found: %w", i, err)
453+
case errors.Is(err, os.ErrNotExist) && p > 0:
454+
// It could be that the partial tile was removed as the tree has grown and a full tile is now present, so try
455+
// falling back to that.
456+
sRaw, err = f(ctx, l, i, 0)
457+
if err != nil {
458+
return sRaw, fmt.Errorf("partial tile at %[1]d/%[2]d.p/%[3]d and full bundle at %[1]d/%[2]d both not found: %[4]w", l, i, p, err)
459+
}
460+
return sRaw, nil
461+
case err != nil:
462+
return sRaw, fmt.Errorf("failed to fetch tile at %d/%d(.p/%d]): %v", l, i, p, err)
463+
default:
464+
return sRaw, nil
465+
}
466+
}

0 commit comments

Comments
 (0)