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(layer): remove the need to repair internal state #7030

Merged
merged 63 commits into from
Mar 21, 2024

Conversation

koivunej
Copy link
Member

@koivunej koivunej commented Mar 6, 2024

Problem

The current implementation of struct Layer supports canceled read requests, but those will leave the internal state such that a following Layer::keep_resident call will need to repair the state. In pathological cases seen during generation numbers resetting in staging or with too many in-progress on-demand downloads, this repair activity will need to wait for the download to complete, which stalls disk usage-based eviction. Similar stalls have been observed in staging near disk-full situations, where downloads failed because the disk was full.

Fixes #6028 or the "layer is present on filesystem but not evictable" problems by:

  1. not canceling pending evictions by a canceled LayerInner::get_or_maybe_download
  2. completing post-download initialization of the LayerInner::inner from the download task

Not canceling evictions above case (1) and always initializing (2) lead to plain LayerInner::inner always having the up-to-date information, which leads to the old Layer::keep_resident never having to wait for downloads to complete. Finally, the Layer::keep_resident is replaced with Layer::is_likely_resident. These fix #7145.

Summary of changes

  • add a new test showing that a canceled get_or_maybe_download should not cancel the eviction
  • switch to using a watch internally rather than a broadcast to avoid hanging eviction while a download is ongoing
  • doc changes for new semantics and cleanup
  • fix Layer::keep_resident to use just self.0.inner.get() as truth as Layer::is_likely_resident
  • remove LayerInner::wanted_evicted boolean as no longer needed

Builds upon: #7185. Cc: #5331.

@koivunej koivunej force-pushed the joonas/layer-cancellation-safety branch from d95f733 to 42b37c4 Compare March 6, 2024 11:06
Copy link

github-actions bot commented Mar 6, 2024

2706 tests run: 2576 passed, 0 failed, 130 skipped (full report)


Flaky tests (3)

Postgres 15

  • test_vm_bit_clear_on_heap_lock: debug
  • test_wal_restore: release
  • test_wal_restore_initdb: release

Code coverage* (full report)

  • functions: 28.4% (7181 of 25277 functions)
  • lines: 47.1% (44154 of 93761 lines)

* collected from Rust tests only


The comment gets automatically updated with the latest test results
d265126 at 2024-03-20T23:57:57.268Z :recycle:

@koivunej
Copy link
Member Author

Rebased away the conflict, handled the #[cfg(test)] mess in failpoints.

koivunej added a commit that referenced this pull request Mar 15, 2024
Split off from #7030:
- each early exit is counted as canceled init, even though it most
likely was just `LayerInner::keep_resident` doing the no-download repair
check
- `downloaded_after` could had been accounted for multiple times, and
also when repairing to match on-disk state

Cc: #5331
koivunej added a commit that referenced this pull request Mar 15, 2024
Aiming for the design where `heavier_once_cell::OnceCell` is initialized
by a future factory lead to awkwardness with how
`LayerInner::get_or_maybe_download` looks right now with the `loop`. The
loop helps with two situations:

- an eviction has been scheduled but has not yet happened, and a read
access should cancel the eviction
- a previous `LayerInner::get_or_maybe_download` that canceled a pending
eviction was canceled leaving the `heavier_once_cell::OnceCell`
uninitialized but needing repair by the next
`LayerInner::get_or_maybe_download`

By instead supporting detached initialization in
`heavier_once_cell::OnceCell` via an `OnceCell::get_or_detached_init`,
we can fix what the monolithic #7030 does:
- spawned off download task initializes the
`heavier_once_cell::OnceCell` regardless of the download starter being
canceled
- a canceled `LayerInner::get_or_maybe_download` no longer stops
eviction but can win it if not canceled

Split off from #7030.

Cc: #5331
@koivunej koivunej force-pushed the joonas/layer-cancellation-safety branch 3 times, most recently from 16cdd9c to f2aec12 Compare March 19, 2024 10:56
@koivunej koivunej force-pushed the joonas/layer-cancellation-safety branch from f2aec12 to c1c92b0 Compare March 19, 2024 13:45
@koivunej koivunej changed the base branch from main to joonas/layer-always-init-on-download March 19, 2024 15:03
@koivunej koivunej force-pushed the joonas/layer-cancellation-safety branch from c1c92b0 to 23a9aae Compare March 20, 2024 11:40
@koivunej koivunej changed the title draft: layer enhancements fix(layer): make internal state need no repairs Mar 20, 2024
@koivunej koivunej changed the title fix(layer): make internal state need no repairs feat(layer): make internal state need no repairs Mar 20, 2024
@koivunej koivunej changed the base branch from joonas/layer-always-init-on-download to joonas/heavier-once-cell-small-fix March 20, 2024 13:21
koivunej added a commit that referenced this pull request Mar 20, 2024
Since #6115 with more often used get_value_reconstruct_data and friends,
we should not have needless INFO level span creation near hot paths. In
our prod configuration, INFO spans are always created, but in practice,
very rarely anything at INFO level is logged underneath.
`ResidentLayer::load_keys` is only used during compaction so it is not
that hot, but this aligns the access paths and their span usage.

PR changes the span level to debug to align with others, and adds the
layer name to the error which was missing.

Split off from #7030.
at best, it was always the same as the internal state in
LayerInner::inner. At worst, it added at least one possible bad state we
should care:

what if we get to the drop with a strong LayerInner reference but the
wanted_evicted was false? luckily we don't seem to have hit this case
ever.
it was added very early, but was never used.
revert it while keeping the log message -- do not mention the metrics.

because there is now a re-check against status being Evicted, this is no
longer expected.
introduced in #7175, and we focused on other things in the review.
@koivunej koivunej force-pushed the joonas/layer-cancellation-safety branch from befd60e to 76fee8c Compare March 20, 2024 22:46
@koivunej koivunej marked this pull request as ready for review March 20, 2024 22:46
@koivunej koivunej requested a review from a team as a code owner March 20, 2024 22:46
@koivunej koivunej requested a review from jcsp March 20, 2024 22:46
@koivunej koivunej changed the title feat(layer): make internal state need no repair fix(layer): make internal state need no repair Mar 20, 2024
@koivunej koivunej changed the title fix(layer): make internal state need no repair fix(layer): remove the need to repair internal state Mar 20, 2024
@koivunej koivunej merged commit 2206e14 into main Mar 21, 2024
53 checks passed
@koivunej koivunej deleted the joonas/layer-cancellation-safety branch March 21, 2024 01:19
koivunej added a commit that referenced this pull request Apr 18, 2024
#7030 introduced an annoying papercut, deeming a failure to acquire a
strong reference to `LayerInner` from `DownloadedLayer::drop` as a
canceled eviction. Most of the time, it wasn't that, but just timeline
deletion or tenant detach with the layer not wanting to be deleted or
evicted.

When a Layer is dropped as part of a normal shutdown, the `Layer` is
dropped first, and the `DownloadedLayer` the second. Because of this, we
cannot detect eviction being canceled from the `DownloadedLayer::drop`.
We can detect it from `LayerInner::drop`, which this PR adds.

Test case is added which before had 1 started eviction, 2 canceled. Now
it accurately finds 1 started, 1 canceled.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants