Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(attachment_service): corrupted attachments.json when parallel requests #6450

Conversation

problame
Copy link
Contributor

The pagebench integration PR (#6214) issues attachment requests in parallel.
We observed corrupted attachments.json from time to time, especially in
the test cases with high tenant counts.

The atomic overwrite added in #6444 exposed the root cause cleanly:
the .commit() calls of two request handlers could interleave or
be reordered.
See also: #6444 (comment)

This PR makes changes to the persistence module to fix above race:

  • mpsc queue for PendingWrites
  • one writer task performs the writes in mpsc queue order
  • request handlers that need to do writes do it using the
    new mutating_transaction function.

mutating_transaction, while holding the lock, does the modifications,
serializes the post-modification state, and pushes that as a
PendingWrite into the mpsc queue.
It then release the lock and awaits the completion of the write.
The writer tasks executes the PendingWrites in queue order.
Once the write has been executed, it wakes the writing tokio task.

…uests

The pagebench integration PR (#6214) issues attachment requests in parallel.
We observed corrupted attachments.json from time to time, especially in
the test cases with high tenant counts.

The atomic overwrite added in #6444 exposed the root cause cleanly:
the `.commit()` calls of two request handlers could interleave or
be reordered.
See also: #6444 (comment)

This PR makes changes to the `persistence` module to fix above race:
- mpsc queue for PendingWrites
- one writer task performs the writes in mpsc queue order
- request handlers that need to do writes do it using the
  new `mutating_transaction` function.

`mutating_transaction`, while holding the lock, does the modifications,
serializes the post-modification state, and pushes that as a
`PendingWrite` into the mpsc queue.
It then release the lock and `await`s the completion of the write.
The writer tasks executes the `PendingWrites` in queue order.
Once the write has been executed, it wakes the writing tokio task.
Copy link

github-actions bot commented Jan 23, 2024

2280 tests run: 2191 passed, 0 failed, 89 skipped (full report)


Code coverage (full report)

  • functions: 54.6% (10651 of 19498 functions)
  • lines: 81.5% (60920 of 74716 lines)

The comment gets automatically updated with the latest test results
aeda8ba at 2024-01-23T18:54:43.850Z :recycle:

@problame problame requested a review from jcsp January 23, 2024 17:08
@problame problame marked this pull request as ready for review January 23, 2024 17:20
@problame problame requested review from a team as code owners January 23, 2024 17:20
@problame problame requested review from save-buffer and removed request for a team January 23, 2024 17:20
@problame problame enabled auto-merge (squash) January 23, 2024 18:55
@save-buffer
Copy link
Contributor

I don't have much context here so maybe this is a silly question, but won't this strongly reduce the amount of parallelism? Since we're serializing the requests through a channel and a mutex. Does that matter at all?

@problame problame merged commit 743f6df into main Jan 23, 2024
46 checks passed
@problame problame deleted the problame/benchmarking/attachment-service-concurrency-safe-persistence branch January 23, 2024 19:14
@problame
Copy link
Contributor Author

problame commented Jan 23, 2024

We'll replace the file persistence code with a proper database soon anyway in #6394, this is just to unblock me in #6214

jcsp added a commit that referenced this pull request Jan 23, 2024
abhigets pushed a commit that referenced this pull request Jan 24, 2024
…uests (#6450)

The pagebench integration PR (#6214) issues attachment requests in
parallel.
We observed corrupted attachments.json from time to time, especially in
the test cases with high tenant counts.

The atomic overwrite added in #6444 exposed the root cause cleanly:
the `.commit()` calls of two request handlers could interleave or
be reordered.
See also:
#6444 (comment)

This PR makes changes to the `persistence` module to fix above race:
- mpsc queue for PendingWrites
- one writer task performs the writes in mpsc queue order
- request handlers that need to do writes do it using the
  new `mutating_transaction` function.

`mutating_transaction`, while holding the lock, does the modifications,
serializes the post-modification state, and pushes that as a
`PendingWrite` into the mpsc queue.
It then release the lock and `await`s the completion of the write.
The writer tasks executes the `PendingWrites` in queue order.
Once the write has been executed, it wakes the writing tokio task.
jcsp added a commit that referenced this pull request Jan 24, 2024
jcsp added a commit that referenced this pull request Jan 24, 2024
jcsp added a commit that referenced this pull request Jan 25, 2024
jcsp added a commit that referenced this pull request Jan 26, 2024
jcsp added a commit that referenced this pull request Jan 26, 2024
## Problem

Spun off from #6394 -- this PR
is just the persistence parts and the changes that enable it to work
nicely


## Summary of changes

- Revert #6444 and #6450
- In neon_local, start a vanilla postgres instance for the attachment
service to use.
- Adopt `diesel` crate for database access in attachment service. This
uses raw SQL migrations as the source of truth for the schema, so it's a
soft dependency: we can switch libraries pretty easily.
- Rewrite persistence.rs to use postgres (via diesel) instead of JSON.
- Preserve JSON read+write at startup and shutdown: this enables using
the JSON format in compatibility tests, so that we don't have to commit
to our DB schema yet.
- In neon_local, run database creation + migrations before starting
attachment service
- Run the initial reconciliation in Service::spawn in the background, so
that the pageserver + attachment service don't get stuck waiting for
each other to start, when restarting both together in a test.
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants