Skip to content

fix: preserve id type bits on update - #488

Open
Meowooh wants to merge 1 commit into
eloqdata:mainfrom
Meowooh:fix-update-index-validation
Open

fix: preserve id type bits on update#488
Meowooh wants to merge 1 commit into
eloqdata:mainfrom
Meowooh:fix-update-index-validation

Conversation

@Meowooh

@Meowooh Meowooh commented Aug 3, 2026

Copy link
Copy Markdown

What changed

  • Rebuild the _id KeyString in EloqRecordStore::updateRecord().
  • Store non-zero KeyString TypeBits in the new MongoRecord, matching the existing insert path.
  • Add a regression test covering primary and secondary index consistency after document updates.

Why

KeyString value bytes normalize equivalent numeric representations, while TypeBits preserve their exact BSON types, such as NumberLong, Double, Decimal, and negative zero.

The insert path stored the _id TypeBits in MongoRecord, but the update path replaced the record and wrote only the BSON payload. After an update, indexed queries could still return correct results because the physical index entries were maintained correctly. However, validate({full: true}) reconstructed the record identity without the original TypeBits and could report _id_ and every secondary index as invalid.

This change preserves the _id TypeBits during updates using the same encoding rule as inserts.

Testing

Added tests/jstests/eloq_basic/update_index_validation.js, covering:

  • NumberInt as the all-zero TypeBits control case
  • NumberLong
  • integral Double
  • Decimal
  • negative Double zero
  • Decimal zero with an exponent
  • embedded NumberLong
  • full validation after insert and update
  • _id_, unchanged secondary indexes, and updated secondary indexes
  • hinted queries for stale, updated, and unchanged keys
  • exact BSON types returned by returnKey()

Results:

  • Before the fix, the NumberLong case reproduced valid: false for _id_, stable_1, and value_1, while hinted queries still returned the correct results.
  • After the fix, update_index_validation.js passed: 1/1 tests.
  • update_affects_indexes.js and return_key.js also passed.
  • git diff --check passed.

Summary by CodeRabbit

  • Bug Fixes

    • Improved indexed document updates for records with different BSON _id types.
    • Preserved key metadata during updates to prevent stale or incorrect index entries.
    • Enhanced validation of index integrity after updating indexed fields.
  • Tests

    • Added coverage for numeric, zero, decimal, and embedded _id values.
    • Verified updated, unchanged, and removed index keys through full validation.

@CLAassistant

CLAassistant commented Aug 3, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The record update path now stores nonzero KeyString type bits derived from _id. A new JavaScript test validates indexed updates across multiple BSON _id types, including index integrity and exact BSON-key matching.

Changes

Record Update Type Bits

Layer / File(s) Summary
Persist KeyString type bits
src/mongo/db/modules/eloq/src/eloq_record_store.cpp
EloqRecordStore::updateRecord derives KeyString type bits from _id and stores nonzero bits in MongoRecord before writing the record.
Validate indexed updates
tests/jstests/eloq_basic/update_index_validation.js
The test covers multiple BSON _id types, collection and index validation, stale and replacement keys, unchanged indexes, and exact BSON-key equality.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Poem

I’m a rabbit with keys in my paws,
Checking each BSON type without flaws.
_id bits stay true,
Index checks run through,
And stale keys hop out of the gauze.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes preserving _id type bits during record updates, which is the main change.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/mongo/db/modules/eloq/src/eloq_record_store.cpp (1)

908-913: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Correct fix; matches the insert path.

The rebuilt idKeyString and the SetUnpackInfo() call correctly mirror the primary-index logic already used in _insertRecords (lines 1152-1155). This closes the gap where updates previously dropped _id type bits while inserts preserved them.

The same 3-line "extract non-zero type bits and call SetUnpackInfo" pattern now appears 4 times in this file (here, lines 955-957, 1153-1155, 1204-1206). Consider extracting a small helper to reduce duplication:

♻️ Optional helper extraction
+namespace {
+void setUnpackInfoFromTypeBits(Eloq::MongoRecord* record, const KeyString::TypeBits& typeBits) {
+    if (!typeBits.isAllZeros()) {
+        record->SetUnpackInfo(typeBits.getBuffer(), typeBits.getSize());
+    }
+}
+}  // namespace

Then each call site becomes, for example:

-    if (const auto& typeBits = idKeyString.getTypeBits(); !typeBits.isAllZeros()) {
-        mongoRecord->SetUnpackInfo(typeBits.getBuffer(), typeBits.getSize());
-    }
+    setUnpackInfoFromTypeBits(mongoRecord.get(), idKeyString.getTypeBits());
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mongo/db/modules/eloq/src/eloq_record_store.cpp` around lines 908 - 913,
Extract the repeated non-zero type-bits extraction and SetUnpackInfo logic into
a small shared helper, using the existing idKeyString/KeyString flow. Replace
the duplicated blocks in the current update path and the corresponding sites
near the other primary-index handling with calls to that helper, preserving the
behavior of skipping all-zero type bits.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/mongo/db/modules/eloq/src/eloq_record_store.cpp`:
- Around line 908-913: Extract the repeated non-zero type-bits extraction and
SetUnpackInfo logic into a small shared helper, using the existing
idKeyString/KeyString flow. Replace the duplicated blocks in the current update
path and the corresponding sites near the other primary-index handling with
calls to that helper, preserving the behavior of skipping all-zero type bits.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2222569c-7a6a-45c8-8c3d-6a97c340e6ab

📥 Commits

Reviewing files that changed from the base of the PR and between 4485b4b and c964fb8.

📒 Files selected for processing (2)
  • src/mongo/db/modules/eloq/src/eloq_record_store.cpp
  • tests/jstests/eloq_basic/update_index_validation.js

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