Skip to content

Commit fc9969c

Browse files
committed
perf: read each block once when deleting a document
1 parent 2ce522b commit fc9969c

3 files changed

Lines changed: 32 additions & 7 deletions

File tree

internal/db/collection_purge_conflict_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ func TestPurgeByDocIDsPruneHistoryReadsBlocksOutsideConflictSet(t *testing.T) {
8686
txn, err := db.NewTxn(false)
8787
require.NoError(t, err)
8888
tctx := InitContext(ctx, txn)
89-
_, _, err = getBlock(tctx, blockstore, blockCID)
89+
_, _, err = getBlock(tctx, blockstore, nil, blockCID)
9090
require.NoError(t, err)
9191
// badger only checks for conflicts when the transaction has a pending write; the real
9292
// purge deletes as it walks, so delete the block here too.

internal/db/collection_purge_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ func sharedFieldBlock(t *testing.T, ctx context.Context, db *DB, headA, headB ci
176176

177177
func requireBlockPresent(t *testing.T, ctx context.Context, bs datastore.Blockstore, blockCID cid.Cid, want bool) {
178178
t.Helper()
179-
_, found, err := getBlock(ctx, bs, blockCID)
179+
_, found, err := getBlock(ctx, bs, nil, blockCID)
180180
require.NoError(t, err)
181181
require.Equal(t, want, found)
182182
}

internal/db/collection_truncate.go

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -380,8 +380,10 @@ func (c *collection) hardDeleteDocumentBlocks(
380380
return err
381381
}
382382

383+
cache := blockCache{}
384+
383385
for _, key := range keysToDelete {
384-
err = c.deleteBlocks(ctx, systemstore, docID, key.Cid, prunedOwners)
386+
err = c.deleteBlocks(ctx, systemstore, docID, key.Cid, prunedOwners, cache)
385387
if err != nil {
386388
return NewErrTruncateDeleteBlocks(err, key.Cid.String())
387389
}
@@ -457,7 +459,7 @@ func (c *collection) hardDeleteCollectionBlocks(
457459
// the document blocks and their owner edges are deleted earlier in truncate (see the
458460
// hardDeleteDocKeysAndHeadstore pass), so the collection-commit DAG walked here only
459461
// re-encounters already-deleted document composites.
460-
err = c.deleteBlocks(ctx, nil, "", key.Cid, nil)
462+
err = c.deleteBlocks(ctx, nil, "", key.Cid, nil, nil)
461463
if err != nil {
462464
return NewErrTruncateDeleteBlocks(err, key.Cid.String())
463465
}
@@ -479,6 +481,12 @@ func (c *collection) hardDeleteCollectionBlocks(
479481
return nil
480482
}
481483

484+
// blockCache holds blocks already read while deleting one document, so a block reachable from more
485+
// than one of the document's headstore entries is read and decoded once rather than once per entry.
486+
// Blocks are content-addressed and immutable, so one read under any transaction is valid to follow
487+
// links from under another. A nil entry records a block that was not found; a nil cache disables it.
488+
type blockCache map[cid.Cid]*coreblock.Block
489+
482490
// deleteBlocks deletes the block of the given cid and all the blocks it links to, if
483491
// a block with this cid is found.
484492
//
@@ -489,6 +497,7 @@ func (c *collection) deleteBlocks(
489497
docID string,
490498
currentCid cid.Cid,
491499
prunedOwners map[string]struct{},
500+
cache blockCache,
492501
) error {
493502
blockstore := datastore.NewMultistore(c.db.rootstore, c.db.lockSet, c.db.blockStoreChunkSize).Blockstore()
494503

@@ -545,7 +554,7 @@ func (c *collection) deleteBlocks(
545554
block *coreblock.Block
546555
}
547556

548-
coreBlock, isFound, err := getBlock(readCtx, blockstore, currentCid)
557+
coreBlock, isFound, err := getBlock(readCtx, blockstore, cache, currentCid)
549558
if err != nil {
550559
return err
551560
}
@@ -591,7 +600,7 @@ func (c *collection) deleteBlocks(
591600
currentBlock := toDelete[i]
592601

593602
if currentBlock.block == nil {
594-
coreBlock, isFound, err := getBlock(readCtx, blockstore, currentBlock.id)
603+
coreBlock, isFound, err := getBlock(readCtx, blockstore, cache, currentBlock.id)
595604
if err != nil {
596605
return err
597606
}
@@ -653,7 +662,16 @@ func (c *collection) deleteBlocks(
653662
return nil
654663
}
655664

656-
func getBlock(ctx context.Context, blockstore datastore.Blockstore, id cid.Cid) (*coreblock.Block, bool, error) {
665+
func getBlock(
666+
ctx context.Context,
667+
blockstore datastore.Blockstore,
668+
cache blockCache,
669+
id cid.Cid,
670+
) (*coreblock.Block, bool, error) {
671+
if block, ok := cache[id]; ok {
672+
return block, block != nil, nil
673+
}
674+
657675
rawBlock, err := blockstore.Get(ctx, id)
658676
if errors.Is(err, ipld.ErrNotFound{}) {
659677
// We are looping through the links in a simple way that may result in us
@@ -662,6 +680,9 @@ func getBlock(ctx context.Context, blockstore datastore.Blockstore, id cid.Cid)
662680
// (another call to `deleteBlocks`).
663681
//
664682
// If we encounter such a block, we can skip over the error and continue.
683+
if cache != nil {
684+
cache[id] = nil
685+
}
665686
return nil, false, nil
666687
}
667688
if err != nil {
@@ -673,5 +694,9 @@ func getBlock(ctx context.Context, blockstore datastore.Blockstore, id cid.Cid)
673694
return nil, false, err
674695
}
675696

697+
if cache != nil {
698+
cache[id] = decodedBlock
699+
}
700+
676701
return decodedBlock, true, nil
677702
}

0 commit comments

Comments
 (0)