#2702 CREATE INDEX waits for any running async tasks by robfrank · Pull Request #3408 · ArcadeData/arcadedb · GitHub
Skip to content

#2702 CREATE INDEX waits for any running async tasks - #3408

Merged
robfrank merged 2 commits into
mainfrom
call-devs
Feb 13, 2026
Merged

robfrank merged 2 commits into
mainfrom
call-devs

Conversation

@robfrank

@robfrank robfrank commented Feb 11, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Fix sequential index creation failing with NeedRetryException when background LSMTree
    compaction is running (NeedRetryException when creating indexes sequentially on large datasets #2702)
  • Instead of throwing immediately, TypeIndexBuilder and ManualIndexBuilder now wait for async
    tasks to complete before creating a new index
  • Clean up searchMoreLikeThis in LSMTreeFullTextIndex: simplify score accumulation (Map<RID,
    Integer> instead of AtomicInteger), remove redundant null checks, use
    Comparator.comparingInt().reversed() for sorting

Test plan

  • New Issue2702SequentialIndexCreationTest covers sequential index creation under compaction
    and verifies the waiting behavior
  • Run existing full-text index tests to verify searchMoreLikeThis refactoring: mvn test
    -Dtest="FullText,MoreLikeThis"
  • Run index builder regression tests: mvn test -Dtest="IndexBuilder,IndexCompaction"

@gemini-code-assist

Copy link
Copy Markdown
Contributor

@claude

claude Bot commented Feb 11, 2026

Copy link
Copy Markdown

Pull Request Review

I've reviewed PR #3408 and have the following feedback:

Overview

This PR addresses Issue #2702 by changing the behavior when creating indexes while async processing (LSMTree compaction) is running. Instead of immediately throwing NeedRetryException, the code now waits for async tasks to complete.


🟢 Positives

1. Code Quality

  • ✅ Clean, focused changes with clear intent
  • ✅ Excellent inline comments explaining the rationale
  • ✅ Consistent implementation across both TypeIndexBuilder and ManualIndexBuilder
  • ✅ Follows existing code style (single-statement if blocks without braces)

2. Test Coverage

  • ✅ Comprehensive test class with two distinct test scenarios
  • ✅ Tests cover the actual issue (sequential index creation on large datasets)
  • ✅ Tests verify the waiting behavior explicitly
  • ✅ Good use of assertThat() syntax as per project guidelines
  • ✅ Proper cleanup of GlobalConfiguration changes in finally blocks

3. Documentation

  • ✅ Extensive markdown documentation (2702-sequential-index-creation-fix.md) explaining the problem, solution, and trade-offs
  • ✅ Clear comments in code explaining the behavior change

🟡 Concerns & Suggestions

1. Thread Safety & Deadlock Risk ⚠️

Issue: Calling database.async().waitCompletion() while holding transaction locks could potentially lead to deadlock scenarios.

Location:

  • TypeIndexBuilder.java:86-89
  • ManualIndexBuilder.java:47-50

Concern: If the async compaction task needs to acquire any locks that the current thread holds, this could deadlock. The code path should be analyzed to ensure:

  • The async tasks don't need schema locks
  • The current transaction context won't block async workers

Recommendation: Add a timeout to waitCompletion() calls to prevent indefinite blocking:

if (database.isAsyncProcessing()) {
  // Wait with timeout to prevent indefinite blocking
  database.async().waitCompletion(timeout);
}

2. LSMTreeFullTextIndex.java Changes

Issue: This file contains significant refactoring unrelated to the main fix:

  • Removed AtomicInteger usage in searchMoreLikeThis (line 695: Map<RID, Integer> instead of Map<RID, AtomicInteger>)
  • Simplified control flow (removed many braces)
  • Added JavaDoc comments
  • Changed sorting implementation (line 715: using Comparator.comparingInt().reversed())

Concern: These changes, while improvements, are not part of the sequential index creation fix and make the PR harder to review. They could also introduce subtle bugs.

Recommendation:

  • ❌ Per CLAUDE.md: "don't add Claude as author" - The extensive JavaDoc additions suggest AI-generated documentation
  • 🔄 Consider splitting LSMTreeFullTextIndex changes into a separate PR for proper review
  • 🧪 Ensure the searchMoreLikeThis refactoring has adequate test coverage

3. Unrelated Documentation File

Issue: The file 2702-sequential-index-creation-fix.md in the root directory appears to be design documentation.

Question: Should this be:

  • Moved to a docs/ directory?
  • Converted to a GitHub issue comment instead?
  • Removed before merging (documentation belongs in code comments and commit messages)?

Per CLAUDE.md: "NEVER proactively create documentation files (*.md)" - This markdown file should likely not be in the repository.

4. Missing Validation

Question: What happens if database.async().waitCompletion() throws an exception? Should there be error handling?

if (database.isAsyncProcessing()) {
  try {
    database.async().waitCompletion();
  } catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    throw new NeedRetryException("Interrupted while waiting for async tasks", e);
  }
}

5. Performance Considerations

Question: The documentation states this can take "30-60+ seconds" for compaction. This means:

  • Index creation DDL operations can block for minutes
  • Applications may experience timeouts if not configured properly
  • Users might perceive the system as hung

Recommendation: Consider adding:

  • Logging when waiting starts: LogManager.instance().log(..., FINE, "Waiting for async compaction...")
  • Progress indicators if possible
  • Documentation in user-facing docs about this behavior

🔍 Testing Recommendations

Run These Tests Before Merging:

# Test the new functionality
mvn test -Dtest=Issue2702SequentialIndexCreationTest

# Regression tests for index creation
mvn test -Dtest="*IndexBuilder*,*IndexCompaction*,LSMTreeIndexTest,TypeLSMTreeIndexTest"

# Full-text index tests (due to LSMTreeFullTextIndex changes)
mvn test -Dtest="*FullText*,*MoreLikeThis*"

🎯 Recommendations Summary

Must Address:

  1. ❌ Remove or relocate the `2702-sequential-index-creation-fix.md" file (violates CLAUDE.md guidelines)
  2. 🔄 Split LSMTreeFullTextIndex refactoring into a separate PR or justify its inclusion
  3. 🧪 Run full test suite, especially full-text search tests

Should Consider:

  1. Add timeout to waitCompletion() calls
  2. Add logging when blocking on async tasks
  3. Add exception handling for interrupted waits
  4. Verify no deadlock scenarios exist

Nice to Have:

  1. Document the blocking behavior in user-facing documentation
  2. Consider adding metrics/monitoring for wait times

✅ Conclusion

The core fix for Issue #2702 is sound and well-implemented. The approach is simple, predictable, and aligns with standard database behavior. However, the PR contains unrelated changes that should be addressed before merging.

Verdict: Approve with changes requested for:

  • Removing the markdown doc file
  • Clarifying/separating LSMTreeFullTextIndex changes
  • Adding timeout/logging for production robustness

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request addresses an issue where creating multiple indexes sequentially could fail with a NeedRetryException. The fix, implemented in TypeIndexBuilder and ManualIndexBuilder, is to wait for any ongoing asynchronous tasks to complete instead of throwing an exception. This change improves the developer experience by removing the need for manual retry logic.

A new test class, Issue2702SequentialIndexCreationTest, has been added to verify the fix under conditions that would previously trigger the error, which is great.

Additionally, the LSMTreeFullTextIndex class has been refactored for better readability and maintainability, including the addition of Javadocs and the use of more modern Java constructs.

My review includes one suggestion regarding coding style in LSMTreeFullTextIndex.java to ensure long-term maintainability.

@mergify

mergify Bot commented Feb 11, 2026 •

Copy link
Copy Markdown
Contributor

🧪 CI Insights

Here's what we observed from your CI run for 810fc8c.

🟢 All jobs passed!

But CI Insights is watching 👀

@codacy-production

codacy-production Bot commented Feb 11, 2026 •

Copy link
Copy Markdown

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
✅ -11.02% ✅ 82.14%
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (b2dcfda) 83715 59702 71.32%
Head commit (810fc8c) 113266 (+29551) 68297 (+8595) 60.30% (-11.02%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#3408) 28 23 82.14%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

See your quality gate settings    Change summary preferences

@codecov

codecov Bot commented Feb 11, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 60.71429% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 62.96%. Comparing base (b2dcfda) to head (810fc8c).
⚠️ Report is 17 commits behind head on main.

Files with missing lines Patch % Lines
.../arcadedb/index/fulltext/LSMTreeFullTextIndex.java 70.83% 2 Missing and 5 partials ⚠️
...n/java/com/arcadedb/schema/ManualIndexBuilder.java 0.00% 2 Missing ⚠️
...ain/java/com/arcadedb/schema/TypeIndexBuilder.java 0.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3408      +/-   ##
==========================================
+ Coverage   62.52%   62.96%   +0.43%     
==========================================
  Files        1251     1251              
  Lines       83715    83708       -7     
  Branches    17142    17140       -2     
==========================================
+ Hits        52346    52704     +358     
+ Misses      24039    23603     -436     
- Partials     7330     7401      +71     

☔ View full report in Codecov by Sentry.
📢 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.


// Wait for any running async tasks (e.g., compaction) to complete before creating new index
// This prevents NeedRetryException when creating multiple indexes sequentially on large datasets
if (database.isAsyncProcessing())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it should be

while (database.isAsyncProcessing())          
  database.async().waitCompletion();

In case of concurrency?

Comment thread 2702-sequential-index-creation-fix.md Outdated
@@ -0,0 +1,163 @@
# Issue #2702: NeedRetryException when creating indexes sequentially on large datasets

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We don't need this file in the codebase


// Wait for any running async tasks (e.g., compaction) to complete before creating new index
// This prevents NeedRetryException when creating multiple indexes sequentially on large datasets
if (database.isAsyncProcessing())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it should be

while (database.isAsyncProcessing())          
  database.async().waitCompletion();

In case of concurrency?

robfrank and others added 2 commits February 12, 2026 16:47
- Use while loop instead of if for async wait in TypeIndexBuilder and
  ManualIndexBuilder to handle concurrency edge cases
- Remove unnecessary 2702-sequential-index-creation-fix.md doc file

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@claude

claude Bot commented Feb 12, 2026

Copy link
Copy Markdown

@robfrank robfrank changed the title fix tests #2702 CREATE INDEX waits for any running async tasks Feb 12, 2026
@robfrank
robfrank requested a review from lvca February 12, 2026 16:57
@lvca lvca added this to the 26.2.1 milestone Feb 12, 2026
@robfrank
robfrank merged commit 1059e4c into main Feb 13, 2026
23 of 28 checks passed
@robfrank
robfrank deleted the call-devs branch February 13, 2026 08:55
robfrank added a commit that referenced this pull request Feb 17, 2026
tae898 pushed a commit to humemai/arcadedb-embedded-python that referenced this pull request Jun 28, 2026
mergify Bot added a commit that referenced this pull request Jul 12, 2026
…e-python [skip ci]

Updates the requirements on [docker](https://github.com/docker/docker-py) to permit the latest version.
Release notes

*Sourced from [docker's releases](https://github.com/docker/docker-py/releases).*

> 7.2.0
> -----
>
> Upgrade Notes
> -------------
>
> * `docker.from_env()` now honors the active Docker CLI context when `DOCKER_HOST` is not set.
>   + This means the client may connect to the daemon selected by `DOCKER_CONTEXT` or the current context in `~/.docker/config.json`, matching Docker CLI behavior more closely.
>   + If your application relied on the previous default connection behavior, set `DOCKER_HOST` explicitly, set `DOCKER_CONTEXT=default`, or pass `use_context=False` to `DockerClient.from_env()`.
> * Added `docker.from_context()` / `DockerClient.from_context()` for explicitly creating a client from a Docker CLI context.
>
> Features
> --------
>
> * Added support for Docker contexts when creating the default client
> * Added subpath support for volumes
>
> Bugfixes
> --------
>
> * Fixed `exec_run` documentation for the `stream` parameter
> * Fixed image loading to avoid depending on the deprecated `JSONMessage.error` field
> * Preserved the rotated unlock key in swarm integration tests
> * Fixed SSL certificate generation in tests
> * Fixed IPv6 integration tests by explicitly enabling IPv6 where required
>
> Miscellaneous
> -------------
>
> * Updated tests for newer Docker Engine behavior
> * CI and build updates
>
> What's Changed
> --------------
>
> * tests/exec: expect 127 exit code for missing executable by [`@​laurazard`](https://github.com/laurazard) in [docker/docker-py#3290](https://redirect.github.com/docker/docker-py/pull/3290)
> * fixing doc for stream param in exec\_run by [`@​yasonk`](https://github.com/yasonk) in [docker/docker-py#3292](https://redirect.github.com/docker/docker-py/pull/3292)
> * Bump default API version to 1.45 (Moby 26.0/26.1) by [`@​thaJeztah`](https://github.com/thaJeztah) in [docker/docker-py#3261](https://redirect.github.com/docker/docker-py/pull/3261)
> * Set a dummy-version if none set, and remove unused APT\_MIRROR build-arg by [`@​thaJeztah`](https://github.com/thaJeztah) in [docker/docker-py#3267](https://redirect.github.com/docker/docker-py/pull/3267)
> * test\_service\_logs: stop testing experimental versions by [`@​thaJeztah`](https://github.com/thaJeztah) in [docker/docker-py#2442](https://redirect.github.com/docker/docker-py/pull/2442)
> * Makefile: fix circular reference for integration-dind by [`@​thaJeztah`](https://github.com/thaJeztah) in [docker/docker-py#3297](https://redirect.github.com/docker/docker-py/pull/3297)
> * image load: don't depend on deprecated JSONMessage.error field by [`@​thaJeztah`](https://github.com/thaJeztah) in [docker/docker-py#3307](https://redirect.github.com/docker/docker-py/pull/3307)
> * integration: test\_create\_volume\_invalid\_driver allow either 400 or 404 by [`@​thaJeztah`](https://github.com/thaJeztah) in [docker/docker-py#3296](https://redirect.github.com/docker/docker-py/pull/3296)
> * integration: adjust tests for omitted "OnBuild" by [`@​thaJeztah`](https://github.com/thaJeztah) in [docker/docker-py#3336](https://redirect.github.com/docker/docker-py/pull/3336)
> * Implement Subpath Support for Volumes in Docker-Py ([#3243](https://redirect.github.com/docker/docker-py/issues/3243)) by [`@​Khushiyant`](https://github.com/Khushiyant) in [docker/docker-py#3270](https://redirect.github.com/docker/docker-py/pull/3270)
> * tests: fix ssl generation by [`@​thaJeztah`](https://github.com/thaJeztah) in [docker/docker-py#3365](https://redirect.github.com/docker/docker-py/pull/3365)
> * test/integration: don't check for deprecated Networks field by [`@​thaJeztah`](https://github.com/thaJeztah) in [docker/docker-py#3362](https://redirect.github.com/docker/docker-py/pull/3362)
> * test: Skip from\_env\_unix tests if DOCKER\_HOST is network socket by [`@​ricardobranco777`](https://github.com/ricardobranco777) in [docker/docker-py#3366](https://redirect.github.com/docker/docker-py/pull/3366)
> * test\_connect\_with\_ipv6\_address: enable IPv6 by [`@​robmry`](https://github.com/robmry) in [docker/docker-py#3372](https://redirect.github.com/docker/docker-py/pull/3372)
> * test\_create\_with\_ipv6\_address: enable IPv6 by [`@​robmry`](https://github.com/robmry) in [docker/docker-py#3373](https://redirect.github.com/docker/docker-py/pull/3373)
> * tests: Migrate off gpg2 and regenerate key ed25519 by [`@​vvoland`](https://github.com/vvoland) in [docker/docker-py#3399](https://redirect.github.com/docker/docker-py/pull/3399)
> * gha: Pin to digests by [`@​vvoland`](https://github.com/vvoland) in [docker/docker-py#3408](https://redirect.github.com/docker/docker-py/pull/3408)
> * Fix integration tests on non-amd64 hosts and add ARM64 CI by [`@​vvoland`](https://github.com/vvoland) in [docker/docker-py#3407](https://redirect.github.com/docker/docker-py/pull/3407)
> * integration/swarm: Preserve rotated unlock key by [`@​vvoland`](https://github.com/vvoland) in [docker/docker-py#3410](https://redirect.github.com/docker/docker-py/pull/3410)
> * [DKP-2535] Honour context if present for default client, add contexts support by [`@​ebriney`](https://github.com/ebriney) in [docker/docker-py#3401](https://redirect.github.com/docker/docker-py/pull/3401)
> * docs: 7.2.0 changelog by [`@​vvoland`](https://github.com/vvoland) in [docker/docker-py#3415](https://redirect.github.com/docker/docker-py/pull/3415)
>
> New Contributors
> ----------------
>
> * [`@​laurazard`](https://github.com/laurazard) made their first contribution in [docker/docker-py#3290](https://redirect.github.com/docker/docker-py/pull/3290)
> * [`@​yasonk`](https://github.com/yasonk) made their first contribution in [docker/docker-py#3292](https://redirect.github.com/docker/docker-py/pull/3292)
> * [`@​ricardobranco777`](https://github.com/ricardobranco777) made their first contribution in [docker/docker-py#3366](https://redirect.github.com/docker/docker-py/pull/3366)

... (truncated)


Commits

* [`5ad5327`](docker/docker-py@5ad5327) Merge pull request [#3415](https://redirect.github.com/docker/docker-py/issues/3415) from vvoland/update-changelog
* [`d242230`](docker/docker-py@d242230) docs: 7.2.0 changelog
* [`ba01cc7`](docker/docker-py@ba01cc7) Merge pull request [#3401](https://redirect.github.com/docker/docker-py/issues/3401) from ebriney/client-from-context
* [`ae5dfe9`](docker/docker-py@ae5dfe9) Merge pull request [#3410](https://redirect.github.com/docker/docker-py/issues/3410) from vvoland/fix-flaky
* [`aa99999`](docker/docker-py@aa99999) integration/swarm: Preserve rotated unlock key
* [`059d371`](docker/docker-py@059d371) Merge pull request [#3407](https://redirect.github.com/docker/docker-py/issues/3407) from vvoland/fix-arm64
* [`9b4b9b8`](docker/docker-py@9b4b9b8) gha: Add arm64 integration CI
* [`9e9f8ff`](docker/docker-py@9e9f8ff) Skip tests incompatible with host architecture
* [`e0542d9`](docker/docker-py@e0542d9) Merge pull request [#3408](https://redirect.github.com/docker/docker-py/issues/3408) from vvoland/gha-pin
* [`578a11d`](docker/docker-py@578a11d) gha: Pin to digests
* Additional commits viewable in [compare view](docker/docker-py@7.1.0...7.2.0)
  
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
  
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot show  ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
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.

NeedRetryException when creating indexes sequentially on large datasets

2 participants