Skip to content

A continuation chunk placed on the head chunk's own page poisons the page the disjoint-slot merge was built for #6175

Description

@lvca

Found while working on #6163/#6154 (PR #6170), by reading the placement path rather than from a failure.

What happens

LocalBucket.writeMultiPageRecord places its first continuation chunk with:

final PageAnalysis pageAnalysis = findAvailableSpace(currentPage.pageId.getPageNumber(), spaceNeededForChunk, txPageCounter, true);

and findAvailableSpace starts with "PRIORITIZE SPACE IN THE SAME PAGE" - so the chunk is preferentially placed on the page that holds the record's HEAD chunk. When it lands there, the loop poisons that page:

if (poisonSlots)
  slotTx.poisonSlotRebasePage(fileId, nextPage.pageId.getPageNumber());

The head chunk's own page is exactly the page #6129 went to some trouble to keep mergeable: a chunked record's update is a single-slot write on it, and both updateRecordInternal and rebaseRecordOnPage carry dedicated machinery (SLOT_KIND_FIRST_CHUNK, chunkChainTailFingerprint, and since #6163 the region re-derivation) so that concurrent writers to other records on that page do not conflict. A continuation chunk landing there throws all of it away for that transaction, and the code already acknowledges it in passing ("including the head chunk's own page when the chain comes back to it").

When it is reachable

Not when the spilling record is the page's LAST one - the head chunk takes the whole free tail, so nothing else fits. It is reachable when the head chunk is in the MIDDLE of its page and the page still has tail: the chunk chain then prefers that tail over any other page.

That is the common shape for a bucket whose records are mostly small with a few large ones - which is also the shape where the merge matters most, because many unrelated records share the page.

Measurement first

Before changing anything, count it: on a workload of concurrent updates to a single-bucket type with a few chunked records, how many commits are poisoned by a continuation chunk landing on a head chunk's page (versus poisoned for other reasons, versus not poisoned)? #6129 was planned off exactly this kind of count (280/320 conflicts, all on page 0) and it changed the plan.

Possible fix

Pass a "do not choose this page" hint down to findAvailableSpace for the FIRST continuation chunk, the way multiPageRecord already suppresses slot 0. The locality argument for same-page placement is weak for a continuation chunk - the chain is walked by pointer, and the head chunk's page is already pinned and read - while the merge cost is concrete.

Worth checking the same question for updateMultiPageRecord's allocation loop, which has the identical call.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions