Skip to content

feat(store): implement pluggable cloud storage for HStore - #3081

Open
vaijosh wants to merge 47 commits into
apache:masterfrom
vaijosh:Hstore+CloudStorage
Open

vaijosh wants to merge 47 commits into
apache:masterfrom
vaijosh:Hstore+CloudStorage

Conversation

@vaijosh

@vaijosh vaijosh commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Purpose

This PR introduces a cloud storage architecture for HugeGraph Store (HStore). In cloud-native environments, storage nodes are ephemeral, making reliance on local disk storage a single point of failure. This implementation decouples the storage layer from local disk dependencies, allowing SST files to be offloaded to durable, scalable cloud storage providers.

Key Changes

Pluggable Architecture

  • Created the CloudStorageProvider SPI interface to enable extensible storage backends.
  • Added CloudStorageProviderFactory for seamless provider discovery and lifecycle management.

S3 Provider Implementation

  • Introduced the hg-store-cloud-s3 module, leveraging AWS SDK v2 for production-ready S3/S3 compatible storage interaction.

Lifecycle & Event Integration

  • Integrated CloudStorageEventListener with RocksDBFactory. This hooks into critical SST lifecycle events (onTableFileCreated, onTableFileDeleted) to ensure synchronized state between local RocksDB and cloud storage.
  • Implemented startup hydration (onDBCreated) to backfill pre-existing files and read-miss on-demand hydration to ensure data availability.

Infrastructure & Testing

  • Added a comprehensive local development environment via docker/cloud-storage/ using MinIO.
  • Included an integration test script (test-graph-queries-and-sst.sh) to verify end-to-end data durability and query consistency.

Implementation Highlights

  • SPI Integration: Standardized service discovery via META-INF/services.
  • RocksDB Hooking: Registered a singleton RocksdbEventListener within RocksDBFactory to intercept file operations without modifying core RocksDB logic.
  • Read-Miss Protection: Added a guard window mechanism in onReadMiss to prevent redundant hydration requests during high-concurrency read scenarios.

Verifying These Changes

  • Unit Tests: Coverage for config parsing (CloudStorageConfigTest), factory registration, and event listener logic.
  • Integration Tests: Verified using the new docker-compose setup with MinIO.
  • Configuration: Verified application.yml bindings for credentials, bucket management, and sync intervals.

Impact

  • Dependencies: Added AWS SDK v2; updated LICENSE and NOTICE accordingly.
  • Configurations: Added cloud.storage namespace to application.yml (disabled by default).
  • Public API: No breaking changes to existing public-facing client APIs.

Documentation

  • Architecture and configuration details are documented in hugegraph-store/docs/pluggable-cloud-storage-architecture.md.

@vaijosh
vaijosh marked this pull request as ready for review July 6, 2026 14:11
@dosubot dosubot Bot added size:XXL This PR changes 1000+ lines, ignoring generated files. feature New feature store Store module labels Jul 6, 2026
vaijosh added a commit to vaijosh/hugegraph that referenced this pull request Jul 8, 2026
apache#3081
-added multipart upload for the S3 storage provider
@vaijosh
vaijosh force-pushed the Hstore+CloudStorage branch from 6a3f496 to 8b6d597 Compare July 8, 2026 10:29
apache#3081
-added multipart upload for the S3 storage provider
@vaijosh
vaijosh force-pushed the Hstore+CloudStorage branch from 8b6d597 to 4275426 Compare July 8, 2026 10:59
@codecov

codecov Bot commented Jul 8, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 70.54054% with 109 lines in your changes missing coverage. Please review.
✅ Project coverage is 41.66%. Comparing base (2f827d6) to head (1cf07b0).

Files with missing lines Patch % Lines
...pache/hugegraph/rocksdb/access/RocksDBFactory.java 56.75% 69 Missing and 11 partials ⚠️
...pache/hugegraph/rocksdb/access/RocksDBSession.java 67.12% 19 Missing and 5 partials ⚠️
...he/hugegraph/store/metric/SystemMetricService.java 0.00% 3 Missing ⚠️
...ache/hugegraph/store/cloud/CloudStorageConfig.java 92.85% 0 Missing and 1 partial ⚠️
.../hugegraph/rocksdb/access/SessionOperatorImpl.java 92.85% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #3081      +/-   ##
============================================
+ Coverage     41.40%   41.66%   +0.26%     
- Complexity     7337     7433      +96     
============================================
  Files           802      806       +4     
  Lines         69792    70142     +350     
  Branches       9312     9361      +49     
============================================
+ Hits          28897    29227     +330     
- Misses        37604    37608       +4     
- Partials       3291     3307      +16     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@VGalaxies VGalaxies left a comment

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.

Review summary

  • Blocking: yes
  • Summary: The change cannot currently guarantee recoverable RocksDB state, may silently disable cloud storage, and contains S3 retry and deployment defects.
  • Evidence:
    • Static analysis of git diff origin/master...HEAD
    • shell syntax and POM XML checks passed
    • git diff --check reported whitespace-only errors

Comment thread install-dist/release-docs/LICENSE Outdated
Comment thread docker/cloud-storage/scripts/test-graph-queries-and-sst.sh
vaijosh added 5 commits July 14, 2026 11:33
apache#3081
- Improved review comments.
- Synced METADATA, CURRENT AND OPTIONS to cloud so that we can recover the DB after cluster crash scenarios.
- Improved the resiliancy and reduced the data loss possibilities.
apache#3081
- Implemented review comments, Delete or tombstone the remote database generation during database destruction and make hydration honor that generation marker. Updated the runbooks and documentation for this.
- Fixed the test coverage issues reported by previous run
apache#3081
- Implemented review comment Cloud upload blocks the RocksDB event thread, S3 service failures bypass the provider retry contract,Multipart wrapping erases the direct-DLQ marker,Release metadata lists different dependency versions, improved test reporting.
apache#3081
- Added few missing configs in hugegraph-store/hg-store-dist/src/assembly/static/conf/application.yml
apache#3081
- Fixed UT failures and code coverage issues.
@vaijosh
vaijosh requested a review from VGalaxies July 15, 2026 14:43

@VGalaxies VGalaxies left a comment

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.

🚨 Review summary

Important

The cloud recovery path has blocking consistency, configuration, deletion-safety, release-metadata, and verification gaps.

📊 Risk dashboard

Signal Result
🚦 Review gate Blocked
🔎 Actionable findings 9 (8 High, 1 Medium)
🧪 Verification coverage 5 checks
⚠️ Confirmed / limited checks 2 / 1

🔬 Coverage details

⚠️ S3 failure semantics — Confirmed

Trace: S3CloudStorageProvider upload, download, delete, and exception-classification paths, CloudStorageEventListener purge and hydration flows, AWS SDK 2.33.8 retry-code and file-transformer behavior

Conclusion: Confirmed ignored per-object deletion errors, retryable error-code misclassification, and non-atomic download recovery risks; lower-impact lifecycle leads were dropped.

⚠️ Release and E2E integrity — Confirmed

Trace: install-dist release LICENSE and known-dependencies inventory, cloud-storage Docker artifact build and recovery workflow, Maven provider packaging and test activation

Conclusion: Confirmed the release dependency inventory mismatch and E2E false-green paths caused by suppressed build and wipe failures.

🟡 Focused unit suites — Limited

Trace: hg-store-common cloud configuration, provider, and factory tests, hg-store-cloud-s3 exception-classification tests, hg-store-node listener, retry, metrics, tracker, configuration, and callback tests, hg-store-core BusinessHandlerImplTest

Conclusion: Surefire reports recorded 184 tests with 0 failures, 0 errors, and 0 skipped. The suites do not cover concurrent metadata publication, comma-separated data roots, or partial S3 batch deletion.

✅ Maven reactor — Clear

Trace: Full 44-project reactor with the cloud-s3 profile, hugegraph-store module ordering and dependency graph

Conclusion: Maven validate completed successfully for all 44 reactor projects; the suspected duplicate cloud-s3 module activation did not reproduce.

✅ Shell syntax — Clear

Trace: pd-entrypoint.sh, store-entrypoint.sh, test-graph-queries-and-sst.sh

Conclusion: bash -n returned successfully for all three changed shell entrypoints and workflows.

Warning

Verification limits

  • No live Docker and MinIO recovery drill was run, so cluster recovery and purge behavior were not exercised end to end.
  • The test environment used Java 17; the legacy JaCoCo agent emitted unsupported class-version instrumentation errors, so coverage instrumentation was not verified even though test assertions passed.
  • S3SingleLargeFileE2ETest was intentionally not run because its default path generates a 20 GiB file.
  • The independent recovery-consistency run timed out after 900 seconds and produced no usable result.

🤖 Codex review · GPT-5.6 Sol · effort: xhigh

Comment thread install-dist/release-docs/LICENSE Outdated
Comment thread docker/cloud-storage/scripts/test-graph-queries-and-sst.sh Outdated
Comment thread docker/cloud-storage/scripts/test-graph-queries-and-sst.sh
@vaijosh

vaijosh commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

🚨 Review summary

Important

The cloud recovery path has blocking consistency, configuration, deletion-safety, release-metadata, and verification gaps.

📊 Risk dashboard

Signal Result
🚦 Review gate Blocked
🔎 Actionable findings 9 (8 High, 1 Medium)
🧪 Verification coverage 5 checks
⚠️ Confirmed / limited checks 2 / 1

🔬 Coverage details

⚠️ S3 failure semantics — Confirmed
Trace: S3CloudStorageProvider upload, download, delete, and exception-classification paths, CloudStorageEventListener purge and hydration flows, AWS SDK 2.33.8 retry-code and file-transformer behavior

Conclusion: Confirmed ignored per-object deletion errors, retryable error-code misclassification, and non-atomic download recovery risks; lower-impact lifecycle leads were dropped.

⚠️ Release and E2E integrity — Confirmed
Trace: install-dist release LICENSE and known-dependencies inventory, cloud-storage Docker artifact build and recovery workflow, Maven provider packaging and test activation

Conclusion: Confirmed the release dependency inventory mismatch and E2E false-green paths caused by suppressed build and wipe failures.

🟡 Focused unit suites — Limited
Trace: hg-store-common cloud configuration, provider, and factory tests, hg-store-cloud-s3 exception-classification tests, hg-store-node listener, retry, metrics, tracker, configuration, and callback tests, hg-store-core BusinessHandlerImplTest

Conclusion: Surefire reports recorded 184 tests with 0 failures, 0 errors, and 0 skipped. The suites do not cover concurrent metadata publication, comma-separated data roots, or partial S3 batch deletion.

✅ Maven reactor — Clear
Trace: Full 44-project reactor with the cloud-s3 profile, hugegraph-store module ordering and dependency graph

Conclusion: Maven validate completed successfully for all 44 reactor projects; the suspected duplicate cloud-s3 module activation did not reproduce.

✅ Shell syntax — Clear
Trace: pd-entrypoint.sh, store-entrypoint.sh, test-graph-queries-and-sst.sh

Conclusion: bash -n returned successfully for all three changed shell entrypoints and workflows.

Warning

Verification limits

  • No live Docker and MinIO recovery drill was run, so cluster recovery and purge behavior were not exercised end to end.
  • The test environment used Java 17; the legacy JaCoCo agent emitted unsupported class-version instrumentation errors, so coverage instrumentation was not verified even though test assertions passed.
  • S3SingleLargeFileE2ETest was intentionally not run because its default path generates a 20 GiB file.
  • The independent recovery-consistency run timed out after 900 seconds and produced no usable result.

🤖 Codex review · GPT-5.6 Sol · effort: xhigh

Hi @VGalaxies.
Thanks for reviewing the changes. I have addressed all the review comments. Can you please review it again?

@vaijosh

vaijosh commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@VGalaxies
I am not sure why code coverage check is failing.
We have
The Diff has 94.79% coverage (agains target 42.32%) [codecov/patch](https://github.com/apache/hugegraph/pull/3081/checks?check_run_id=89150435397)Successful in 1s — 94.79% of diff hit (target 42.32%)

Not sure why the coverage is suddenly dropped at project level to 30.60% (-11.72%) compared to e960cc5 codecov/projectFailing after 1s — 30.60% (-11.72%) compared to e960cc5

@vaijosh
vaijosh requested a review from VGalaxies July 23, 2026 11:57
@vaijosh

vaijosh commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

Hi @VGalaxies @imbajin Please don't merge the PR. I can see that JDK17 changes are in master branch. So I will need to test my changes with JRE17. I will update here once my testing is done.

Please ignore. I was bit confused due to merge conflict I got in docker/README.md due to changes in 9aaad11. It seems only reference to JDK17 was removed from README.md. But we are not yet moved to JDK17.

@vaijosh

vaijosh commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

@imbajin @VGalaxies
I have committed few more changes, fixed multiple review comments by Claude Code and Github Copilot.

Tested following scenarios

  1. SST and metadata synching is happening properly when Flush happens - End to End test and Manual steps in README.md
  2. During Compaction the new files are synced and few files are deleted. - End to End tests.
  3. During disk failures, the rehydration happens via Cloud storage. - End to End test and Manual steps in README.md
  4. During delete scenarios the TOMBSTONE is written and when delete is complete the data is deleted. - End to End test
  5. Load IBM AML large data ( Around 677609 Vertices and 17843793 Edgest) - aml_sql_showcase_hugegraph.ipynb

apache#3081
- Set a stable node-id on all three store containers so the cloud key scope
 survives a full volume wipe.
 -Document the scope re-seed WARN in README and pluggable-cloud-storage-architecture.md, covering when it is safe and when it is a silent data-loss risk.
@vaijosh

vaijosh commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

@VGalaxies @imbajin
Is anyone currently reviewing this PR? I understand it's a substantial change and will take some time to review, which is completely fine. I just wanted to check in to ensure it hasn't stalled and is still on the radar.

@bitflicker64 bitflicker64 left a comment

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.

Blocking: no. Summary: The SPI/factory shape is out of scope here because issue #3079 explicitly asks for it, but the biggest simplification left is inside the S3 provider — init() sets no overrideConfiguration, so the AWS SDK is already retrying every uploadPart with jittered backoff, and the hand-rolled multipart driver plus its second retry layer (~400 of that file's 1100 lines) can go. Evidence: local diff of the exact head against the PR base (git diff 401e627c30a7a0e0db5548a9431b6acfe82e43a1 eddcd868cc97d574e75f0a5709899b0a4600b222, 62 files / +24239 / -84); read S3CloudStorageProvider.init() L176-248 and the multipart path L691-956, CloudStorageEventListener.applyBackpressure/dlqEnqueueRateBacklog L1858-1942 against upload-backpressure-high-watermark: 0 in both application.yml files, AppConfig.readProviderProperties() L723-737 against spring-boot 2.5.14 in hg-store-node/pom.xml, and the **/*.ipynb exemption added at .licenserc.yaml:69. Note: the GitHub Files API reports additions=0 for hg-store-rocksdb/** and pom.xml at this diff size — those files do carry changes; the local diff is authoritative. All four anchors verified against right-side added lines in the exact-head diff.

Comment thread .licenserc.yaml Outdated
apache#3081
-Implemented review comments, removed multipart retry and leveraged s3-transfer-manager
-Removed upload-backpressure-high-watermark
- Replaced the manual AbstractEnvironment/EnumerablePropertySource streaming (~20 lines) with Binder.get(environment).bind("cloud.storage." + provider, Bindable.mapOf(...)).
apache#3081
-Fix docker-compose.dev.yml issue ( introduced due to merge conflicts)

@bitflicker64 bitflicker64 left a comment

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.

Blocking: no. Summary: the rework since the last round is real (the multipart driver, the inert backpressure path, the notebook and the property-source scan are all gone), and the biggest simplification left is the construction surface of CloudStorageEventListener: seven public constructors plus a Tuning/Builder pair plus equivalent setters, when production has exactly one caller using the full path, about 150 lines that one constructor with two extra parameters replaces. Second: CloudSyncTracker uses a Roaring64NavigableMap as a plain set, which costs a new RoaringBitmap dependency in hg-store-node and five synchronized blocks that ConcurrentHashMap.newKeySet() makes unnecessary. Evidence: reviewed the full diff at head f5b285d (60 files, +21633/-83) with the head fetched locally; git grep 'new CloudStorageEventListener(' shows one production call site (AppConfig) against 61 test call sites; CloudSyncTracker touches the bitmap only via addLong/removeLong/contains/getLongCardinality. The SPI/factory shape is not raised: issue #3079 explicitly asks for an SPI-based extensible architecture, and the retry queue's DLQ persistence is data-loss protection, not scaffolding.

- Implemented review comments 1.collapse CloudStorageEventListener/CloudUploadRetryQueue constructors 2.replace Roaring64NavigableMap with ConcurrentHashMap.newKeySet() in CloudSyncTracker
- Added back RoaringBitmap in known-dependencies.txt and LICENSE
RocksDB's onTableFileCreated/onTableFileDeleted/onCompactionCompleted callbacks run on RocksDB's own native threads with no Java caller frame, so they resolve classes via the plain system classloader. Inside a Spring Boot fat jar that classloader can't see classes nested under BOOT-INF/lib, so registering the listener always threw NoClassDefFoundError once the distribution jar was packaged. Add RocksDBFactory#hasRocksdbChangedListeners() and only call dbOptions.setListeners(...) in RocksDBSession#openRocksDB when at least one RocksdbChangedListener is actually registered, so the native callback path is never exercised unless a listener-based feature (e.g. cloud storage sync) is enabled.
- Fixed license issues. Now S3 provider is opt-in mechanism, so the known-dependencies.txt and LICENSE entries are reported as 3rd party check failures.
- It seems earlier the CI failure was because rockdb jni ws not on classpath. Updated Classpath a bit
- Fix redundant jsonassert-1.5.0.jar brought in due to merge commit.

@bitflicker64 bitflicker64 left a comment

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.

Blocking: no. Summary: The largest cut is the global mutable provider in CloudStorageProviderFactory. Passing the resolved provider into the listener and retry queue removes 16 null-provider branches and a second retry budget. The file-backed DLQ has no production reader because replayDlq() is only called from tests. Evidence: static reading of the full diff at 1cf07b0; grep for replayDlq, getActiveProvider, provider == null, metadataSyncScheduler() and uploadSubsystemShuttingDown across hg-store-*/src/main; RocksDBFactory.createGraphDB fires onDBCreated, which runs uploadExistingSstFiles on every open.

* has not yet been called.
*/
@Getter
private static volatile CloudStorageProvider activeProvider;

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.

Important: should not exist. The provider is set once in @PostConstruct and never reconfigured, yet it lives in a mutable global.

The listener and retry queue call getActiveProvider() at 18 sites with 16 provider == null branches. Those branches feed a second "provider unavailable" retry budget: DEFAULT_MAX_PROVIDER_UNAVAILABLE_RETRIES, computeProviderUnavailableDelay and two *ForTest setters in CloudUploadRetryQueue, plus TRUNCATE_PROVIDER_UNAVAILABLE_MAX_DELAY_MS in the listener. AppConfig returns before initialize when cloud storage is disabled, so the disabled branch here never runs. reset() and setActiveProviderForTest() are test hooks in main code.

Keep the SPI (#3079 asks for it). Resolve the provider once and pass it to both constructors as a final field:

CloudStorageProvider provider = ServiceLoader.load(CloudStorageProvider.class).stream()
        .map(ServiceLoader.Provider::get)
        .filter(p -> p.providerName().equals(cfg.getProvider()))
        .findFirst()
        .orElseThrow(() -> new IllegalArgumentException(
                "No cloud storage provider '" + cfg.getProvider() + "' on the classpath"));
provider.init(cfg);

That deletes the global, the null branches, the second retry budget and the test hooks.

* fail again).</li>
* </ul>
*/
public void replayDlq() {

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.

Important: should not exist. replayDlq() has no caller outside CloudUploadRetryQueueTest: no endpoint, no scheduled call, no startup call.

loadDlqFromDisk() reads .cloud-upload-dlq.tsv at startup and logs "call replayDlq() to retry them", but no operator path can do that. The loaded entries sit in memory unused. Recovery already happens without the file: createGraphDB fires onDBCreated on every open, and uploadExistingSstFiles uploads every live *.sst missing from the bucket. The PR's docs say evicted entries "stay recoverable via the delete guard and startup SST backfill".

That leaves about 380 lines writing a file nobody reads:

  • loadDlqFromDisk, appendDlqEntryToDisk, rewriteDlqFile, fsyncDir
  • serialize/deserialize/escape/unescape
  • dlqFileLock
  • the dlqPersistenceHealthy flag, gauge and AppConfig binding
  • this method

Requested change: keep the in-memory DLQ count for visibility and delete the persistence and replay. If replay is wanted, call replayDlq() once after loadDlqFromDisk() in the constructor so the file has a reader.

* the same JVM binds new listeners to a live executor instead of a TERMINATED one (which would
* reject every upload via AbortPolicy and silently divert all SSTs to the DLQ).
*/
private static ThreadPoolExecutor sharedUploadExecutor;

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.

Important: should not exist. Production builds one listener, but the upload pool and metadata-sync scheduler are static, with lazy re-creation in sharedUploadExecutor() / metadataSyncScheduler().

A static uploadSubsystemShuttingDown gate stops the scheduler from coming back during drain. Because the gate lets metadataSyncScheduler() return null, four call sites carry a scheduler == null branch (L899, L1165, L1796, L2114), and requestDebouncedMetadataSync checks the gate again. The stated reason is "a Spring context restart in the same JVM", which hg-store-node does not do.

Requested change: create both executors as private final instance fields in the constructor. Add a close() that calls uploadExecutor.shutdown(), awaitTermination(...) and then scheduler.shutdownNow(), and call it from AppConfig.onDestroy(). A schedule after shutdown throws RejectedExecutionException, which every call site already catches. The two static fields, both lazy getters, the gate and the four null branches go.

@Data
@Configuration
@ConfigurationProperties(prefix = "cloud.storage")
public class CloudStorageSpringConfig {

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.

Important: replace or collapse. This class re-declares all 12 fields of CloudStorageConfig with the same defaults, and toCloudStorageConfig() copies them one setter at a time. A new knob means three edits, and the two sets of defaults can drift.

CloudStorageConfig is already a Lombok @Data bean, so bind it directly:

CloudStorageConfig cfg = Binder.get(environment)
        .bind("cloud.storage", CloudStorageConfig.class)
        .orElseGet(CloudStorageConfig::new);
cfg.setProviderProperties(readProviderProperties(cfg.getProvider()));

That deletes this inner @Configuration class and the copy method. Relaxed binding (CLOUD_STORAGE_ENABLED and so on) still works.

* truncate-purge intent durable across process restarts while the provider is unavailable.
*/
@SuppressWarnings("ResultOfMethodCallIgnored")
private void writePendingTruncateMarker(String dbName, String prefix) throws IOException {

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.

Important: replace or collapse. The delete and truncate marker code exists twice, and the copies differ only in the directory and the log text:

  • This method matches writePendingDeleteMarker line for line (file fsync, directory fsync, Windows skip). The only extra there is deleteMarkerHealthy = true.
  • processPendingTruncateMarkersOnStartup matches processPendingDeleteMarkersOnStartup except for the log text and the final schedule call.
  • pending*Dir, pending*MarkerPath and removePending*Marker come in pairs.

Requested change: one writeMarker(Path dir, String prefix), one removeMarker(Path dir, String prefix) and one scanMarkers(Path dir, BiConsumer<String, String> onMarker) taking (dbName, prefix). Each caller passes its directory and callback, and the delete caller sets deleteMarkerHealthy itself. That removes about 90 lines.

While there: the file name is Base64(prefix), the body repeats the prefix, and the startup scan drops the marker unless the two match. Decode the name and write an empty file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature size:XXL This PR changes 1000+ lines, ignoring generated files. store Store module

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

4 participants