Skip to content

fix: break cold range metadata lock inversion - #575

Closed
Meowooh wants to merge 1 commit into
eloqdata:mainfrom
Meowooh:fix/cold-range-metadata-lock-inversion
Closed

Meowooh wants to merge 1 commit into
eloqdata:mainfrom
Meowooh:fix/cold-range-metadata-lock-inversion

Conversation

@Meowooh

@Meowooh Meowooh commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

结论

冷加载 range slices 时持有 fast-reader 再去申请 meta_data_mux_,与 fast writer(先拿 meta_data_mux_ 写锁、再等 per-shard fast reader 归零)构成闭环。修复方式是:在调用方已经持有的 metadata guard 内取 catalog/schema 快照,冷加载路径不再重新申请该锁。

故障现场

2026-10-08 08:28–08:45(UTC+8),三节点只读取证(/proc/<pid>/mem 的 O_RDONLY + pread,未 attach、未暂停进程;Build ID libtxservice.so=0f3cb26c…,libstorage_eloq_core.so=853d8fd6…)。.13 / PID 18246:

观察对象 值
meta_data_mux_.__cur_writer 18324
fast slot 0 / slot 1 0x80000000 / 0x80000001
TID 18325 futex wait meta_data_mux_ + 8(0x55dcc973c30)
冷加载 range 2701(range_slices_ == nullptr,owner 属于本 NG)

闭环两半:

  • TID 18324 / writer:持有 meta_data_mux_ 写锁 → FastMetaDataMutex::lock 在 0x4b8500–0x4b8507 循环等待低 31 位清零,即等待 shard 1 的 reader 退出。
  • TID 18325 / reader:PinRangeSlice 已持有 shard 1 fast-reader → 进入 FetchRangeSlices → GetSharedTableSchema → 申请 meta_data_mux_ 读锁。它拿不到,也就不会释放 fast-reader。

栈上的返回地址与部署指令逐条交叉验证过调用链(libtxservice.so+0x4bdfa0 → GetSharedTableSchema,+0x396c2c → FetchRangeSlices,libstorage_eloq_core.so+0x170243 → PinRangeSlice<MongoKey>);同一现场脚本重复采样输出 verdict: DEADLOCK_CONFIRMED。入口节点首次阻塞在 02:36:39,与 02:36:36 的 range 2926 在线 split 时间线完全对应。

修复

  1. 冷加载路径不再重新申请 meta_data_mux_。 LocalCcShards 新增私有 GetRangeCatalogSnapshotInternal:校验调用方真实持有的 fast/ordinary guard,在 guard 下读取 table_catalogs_,并在 CatalogEntry::s_mux_ 下复制 current/dirty schema。FetchRangeSlices / FetchTableRanges 改为接收这个 owning 快照并设为私有(…WithCatalogGuard);公开 wrapper 为 replay、Analyze、DataSync 等原本没有 guard 的调用方保留普通加锁路径。guard 覆盖注册与存储投递,投递后不再访问请求对象(inline SetFinish 会销毁它)。
  2. FetchRangeSlicesReq::SetFinish 不再查 catalog。 key cache 的 advisory 估算改用随请求携带的 admission 时刻 current schema——identity 选择本就基于它;回调里回查等于把同一个重入放回 inline 完成路径。
  3. 预算打满时的淘汰改为通知专用线程。 原先 inline 完成里直接调 KickoutRangeSlices(),它会再取 meta_data_mux_。现在只投递一个无指针、可合并的通知,由独立 eviction pthread 在自己的队列锁之外消费。该线程在容器、bucket、metrics、ranges heap 就绪之后启动,startup 期间的通知保持 pending,shutdown 在 shard 拆解前 join。它执行的就是普通 KickoutRangeSlices 逻辑;ranges-heap owner 保持 idle,因为它的 mimalloc 后备 TLD 与 scanner 分配共享,不能并发做 scratch 分配。

影响范围

PinRangeSlice / PinRangeSlices 的冷加载分支、FetchTableRanges 的冷加载分支、冷加载完成回调、以及内存打满时的淘汰触发路径。

测试

测试先空着。 本 PR 只包含修复与文档,回归测试由另一个 agent 验证后单独提交到本分支。
需要覆盖的交错:reader 已持有 fast guard → writer 已取 meta_data_mux_ 写锁并等待 reader 排空 → reader 再解析 schema/identity,要求两侧都有界完成;以及 inline 完成(成功 / ranges 预算打满通知)这条路径。仅仅照抄锁算法的 fixture 不算证据。

验证情况(截至提交时)

  • 已确认:修复后的代码在 -Wall -Wextra -Werror 下可编译(按测试夹具的编译边界抽取生产源码构建);同一夹具在修复前源码上复现了死锁(RUNTIME_TIMEOUT)。
  • 仍需验证:writer 持写锁等待 reader 排空与冷加载冷路径的交错(含 PinRangeSlices、inline 完成、预算打满通知);多节点真实集群上 range 2701 的锁环消失;淘汰线程的启停时序。
  • 诊断脚本对 .11 输出 NOT_OBSERVED,但那只是单点诊断探针,不等于集群健康,也不能作为验收依据。
  • pending split 队列的准入预算/反压是独立的内存稳健性改进,不能替代本锁序修复,本 PR 不含该改动。

诊断报告与取证细节按需补充。

@coderabbitai

coderabbitai Bot commented Oct 8, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 270 files, which is 170 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 53bf8a51-2a73-4408-be95-3cdfddf9fa82
📥 Commits

Reviewing files that changed from the base of the PR and between 6474664 and 237b9cd.

📒 Files selected for processing (270)
  • .gitmodules
  • CLAUDE.md
  • CMakeLists.txt
  • build_eloq_log_service.cmake
  • build_tx_service.cmake
  • cmake/EloqThirdParty.cmake
  • core/include/data_substrate.h
  • core/include/glog_error_logging.h
  • core/include/mongo_metrics.h
  • core/src/data_substrate.cpp
  • core/src/log_init.cpp
  • core/src/metrics_init.cpp
  • core/src/storage_init.cpp
  • core/src/tx_service_init.cpp
  • docs/01-architecture-overview.md
  • docs/02-threading-model.md
  • docs/03-concurrency-control.md
  • docs/04-transaction-execution.md
  • docs/05-data-model-and-catalog.md
  • docs/06-distribution-and-clustering.md
  • docs/07-durability-and-recovery.md
  • docs/08-range-and-bucket-management.md
  • docs/09-store-handler.md
  • docs/10-log-service.md
  • docs/11-rename-collection.md
  • docs/README.md
  • eloq_log_service/CMakeLists.txt
  • eloq_log_service/include/log_instance.h
  • eloq_log_service/include/log_service.h
  • eloq_log_service/include/log_shipping_agent.h
  • eloq_log_service/include/log_state.h
  • eloq_log_service/src/log_instance.cpp
  • eloq_log_service/src/log_state_memory_impl.cpp
  • eloq_log_service/src/log_state_rocksdb_cloud_impl.cpp
  • eloq_log_service/src/log_state_rocksdb_impl.cpp
  • store_handler/catalog_visibility.h
  • store_handler/data_store_leader_admission.h
  • store_handler/data_store_service_client.cpp
  • store_handler/data_store_service_client.h
  • store_handler/data_store_service_client_closure.cpp
  • store_handler/data_store_service_client_closure.h
  • store_handler/data_store_service_completion.h
  • store_handler/data_store_service_scanner.cpp
  • store_handler/data_store_service_scanner.h
  • store_handler/eloq_data_store_service/CMakeLists.txt
  • store_handler/eloq_data_store_service/data_store_factory.h
  • store_handler/eloq_data_store_service/data_store_service.cpp
  • store_handler/eloq_data_store_service/data_store_service.h
  • store_handler/eloq_data_store_service/data_store_service_config.cpp
  • store_handler/eloq_data_store_service/data_store_service_config.h
  • store_handler/eloq_data_store_service/data_store_service_util.h
  • store_handler/eloq_data_store_service/ds_request.proto
  • store_handler/eloq_data_store_service/eloq_store_data_store_factory.h
  • store_handler/eloq_data_store_service/eloq_value_codec.h
  • store_handler/eloq_data_store_service/internal_request.h
  • store_handler/eloq_data_store_service/main.cpp
  • store_handler/eloq_data_store_service/rocksdb_cloud_data_store_factory.h
  • store_handler/eloq_data_store_service/rocksdb_config.cpp
  • store_handler/eloq_data_store_service/rocksdb_data_store_common.cpp
  • store_handler/eloq_data_store_service/rocksdb_data_store_common.h
  • store_handler/eloq_data_store_service/rocksdb_data_store_factory.h
  • store_handler/eloq_data_store_service/tests/dss_completion_lifetime_test.cpp
  • store_handler/eloq_data_store_service/tests/dss_shard_lifecycle_test.cpp
  • store_handler/eloq_data_store_service/tests/dss_slice_completion_test.cpp
  • store_handler/eloq_data_store_service/tests/scoped_allocation_failure.cpp
  • store_handler/eloq_data_store_service/tests/scoped_allocation_failure.h
  • store_handler/eloq_data_store_service/tests/tikv_archive_cleanup_watermark_test.cpp
  • store_handler/eloq_data_store_service/tests/tikv_archive_retention_cleanup_test.cpp
  • store_handler/eloq_data_store_service/tests/tikv_backend_smoke_test.cpp
  • store_handler/eloq_data_store_service/tests/tikv_error_test.cpp
  • store_handler/eloq_data_store_service/tests/tikv_expired_ttl_cleanup_test.cpp
  • store_handler/eloq_data_store_service/tests/tikv_kv_metrics_test.cpp
  • store_handler/eloq_data_store_service/tests/tikv_namespace_admin_test.cpp
  • store_handler/eloq_data_store_service/tests/tikv_retired_tombstone_cleanup_test.cpp
  • store_handler/eloq_data_store_service/tests/tikv_value_codec_test.cpp
  • store_handler/eloq_data_store_service/tikv_archive_cleanup_watermark.h
  • store_handler/eloq_data_store_service/tikv_archive_retention_cleanup.h
  • store_handler/eloq_data_store_service/tikv_config.cpp
  • store_handler/eloq_data_store_service/tikv_config.h
  • store_handler/eloq_data_store_service/tikv_data_store.cpp
  • store_handler/eloq_data_store_service/tikv_data_store.h
  • store_handler/eloq_data_store_service/tikv_data_store_factory.h
  • store_handler/eloq_data_store_service/tikv_error.h
  • store_handler/eloq_data_store_service/tikv_expired_ttl_cleanup.h
  • store_handler/eloq_data_store_service/tikv_key_codec.cpp
  • store_handler/eloq_data_store_service/tikv_key_codec.h
  • store_handler/eloq_data_store_service/tikv_kv_client.cpp
  • store_handler/eloq_data_store_service/tikv_kv_client.h
  • store_handler/eloq_data_store_service/tikv_kv_metrics.h
  • store_handler/eloq_data_store_service/tikv_namespace_admin.cpp
  • store_handler/eloq_data_store_service/tikv_namespace_admin.h
  • store_handler/eloq_data_store_service/tikv_namespace_cleanup.cpp
  • store_handler/eloq_data_store_service/tikv_retired_tombstone_cleanup.h
  • store_handler/kv_store.h
  • store_handler/rocksdb_handler.cpp
  • store_handler/rocksdb_handler.h
  • tx_service/CMakeLists.txt
  • tx_service/abseil-cpp
  • tx_service/include/catalog_factory.h
  • tx_service/include/catalog_key_record.h
  • tx_service/include/cc/catalog_cc_map.h
  • tx_service/include/cc/catalog_schema_selector.h
  • tx_service/include/cc/cc_entry.h
  • tx_service/include/cc/cc_handler.h
  • tx_service/include/cc/cc_handler_result.h
  • tx_service/include/cc/cc_map.h
  • tx_service/include/cc/cc_page_clean_guard.h
  • tx_service/include/cc/cc_req_base.h
  • tx_service/include/cc/cc_req_misc.h
  • tx_service/include/cc/cc_request.h
  • tx_service/include/cc/cc_shard.h
  • tx_service/include/cc/cluster_config_cc_map.h
  • tx_service/include/cc/local_cc_handler.h
  • tx_service/include/cc/local_cc_shards.h
  • tx_service/include/cc/non_blocking_lock.h
  • tx_service/include/cc/object_cc_map.h
  • tx_service/include/cc/range_bucket_cc_map.h
  • tx_service/include/cc/range_cc_map.h
  • tx_service/include/cc/range_slice.h
  • tx_service/include/cc/reader_writer_cntl.h
  • tx_service/include/cc/template_cc_map.h
  • tx_service/include/checkpointer.h
  • tx_service/include/cluster_config_record.h
  • tx_service/include/concurrent_queue_wsize.h
  • tx_service/include/data_sync_task.h
  • tx_service/include/dss_metadata_route.h
  • tx_service/include/eloq_log_wrapper.h
  • tx_service/include/eloq_string_key_record.h
  • tx_service/include/error_messages.h
  • tx_service/include/fault/cc_node.h
  • tx_service/include/fault/log_replay_service.h
  • tx_service/include/fault/recovery_watchdog_timer.h
  • tx_service/include/index_build_config.h
  • tx_service/include/lifecycle_identity.h
  • tx_service/include/namespace_lock.h
  • tx_service/include/namespace_terminal_release.h
  • tx_service/include/native_node_group_readiness.h
  • tx_service/include/node_group_id_allocator.h
  • tx_service/include/physical_metadata_identity.h
  • tx_service/include/proto/cc_request.proto
  • tx_service/include/range_bucket_key_record.h
  • tx_service/include/range_record.h
  • tx_service/include/read_write_set.h
  • tx_service/include/remote/cc_node_service.h
  • tx_service/include/remote/namespace_admission.h
  • tx_service/include/remote/remote_cc_handler.h
  • tx_service/include/rename_post_write.h
  • tx_service/include/rename_publication.h
  • tx_service/include/rename_rekey.h
  • tx_service/include/rpc_closure.h
  • tx_service/include/schema.h
  • tx_service/include/sequences/sequences.h
  • tx_service/include/sharder.h
  • tx_service/include/sk_generator.h
  • tx_service/include/statistics.h
  • tx_service/include/store/data_store_handler.h
  • tx_service/include/system_handler.h
  • tx_service/include/table_statistics.h
  • tx_service/include/tx_execution.h
  • tx_service/include/tx_index_operation.h
  • tx_service/include/tx_key.h
  • tx_service/include/tx_operation.h
  • tx_service/include/tx_operation_result.h
  • tx_service/include/tx_request.h
  • tx_service/include/tx_service.h
  • tx_service/include/tx_service_metrics.h
  • tx_service/include/tx_util.h
  • tx_service/include/tx_worker_pool.h
  • tx_service/include/txlog.h
  • tx_service/include/type.h
  • tx_service/include/util.h
  • tx_service/raft_host_manager/include/host_manager_signal_policy.h
  • tx_service/raft_host_manager/include/leader_generation.h
  • tx_service/raft_host_manager/include/leader_notification_policy.h
  • tx_service/raft_host_manager/include/raft_host_manager.h
  • tx_service/raft_host_manager/src/main.cpp
  • tx_service/raft_host_manager/src/raft_host_manager.cpp
  • tx_service/raft_host_manager/src/raft_host_manager_service.cpp
  • tx_service/src/catalog_key_record.cpp
  • tx_service/src/cc/cc_handler_result.cpp
  • tx_service/src/cc/cc_map.cpp
  • tx_service/src/cc/cc_req_misc.cpp
  • tx_service/src/cc/cc_request.cpp
  • tx_service/src/cc/cc_shard.cpp
  • tx_service/src/cc/local_cc_handler.cpp
  • tx_service/src/cc/local_cc_shards.cpp
  • tx_service/src/cc/non_blocking_lock.cpp
  • tx_service/src/cc/range_slice.cpp
  • tx_service/src/cc/reader_writer_cntl.cpp
  • tx_service/src/checkpointer.cpp
  • tx_service/src/data_sync_task.cpp
  • tx_service/src/eloq_basic_catalog_factory.cpp
  • tx_service/src/fault/cc_node.cpp
  • tx_service/src/fault/fault_inject.cpp
  • tx_service/src/fault/log_replay_service.cpp
  • tx_service/src/native_node_group_readiness.cpp
  • tx_service/src/range_record.cpp
  • tx_service/src/remote/cc_node_service.cpp
  • tx_service/src/remote/cc_stream_receiver.cpp
  • tx_service/src/remote/cc_stream_sender.cpp
  • tx_service/src/remote/remote_cc_handler.cpp
  • tx_service/src/remote/remote_cc_request.cpp
  • tx_service/src/sequences/sequences.cpp
  • tx_service/src/sharder.cpp
  • tx_service/src/sk_generator.cpp
  • tx_service/src/store/snapshot_manager.cpp
  • tx_service/src/tx_execution.cpp
  • tx_service/src/tx_index_operation.cpp
  • tx_service/src/tx_operation.cpp
  • tx_service/src/tx_trace.cpp
  • tx_service/src/tx_worker_pool.cpp
  • tx_service/tests/BatchReadRetry-Test.cpp
  • tx_service/tests/CMakeLists.txt
  • tx_service/tests/CatalogKeyDecode-Test.cpp
  • tx_service/tests/CatalogRecordDecode-Test.cpp
  • tx_service/tests/CatalogRenameOwnership-Test.cpp
  • tx_service/tests/CatalogSchemaSelector-Test.cpp
  • tx_service/tests/CcPage-Test.cpp
  • tx_service/tests/ClusterCrossNg-Test.cpp
  • tx_service/tests/DataStoreLeaderAdmission-Test.cpp
  • tx_service/tests/DataStorePreparedTopology-Test.cpp
  • tx_service/tests/DataStoreRoute-Test.cpp
  • tx_service/tests/DataSubstrateLifecycle-Test.cpp
  • tx_service/tests/DataSyncMigrationTarget-Test.cpp
  • tx_service/tests/DssMetadataRoute-Test.cpp
  • tx_service/tests/HostManagerSignalPolicy-Test.cpp
  • tx_service/tests/IndexBuildConfig-Test.cpp
  • tx_service/tests/IndexPrepareRanges-Test.cpp
  • tx_service/tests/LargeObjLRU-Test.cpp
  • tx_service/tests/LeaderGeneration-Test.cpp
  • tx_service/tests/LeaderNotificationPolicy-Test.cpp
  • tx_service/tests/LifecycleIdentity-Test.cpp
  • tx_service/tests/LogStateRenameSchemaReplay-Test.cpp
  • tx_service/tests/LogStateSnapshotRecovery-Test.cpp
  • tx_service/tests/MemDataStore-Test.cpp
  • tx_service/tests/NamespaceLock-Test.cpp
  • tx_service/tests/NativeNodeGroupReadiness-Test.cpp
  • tx_service/tests/NodeGroupIdAllocator-Test.cpp
  • tx_service/tests/NonBlockingLock-Test.cpp
  • tx_service/tests/PhysicalMetadataIdentity-Test.cpp
  • tx_service/tests/QueueFailure-Test.cpp
  • tx_service/tests/RangeBucketRoutePublication-Test.cpp
  • tx_service/tests/RangeScanMemory-Test.cpp
  • tx_service/tests/ReaderWriterCntl-Test.cpp
  • tx_service/tests/RecoveryControl-Test.cpp
  • tx_service/tests/RenamePublication-Test.cpp
  • tx_service/tests/SchemaRenameIntent-Test.cpp
  • tx_service/tests/StrictCheckpointRouting-Test.cpp
  • tx_service/tests/TxWorkerPool-Test.cpp
  • tx_service/tests/checkpoint_completion/README.md
  • tx_service/tests/checkpoint_completion/compile_production.py
  • tx_service/tests/checkpoint_completion/completion_test.cpp
  • tx_service/tests/checkpoint_completion_test.py
  • tx_service/tests/cluster/scripted_host_manager.cpp
  • tx_service/tests/cluster/scripted_host_manager.h
  • tx_service/tests/cluster/test_cluster.cpp
  • tx_service/tests/cluster/test_cluster.h
  • tx_service/tests/cluster/txnode_main.cpp
  • tx_service/tests/harness/test_node.cpp
  • tx_service/tests/include/mock/mock_catalog_factory.h
  • tx_service/tests/include/mock/mock_log_agent.h
  • tx_service/tests/index_upload_progress/README.md
  • tx_service/tests/index_upload_progress/closure_test.cpp
  • tx_service/tests/index_upload_progress/worker_test.cpp
  • tx_service/tests/index_upload_progress_test.py
  • tx_service/tests/leader_refresh_integration_test.cpp
  • tx_service/tx-log-protos/log.proto
  • tx_service/tx-log-protos/log_agent.cpp
  • tx_service/tx-log-protos/log_agent.h
  • tx_service/tx-log-protos/rename_recovery_identity.h

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@Meowooh

Meowooh commented Oct 8, 2026

Copy link
Copy Markdown
Contributor Author

Closing: this branch is based on the internal pingkai-master lineage. The PR will be opened against the internal repository instead.

@Meowooh Meowooh closed this Oct 8, 2026
@Meowooh
Meowooh deleted the fix/cold-range-metadata-lock-inversion branch October 8, 2026 06:25
The change previously proposed in this branch is being submitted to our
internal repository instead. This branch intentionally contains no code.
@Meowooh Meowooh reopened this Oct 8, 2026
@Meowooh
Meowooh force-pushed the fix/cold-range-metadata-lock-inversion branch from 237b9cd to 22ecc07 Compare October 8, 2026 15:27
@Meowooh Meowooh closed this Oct 8, 2026
liangjchen added a commit that referenced this pull request Oct 19, 2026
Follow EloqKV #575 and use the RustFS binary already installed in the
shared ubuntu-dev image. Remove the MinIO source build and cache, check
for RustFS before compiling, and use its readiness endpoint. Preserve
failure status and logs while stopping the server and removing its
private temporary data on exit.

Verified the published amd64/arm64 image manifests and the image-pinned
amd64 RustFS checksum. The exact workflow cloud test passed locally:
1 case and 11 assertions. Missing-binary and injected-exit-7 cleanup
checks passed, as did actionlint, YAML, shell syntax, and whitespace.
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.

1 participant