Skip to content

Add missing range conflict check between file ingestion and RefitLevel() #10988

Closed
hx235 wants to merge 4 commits intofacebook:mainfrom
hx235:range_conflict_checking_ingestion_refit
Closed

Add missing range conflict check between file ingestion and RefitLevel() #10988
hx235 wants to merge 4 commits intofacebook:mainfrom
hx235:range_conflict_checking_ingestion_refit

Conversation

@hx235
Copy link
Copy Markdown
Contributor

@hx235 hx235 commented Nov 25, 2022

Context:
File ingestion never checks whether the key range it acts on overlaps with an ongoing RefitLevel() (used in CompactRange() with change_level=true). That's because RefitLevel() doesn't register and make its key range known to file ingestion. Though it checks overlapping with other compactions by https://github.com/facebook/rocksdb/blob/7.8.fb/db/external_sst_file_ingestion_job.cc#L998.

RefitLevel() (used in CompactRange() with change_level=true) doesn't check whether the key range it acts on overlaps with an ongoing file ingestion. That's because file ingestion does not register and make its key range known to other compactions.

  • Note that non-refitlevel-compaction (e.g, manual compaction w/o RefitLevel() or general compaction) also does not check key range overlap with ongoing file ingestion for the same reason.
  • But it's fine. Credited to @cbi42's discovery, WaitForIngestFile was called by background and foreground compactions. They were introduced in 0f88160, 5c64fb6 and 87dfc1d.
  • Regardless, this PR registers file ingestion like a compaction is a general approach that will also add range conflict check between file ingestion and non-refitlevel-compaction, though it has not been the issue motivated this PR.

Above are bugs resulting in two bad consequences:

  • If file ingestion and RefitLevel() creates files in the same level, then range-overlapped files will be created at that level and caught as corruption by force_consistency_checks=true
  • If file ingestion and RefitLevel() creates file in different levels, then with one further compaction on the ingested file, it can result in two same keys both with seqno 0 in two different levels. Then with iterator's optimization that assumes no two same keys both with seqno 0, it will either break this assertion in debug build or, even worst, return value of this same key for the key after it, which is the wrong value to return, in release build.

Therefore we decide to introduce range conflict check for file ingestion and RefitLevel() inspired from the existing range conflict check among compactions.

Summary:

  • Treat file ingestion job and RefitLevel() as Compaction of new compaction reasons: CompactionReason::kExternalSstIngestion and CompactionReason::kRefitLevel and register/unregister them. File ingestion is treated as compaction from L0 to different levels and RefitLevel() as compaction from source level to target level.
  • Check for RangeOverlapWithCompaction with other ongoing compactions, RegisterCompaction() on this "compaction" before changing the LSM state in VersionStorageInfo, and UnregisterCompaction() after changing.
  • Replace scattered fixes (0f88160, 5c64fb6 and 87dfc1d.) that prevents overlapping between file ingestion and non-refit-level compaction with this fix cuz those practices are easy to overlook.
  • Misc: logic cleanup, see PR comments

Test:

  • New unit test DBCompactionTestWithOngoingFileIngestionParam* that failed pre-fix and passed afterwards.
  • Made compatible with existing tests, see PR comments
  • make check
  • [Ongoing] Stress test rehearsal with normal value and aggressive CI value [CI only]Aggressive crash test value #10761

@hx235 hx235 added WIP Work in progress and removed CLA Signed labels Nov 25, 2022
@hx235 hx235 changed the title [WIP]Check range conflict with other compaction during file ingestion and RefitLevel [WIP] Check range conflict with other compaction during file ingestion and RefitLevel Nov 25, 2022
@hx235 hx235 force-pushed the range_conflict_checking_ingestion_refit branch 3 times, most recently from 18b54d1 to f7e55d4 Compare November 25, 2022 19:48
@hx235 hx235 force-pushed the range_conflict_checking_ingestion_refit branch 2 times, most recently from ef1aa23 to 324994d Compare November 25, 2022 23:15
@hx235 hx235 changed the title [WIP] Check range conflict with other compaction during file ingestion and RefitLevel Range conflict check for file ingestion and RefitLevel() Nov 25, 2022
@hx235 hx235 changed the title Range conflict check for file ingestion and RefitLevel() Introduce range conflict check for file ingestion and RefitLevel() Nov 25, 2022
@hx235 hx235 force-pushed the range_conflict_checking_ingestion_refit branch from 324994d to 549d68d Compare November 25, 2022 23:27
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Note] Logic in IsBottommostLevel() does not consider cases like RefitLevel() and file ingestion. So I explicitly excluded them to avoid touching its logic.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's still correct to keep the original logic right? I'm fine with either way, just checking.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original logic is correct to keep - it's just that the bottommost concept is not applied to RefitLevel (where we can output to L0 when L0 is empty) nor file ingestion (where the input files do not exists in LSM prior to the "file-ingestion compaction). I also didn't want to relax the logic in IsBottommostLevel for RefitLevel or file ingestion cuz they are really here for conflict checking, not for anything else. Updated CompactionReason::kExternalSstIngestion/kRefitLevel comments.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Note] Due to some clean up in RefitLevel, this now returns OK. The result of this CompactRange() does not matter for this UT after inspection.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to figure out why it now returns OK here, it's due to the new conditional check where level is 8 and is empty:

if (vstorage->LevelFiles(level).empty()) {
    return Status::OK();
  }

it seems that we may incorrectly compute final_output_level:

if (output_level == ColumnFamilyData::kCompactToBaseLevel) {
final_output_level = cfd->NumberLevels() - 1;

when base level != last level, which in turn means that we may move the wrong files during RefitLevel().

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's due to the new conditional check where level is 8

Correct.

It seems that we may incorrectly compute final_output_level

Thanks! This is an accidental finding which I plan to address it in #11041. The test has been using the wrong final_output_level prior my PR anyway.

Copy link
Copy Markdown
Contributor Author

@hx235 hx235 Nov 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Note] This is a clean up decided to early return in empty source level case, to avoid below cfd->compaction_picker()->GetRange() called on empty input.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Note] With this PR, file ingestion results will depend on on-going compaction too. Disable auto ones so this test is remained untouched. Also auto-compaction is irrelevant to this test after inspection.

Comment on lines 232 to 235
Copy link
Copy Markdown
Contributor Author

@hx235 hx235 Nov 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Note] Wish I could have used std::unique_ptr<> for compaction_input_metdatas_ and file_ingesting_compactions_ and avoid explicit deletion in ~ExternalSstFileIngestionJob(). But this mysterious window failure https://app.circleci.com/pipelines/github/facebook/rocksdb/21691/workflows/80e4fb38-8369-4350-8e46-119878df1fb2/jobs/537236 stopped me from doing so.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Note] Same as above

Copy link
Copy Markdown
Contributor Author

@hx235 hx235 Nov 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Note] Similar to above, ingest file of overlapped ranges with ongoing compaction needs allow_global_seqno=true just like how it's needed for overlapping ranges with existing files. Same for below.

@hx235 hx235 force-pushed the range_conflict_checking_ingestion_refit branch from 549d68d to 55ffcd0 Compare November 25, 2022 23:54
@facebook-github-bot
Copy link
Copy Markdown
Contributor

@hx235 has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@hx235 hx235 requested a review from ajkr November 28, 2022 18:03
@hx235 hx235 requested a review from cbi42 December 6, 2022 01:15
@hx235 hx235 changed the title Introduce range conflict check for file ingestion and RefitLevel() Introduce range conflict check between file ingestion and RefitLevel() Dec 6, 2022
@hx235 hx235 changed the title Introduce range conflict check between file ingestion and RefitLevel() Introduce range conflict check for file ingestion and RefitLevel() Dec 6, 2022
@hx235 hx235 changed the title Introduce range conflict check for file ingestion and RefitLevel() Add missing range conflict check for file ingestion and RefitLevel() Dec 13, 2022
@hx235 hx235 force-pushed the range_conflict_checking_ingestion_refit branch from 55ffcd0 to 0f366ef Compare December 13, 2022 04:59
@facebook-github-bot
Copy link
Copy Markdown
Contributor

@hx235 has updated the pull request. You must reimport the pull request before landing.

@facebook-github-bot
Copy link
Copy Markdown
Contributor

@hx235 has updated the pull request. You must reimport the pull request before landing.

@facebook-github-bot
Copy link
Copy Markdown
Contributor

@hx235 has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

1 similar comment
@facebook-github-bot
Copy link
Copy Markdown
Contributor

@hx235 has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@hx235 hx235 force-pushed the range_conflict_checking_ingestion_refit branch from 8a4e1bf to 8f09fb2 Compare December 29, 2022 17:44
@facebook-github-bot
Copy link
Copy Markdown
Contributor

@hx235 has updated the pull request. You must reimport the pull request before landing.

@facebook-github-bot
Copy link
Copy Markdown
Contributor

@hx235 has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@hx235 hx235 force-pushed the range_conflict_checking_ingestion_refit branch from 8f09fb2 to 2aeda64 Compare December 29, 2022 20:34
@facebook-github-bot
Copy link
Copy Markdown
Contributor

@hx235 has updated the pull request. You must reimport the pull request before landing.

@facebook-github-bot
Copy link
Copy Markdown
Contributor

@hx235 has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@hx235 hx235 force-pushed the range_conflict_checking_ingestion_refit branch from 2aeda64 to ad53bce Compare December 29, 2022 21:43
@facebook-github-bot
Copy link
Copy Markdown
Contributor

@hx235 has updated the pull request. You must reimport the pull request before landing.

@facebook-github-bot
Copy link
Copy Markdown
Contributor

@hx235 has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@facebook-github-bot
Copy link
Copy Markdown
Contributor

@hx235 merged this pull request in 9502856.

facebook-github-bot pushed a commit that referenced this pull request Jan 5, 2023
Summary:
valgrind build for `ExternalSSTFileBasicTest/ExternalSSTFileBasicTest.IngestFileWithMixedValueType` and `ExternalSSTFileBasicTest/ExternalSSTFileBasicTest.IngestFileWithGlobalSeqnoPickedSeqno` started failing (see error message in T141554665). I could not repro but I suspect it is due to file ingestion range overlapping with ongoing compaction, which caused a new global seqno being assigned after #10988.

Pull Request resolved: #11070

Test Plan: monitor future valgrind tests result.

Reviewed By: hx235

Differential Revision: D42319056

Pulled By: cbi42

fbshipit-source-id: acbcd841a2a15e36b278f39ba514f4b9a6ee43ca
inikep added a commit to percona/rocksdb that referenced this pull request Feb 18, 2025
inikep added a commit to percona/rocksdb that referenced this pull request Feb 18, 2025
inikep added a commit to percona/rocksdb that referenced this pull request Feb 18, 2025
inikep added a commit to percona/rocksdb that referenced this pull request May 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants