Skip to content

Jbtm 4038 JGroups and JGroups+RAFT object store examples - #775

Open
mmusgrov wants to merge 8 commits into
jbosstm:mainfrom
mmusgrov:JBTM-4038
Open

Jbtm 4038 JGroups and JGroups+RAFT object store examples#775
mmusgrov wants to merge 8 commits into
jbosstm:mainfrom
mmusgrov:JBTM-4038

Conversation

@mmusgrov

@mmusgrov mmusgrov commented Aug 6, 2026

Copy link
Copy Markdown
Member

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Adds standalone and clustered JGroups SlotStore and JGroups Raft examples. Adds JGroups configurations, Maven dependencies, cluster runners, WAL recovery support, documentation, and sequential quickstart commands.

JGroups object-store quickstarts

Layer / File(s) Summary
Store dependencies and configurations
ArjunaJTA/object_store/pom.xml, ArjunaJTA/object_store/src/main/resources/*, pom.xml
Adds JGroups Raft and Arjuna dependencies. Adds JGroups, TCP, Raft, and Narayana properties configurations.
Standalone store examples
ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroups*SlotStore*Example.java, ArjunaJTA/object_store/run.sh, ArjunaJTA/object_store/README.md
Adds standalone SlotStore and Raft examples, properties-file entry points, sequential execution commands, and usage documentation.
Clustered store examples
ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/*ClusterExample.java, ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/ClusterExampleSupport.java, ArjunaJTA/object_store/run-jgroups*-cluster.sh
Adds two-node transaction-store examples. The examples create in-doubt transactions and verify recovery-store visibility. The scripts manage startup, readiness polling, cleanup, and exit status.
WAL recovery workflow
ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreWALRecoveryExample.java, ArjunaJTA/object_store/run-jgroups-wal-recovery.sh
Adds separate WAL creation and recovery phases. The workflow persists a transaction UID, scans recovered transactions, cleans generated state, and returns the recovery status.

Sequence Diagram(s)

sequenceDiagram
  participant Node1 as JGroups SlotStore node1
  participant Cluster as JGroups cluster
  participant Node2 as JGroups SlotStore node2
  Node1->>Cluster: Publish readiness
  Node2->>Cluster: Join cluster
  Node1->>Cluster: Replicate in-doubt transaction
  Node2->>Cluster: Scan recovery store
  Node2-->>Cluster: Report transaction visibility
Loading

Possibly related issues

Possibly related PRs

  • jbosstm/quickstart#743 — Also changes ArjunaJTA/object_store/README.md and updates object-store example commands.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the JGroups and JGroups Raft object store examples added by the pull request.
Description check ✅ Passed The description references the related issue and JDK 25 target, so it is related to the changeset.
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.

Actionable comments posted: 8

🤖 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.

Inline comments:
In `@ArjunaJTA/object_store/README.md`:
- Around line 41-46: Update the README instructions for
JGroupsSlotStoreClusterExample and JGroupsRaftSlotStoreClusterExample to
explicitly state that each node command must run concurrently in a separate
terminal, so both cluster processes remain active during formation.

In `@ArjunaJTA/object_store/run-jgroups-cluster.sh`:
- Around line 11-24: The Maven version argument handling is unsafe and
duplicated across both cluster scripts. In
ArjunaJTA/object_store/run-jgroups-cluster.sh lines 11-24, replace the x-prefix
check with a quoted -n test, store the optional argument in an array, and invoke
Maven directly in a negated if using "${NARAYANA_VERSION_PARAM[@]}". Apply the
same array conversion and direct Maven result check in
ArjunaJTA/object_store/run-jgroups-raft-cluster.sh lines 12-25, and update its
Maven invocations on lines 29 and 47 to use the quoted array expansion.
- Around line 45-46: Remove the duplicated exec:java goal and -Dexec.mainClass
argument from the node2 invocation in the JGroups cluster script, leaving one
Maven execution with node2, port 7801, and the existing Narayana version
parameter.

In
`@ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreClusterExample.java`:
- Around line 148-180: Extract the duplicated recovery scanning, shutdown,
logging, node coordination, and CrashInCommitRecord logic into a package-private
ClusterExampleSupport helper. In
ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreClusterExample.java#L148-L180,
remove scanRecoveryStore, shutdown, and log and call the helper; in
ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreClusterExample.java#L167-L199,
move those methods and CrashInCommitRecord into the helper. Move the identical
marker-file wait and creation block from both main methods as well, leaving each
example responsible only for its store configuration and removing the dependency
between the two examples.

In
`@ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreClusterExample.java`:
- Around line 183-185: Update the exception handler in
JGroupsSlotStoreClusterExample so the recovery-store scan failure logs the full
exception stack trace rather than only e.getMessage(). Preserve the existing
error context while passing the caught exception through the logger’s
throwable-aware API.
- Around line 135-141: Update the state-transfer wait logic around the deadline
loop in JGroupsSlotStoreClusterExample so it distinguishes cache population from
expiration of the 10-second deadline. After the loop, report a timeout when the
cache remains empty, and only log “State transfer complete” when entries are
present.
- Around line 132-141: Update the startup and state-transfer logic around the
ReplCache usage to avoid direct calls to getL2Cache().getInternalMap() and
cache.start(). Use the supported SlotStoreAdaptor/store startup path and
supported diagnostics or callbacks to determine completion, preserving the
example’s state-transfer wait and cache-entry reporting behavior.

In
`@ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreExample.java`:
- Around line 26-35: Wrap the transaction work in main, including utx.begin(),
Util.enlistResources(), and utx.commit(), in a try/finally so shutdownStore()
always executes. Apply this change in
ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreExample.java
(lines 26-35) and
ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreExample.java
(lines 32-41), ensuring cleanup occurs on every transaction outcome.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fbb87ed7-ab23-4df9-a071-2b4c4ce84c3d

📥 Commits

Reviewing files that changed from the base of the PR and between 4b03a1d and e7ba2c1.

📒 Files selected for processing (19)
  • ArjunaJTA/object_store/README.md
  • ArjunaJTA/object_store/pom.xml
  • ArjunaJTA/object_store/run-jgroups-cluster.sh
  • ArjunaJTA/object_store/run-jgroups-raft-cluster.sh
  • ArjunaJTA/object_store/run-jgroups-wal-recovery.sh
  • ArjunaJTA/object_store/run.sh
  • ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreClusterExample.java
  • ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreConfigExample.java
  • ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreExample.java
  • ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreClusterExample.java
  • ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreConfigExample.java
  • ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreExample.java
  • ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreWALRecoveryExample.java
  • ArjunaJTA/object_store/src/main/resources/jgroups-config.xml
  • ArjunaJTA/object_store/src/main/resources/jgroups-jbossts-properties.xml
  • ArjunaJTA/object_store/src/main/resources/jgroups-raft-config.xml
  • ArjunaJTA/object_store/src/main/resources/jgroups-raft-jbossts-properties.xml
  • ArjunaJTA/object_store/src/main/resources/jgroups-raft-tcp-config.xml
  • ArjunaJTA/object_store/src/main/resources/jgroups-tcp-config.xml

Comment on lines +41 to +46
mvn -e compile exec:java -Dexec.mainClass=org.jboss.narayana.jta.quickstarts.JGroupsSlotStoreClusterExample -Dexec.args="node1" -Djgroups.bind_port=7800
mvn -e compile exec:java -Dexec.mainClass=org.jboss.narayana.jta.quickstarts.JGroupsSlotStoreClusterExample -Dexec.args="node2" -Djgroups.bind_port=7801
mvn -e compile exec:java -Dexec.mainClass=org.jboss.narayana.jta.quickstarts.JGroupsRaftSlotStoreConfigExample
mvn -e compile exec:java -Dexec.mainClass=org.jboss.narayana.jta.quickstarts.JGroupsRaftSlotStoreExample
mvn -e compile exec:java -Dexec.mainClass=org.jboss.narayana.jta.quickstarts.JGroupsRaftSlotStoreClusterExample -Dexec.args="node1" -Djgroups.bind_port=7800
mvn -e compile exec:java -Dexec.mainClass=org.jboss.narayana.jta.quickstarts.JGroupsRaftSlotStoreClusterExample -Dexec.args="node2" -Djgroups.bind_port=7801

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

State that each cluster pair must run concurrently.

Lines 41-42 and Lines 45-46 present two-node commands as a serial sequence. Run each node in a separate terminal so both processes are active when the cluster forms.

🤖 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 `@ArjunaJTA/object_store/README.md` around lines 41 - 46, Update the README
instructions for JGroupsSlotStoreClusterExample and
JGroupsRaftSlotStoreClusterExample to explicitly state that each node command
must run concurrently in a separate terminal, so both cluster processes remain
active during formation.

Comment thread ArjunaJTA/object_store/run-jgroups-cluster.sh Outdated
Comment thread ArjunaJTA/object_store/run-jgroups-cluster.sh Outdated
Comment on lines +132 to +141
ReplCache<ByteArrayKey, byte[]> cache = config.getCache();
cache.start();

long deadline = System.currentTimeMillis() + 10_000;
while (cache.getL2Cache().getInternalMap().isEmpty()
&& System.currentTimeMillis() < deadline) {
Thread.sleep(200);
}
log("State transfer complete: %d cache entries",
cache.getL2Cache().getInternalMap().size());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Locate the JGroups and Narayana jars declared for this module, then inspect the APIs used here.
fd -t f 'pom.xml' ArjunaJTA/object_store --exec cat

# Check for other usages of these accessors in the repository.
rg -nP -C3 'getL2Cache\s*\(|getInternalMap\s*\(' --type=java

Repository: jbosstm/quickstart

Length of output: 4243


🌐 Web query:

JGroups ReplCache getL2Cache getInternalMap API

💡 Result:

In the JGroups framework, getL2Cache and getInternalMap are methods used to access underlying cache structures, primarily for monitoring or diagnostic purposes such as the ReplCacheDemo [1][2][3]. getL2Cache The ReplCache class provides the getL2Cache method, which returns the L2 (Level 2) cache instance [1][4][5]. Its signature is typically defined as: public Cache<K, ReplCache.Value> getL2Cache [1][4][6][7] This method allows access to the cache that stores the actual values, wrapped in ReplCache.Value objects [1][4]. getInternalMap The getInternalMap method is a member of the Cache class (which is used by ReplCache for its L2 cache) [2][8]. Its signature is: public java.util.concurrent.ConcurrentMap<K, Cache.Value> getInternalMap [2][9][10] Official documentation and code comments explicitly state that this method should not be used to add or remove elements [2][9][8]. It was added to the API specifically to support the data model requirements of the ReplCacheDemo [2][3][9][8]. In practice, it is often used to bind the cache state to a UI component, such as a table model, for visualizing the data currently held in the cache [3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Files matching target class:"
fd -t f 'JGroupsSlotStoreClusterExample.java|JGroupsSlots.java|SlotStoreAdaptor.java|.*Slots.*\.java' .

echo
echo "Target example relevant lines:"
target="$(fd -t f 'JGroupsSlotStoreClusterExample.java' . | head -n 1 || true)"
if [ -n "${target:-}" ]; then
  wc -l "$target"
  sed -n '1,220p' "$target" | cat -n
fi

echo
echo "Search relevant symbols:"
rg -n -C 4 'class JGroupsSlots|class SlotStoreAdaptor|ReplCache<|getL2Cache|getInternalMap|\.start\(\)|start\(\)' --type=java JavaResources resources test 2>/dev/null || true

Repository: jbosstm/quickstart

Length of output: 10334


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import tempfile, urllib.request, zipfile, io
urls = [
    "https://repo1.maven.org/maven2/org/jgroups/jgroups/5.3.8.Final/jgroups-5.3.8.Final.jar",
    "https://repo1.maven.org/maven2/org/jboss/narayana/ArjunaJTA/arjuna/7.3.5.Final-SNAPSHOT/arjuna-7.3.5.Final-SNAPSHOT.jar",
]
tmp = tempfile.TemporaryDirectory()
files = {}
for url in urls:
    path = url.split("/")[-1]
    filename = tmp.name + "/" + path
    urllib.request.urlretrieve(url, filename)
    files[path] = zipfile.ZipFile(filename)
for name, zf in files.items():
    print(f"\n=== {name} ===")
    for path in [
        "org/jgroups/blocks/ReplCache.class",
        "org/jgroups/blocks/Cache.class",
        "org/jboss/ats/internal/arjuna/objectstore/slot/jgroups/JGroupsSlots.class",
        "org/jboss/narayana/objectstore/slot/jgroups/JGroupsSlots.class",
    ]:
        if path in zf.namelist():
            print("contains", path)
            data = zf.read(path)
            # simple constant pool scanner for nearby method signatures
            out = data
            print("size bytes", len(data))
PY

echo
echo "Inspect parent/dependency versions:"
sed -n '1,180p' ArjunaJTA/object_store/pom.xml
sed -n '1,220p' pom.xml 2>/dev/null || true
sed -n '1,220p' ArjunaJTA/pom.xml 2>/dev/null || true
rg -n 'version\.org\.jgroups|jgroups-raft|org\.jboss\.narayana\.' -S pom.xml ArjunaJTA/object_store/pom.xml ArjunaJTA/pom.xml ArjunaJTA 2>/dev/null || true

Repository: jbosstm/quickstart

Length of output: 2572


Avoid using undocumented JGroups cache internals in the example.

getL2Cache() and Cache.getInternalMap() are accessor APIs intended for monitoring or demos. The direct cache.start() call also introduces ordering dependence on SlotStoreAdaptor; keep this example on the supported store startup path, or replace the cache inspection with supported diagnostics.

🤖 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
`@ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreClusterExample.java`
around lines 132 - 141, Update the startup and state-transfer logic around the
ReplCache usage to avoid direct calls to getL2Cache().getInternalMap() and
cache.start(). Use the supported SlotStoreAdaptor/store startup path and
supported diagnostics or callbacks to determine completion, preserving the
example’s state-transfer wait and cache-entry reporting behavior.

Comment on lines +183 to +185
} catch (Exception e) {
log("Error scanning recovery store: %s", e.getMessage());
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep the stack trace when the scan fails.

e.getMessage() can be null and it hides the failure location. A quickstart user then has no way to diagnose a store or serialization error.

♻️ Proposed change
         } catch (Exception e) {
             log("Error scanning recovery store: %s", e.getMessage());
+            e.printStackTrace();
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (Exception e) {
log("Error scanning recovery store: %s", e.getMessage());
}
} catch (Exception e) {
log("Error scanning recovery store: %s", e.getMessage());
e.printStackTrace();
}
🤖 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
`@ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreClusterExample.java`
around lines 183 - 185, Update the exception handler in
JGroupsSlotStoreClusterExample so the recovery-store scan failure logs the full
exception stack trace rather than only e.getMessage(). Preserve the existing
error context while passing the caught exception through the logger’s
throwable-aware API.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@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.

Actionable comments posted: 4

🤖 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.

Inline comments:
In `@ArjunaJTA/object_store/run-jgroups-cluster.sh`:
- Around line 27-30: The background node processes lack signal-safe cleanup. In
ArjunaJTA/object_store/run-jgroups-cluster.sh:27-30 and
ArjunaJTA/object_store/run-jgroups-raft-cluster.sh:28-31, install the existing
cleanup routine as an EXIT trap before or immediately after starting node1, and
add INT/TERM handlers that exit through the trap so each node process is
terminated and resources are released.

In
`@ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/ClusterExampleSupport.java`:
- Around line 49-56: Update ClusterExampleSupport.waitForNode1() to use a
bounded deadline while polling for node1.ready instead of waiting indefinitely.
When the timeout expires, log the failure and terminate with a nonzero result;
preserve the existing readiness wait and post-readiness delay.

In
`@ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreClusterExample.java`:
- Around line 68-89: Update setupStore in JGroupsRaftSlotStoreClusterExample to
configure the TCP stack through the Raft-specific jGroupsRaftConfigFileName
property, replacing the non-Raft setJGroupsConfigFileName call while preserving
the existing jgroups-raft-tcp-config.xml value.

In
`@ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreClusterExample.java`:
- Around line 89-102: Update the cache lifecycle around dataArrived.await in
JGroupsSlotStoreClusterExample so listener removal and cache.stop() always
execute in a finally block, including when await throws. Keep cache.stop() after
cache.start(), and preserve the existing transferred/timeout logging after
cleanup.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0286a822-5e0d-4b14-aa4c-271894d6a518

📥 Commits

Reviewing files that changed from the base of the PR and between 4b03a1d and 18ebb89.

📒 Files selected for processing (21)
  • ArjunaJTA/object_store/README.md
  • ArjunaJTA/object_store/pom.xml
  • ArjunaJTA/object_store/run-jgroups-cluster.sh
  • ArjunaJTA/object_store/run-jgroups-raft-cluster.sh
  • ArjunaJTA/object_store/run-jgroups-wal-recovery.sh
  • ArjunaJTA/object_store/run.sh
  • ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/ClusterExampleSupport.java
  • ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreClusterExample.java
  • ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreConfigExample.java
  • ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreExample.java
  • ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreClusterExample.java
  • ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreConfigExample.java
  • ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreExample.java
  • ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreWALRecoveryExample.java
  • ArjunaJTA/object_store/src/main/resources/jgroups-config.xml
  • ArjunaJTA/object_store/src/main/resources/jgroups-jbossts-properties.xml
  • ArjunaJTA/object_store/src/main/resources/jgroups-raft-config.xml
  • ArjunaJTA/object_store/src/main/resources/jgroups-raft-jbossts-properties.xml
  • ArjunaJTA/object_store/src/main/resources/jgroups-raft-tcp-config.xml
  • ArjunaJTA/object_store/src/main/resources/jgroups-tcp-config.xml
  • pom.xml

Comment on lines +27 to +30
echo "Starting node1 on port 7800..."
mvn -q exec:java -Dexec.mainClass=$MAIN_CLASS \
-Dexec.args="node1" -Djgroups.bind_port=7800 "${NARAYANA_VERSION_PARAM[@]}" &
PID1=$!

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Install signal-safe cleanup for the background node.

An interrupt or termination after node1 starts can bypass the normal cleanup block. Node1 can then keep its transport port and store resources active. Add an EXIT cleanup trap and signal handlers that exit through it.

  • ArjunaJTA/object_store/run-jgroups-cluster.sh#L27-L30: install the cleanup trap before or immediately after starting node1.
  • ArjunaJTA/object_store/run-jgroups-raft-cluster.sh#L28-L31: install the same cleanup trap for the Raft node1 process.
📍 Affects 2 files
  • ArjunaJTA/object_store/run-jgroups-cluster.sh#L27-L30 (this comment)
  • ArjunaJTA/object_store/run-jgroups-raft-cluster.sh#L28-L31
🤖 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 `@ArjunaJTA/object_store/run-jgroups-cluster.sh` around lines 27 - 30, The
background node processes lack signal-safe cleanup. In
ArjunaJTA/object_store/run-jgroups-cluster.sh:27-30 and
ArjunaJTA/object_store/run-jgroups-raft-cluster.sh:28-31, install the existing
cleanup routine as an EXIT trap before or immediately after starting node1, and
add INT/TERM handlers that exit through the trap so each node process is
terminated and resources are released.

Comment on lines +49 to +56
void waitForNode1() throws InterruptedException {
if (!isNode1()) {
log("Waiting for node1 to be ready...");
while (!new File("node1.ready").exists()) {
Thread.sleep(200);
}
Thread.sleep(1000);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Add a timeout to waitForNode1().

If node1 does not create node1.ready, node2 blocks indefinitely. Use a bounded wait and terminate with a nonzero result when the deadline expires.

🤖 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
`@ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/ClusterExampleSupport.java`
around lines 49 - 56, Update ClusterExampleSupport.waitForNode1() to use a
bounded deadline while polling for node1.ready instead of waiting indefinitely.
When the timeout expires, log the failure and terminate with a nonzero result;
preserve the existing readiness wait and post-readiness delay.

Comment on lines +68 to +89
private static void setupStore(ClusterExampleSupport support) {
JGroupsRaftStoreEnvironmentBean config = new JGroupsRaftStoreEnvironmentBean();
backingSlots = new JGroupsRaftSlots();

config.setJGroupsConfigFileName("jgroups-raft-tcp-config.xml");
config.setNodeAddress(support.nodeId());
config.setCacheName("raftClusterTxStore");
config.setClusterName("raftClusterTxStore");
config.setStoreDir("RaftStore-" + support.nodeId());
config.setBackingSlots(backingSlots);

if (support.isNode1()) {
// Node1 bootstraps a single-member cluster
config.setRaftMembers("node1");
}
// Other nodes join dynamically (no raftMembers set)

BeanPopulator.getDefaultInstance(ObjectStoreEnvironmentBean.class)
.setObjectStoreType(SlotStoreAdaptor.class.getName());
BeanPopulator.setBeanInstanceIfAbsent(
SlotStoreEnvironmentBean.class.getName(), config);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

bean_file="$(fd -a '^JGroupsRaftStoreEnvironmentBean\.java$' . | head -n1 || true)"
slots_file="$(fd -a '^JGroupsRaftSlots\.java$' . | head -n1 || true)"

printf 'Environment bean: %s\n' "${bean_file:-not found}"
printf 'Raft slots: %s\n' "${slots_file:-not found}"

if [[ -n "$bean_file" ]]; then
  rg -n -C3 'JGroupsConfigFileName|JGroupsRaftConfigFileName|jGroupsRaftConfigFileName' "$bean_file"
fi

if [[ -n "$slots_file" ]]; then
  rg -n -C5 'getJGroupsConfigFileName|getJGroupsRaftConfigFileName|jGroupsRaftConfigFileName' "$slots_file"
fi

Repository: jbosstm/quickstart

Length of output: 206


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Repository root: %s\n' "$(pwd)"
printf 'Tracked files matching example/snippet names:\n'
git ls-files | rg 'JGroupsRaftSlotStoreClusterExample|Raft|jgroups-raft|SlotStore' || true

printf '\nRelevant file around snippet:\n'
file="$(git ls-files | rg 'JGroupsRaftSlotStoreClusterExample\.java$' | head -n1 || true)"
printf 'File: %s\n' "${file:-not found}"
if [[ -n "$file" ]]; then
  wc -l "$file"
  sed -n '1,140p' "$file" | cat -n
fi

Repository: jbosstm/quickstart

Length of output: 6119


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Maven dependencies mentioning jgroups or narayana:\n'
git ls-files | rg '(^|/)(pom\.xml|.*\.properties)$' | xargs rg -n 'jgroups|Narayana|narayana|JGroups|Raft' || true

printf '\nLocal build artifacts / dependencies availability:\n'
mkdir -p /tmp/jgroups-check
cd /tmp/jgroups-check
mvn dependency:tree -DincludeArtifactIds=loggingcommons-logmanager || true

printf '\nSearch installed jars for JGroupsRaftSlots/JGroupsRaftStoreEnvironmentBean if present:\n'
if [[ -d "$HOME/.m2/repository" ]]; then
  find "$HOME/.m2/repository" -type f \( -name '*.jar' \) | while read -r jar; do
    if unzip -l "$jar" 2>/dev/null | rg -q 'JGroupsRaft(Slots|StoreEnvironmentBean)\.class'; then
      echo "JAR: $jar"
      unzip -l "$jar" | rg 'JGroupsRaft(Slots|StoreEnvironmentBean)\.class|jgroups.*raft|Raft.*ConfigFileName'
    fi
  done
else
  echo "No local Maven repository found"
fi

Repository: jbosstm/quickstart

Length of output: 50374


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Narayana object_store pom relevant sections:\n'
sed -n '1,140p' ArjunaJTA/object_store/pom.xml | cat -n

printf '\nAll tracked Raft property/config files:\n'
for f in ArjunaJTA/object_store/src/main/resources/*raft*tcp*.xml ArjunaJTA/object_store/src/main/resources/*raft*.xml; do
  [[ -f "$f" ]] && { echo "===== $f ====="; sed -n '1,220p' "$f" | cat -n; }
done

printf '\nAll tracked references to the two setters/properties:\n'
rg -n 'setJGroupsConfigFileName|setJGroupsRaftConfigFileName|getJGroupsConfigFileName|getJGroupsRaftConfigFileName|jGroupsRaftConfigFileName|JGroupsRaftConfigFileName' ArjunaJTA/object_store || true

Repository: jbosstm/quickstart

Length of output: 12257


🌐 Web query:

Narayana 7.3 JGroupsRaftStoreEnvironmentBean setJGroupsConfigFileName jGroupsRaftConfigFileName

💡 Result:

There is no standard class named JGroupsRaftStoreEnvironmentBean within the Narayana project codebase. Consequently, the methods setJGroupsConfigFileName and jGroupsRaftConfigFileName are not recognized members of the Narayana configuration system [1][2]. Narayana relies on various EnvironmentBean objects to handle configuration, which are typically populated using property keys defined by @PropertyPrefix annotations [3][4]. While Narayana utilizes JGroups for clustering, JGroups-Raft is a separate library maintained by the JGroups-Extras project [5][6]. If you are attempting to configure a storage solution involving consensus protocols in Narayana, the project often uses the ObjectStoreEnvironmentBean or specialized beans like RedisStoreEnvironmentBean (in certain experimental branches) for external storage backends [7][8]. Configuration for JGroups-related components is generally handled via standard JGroups XML configuration files, which can be specified according to the requirements of the specific JGroups implementation or protocol stack being used [5]. To verify configuration properties for any Narayana EnvironmentBean, it is recommended to examine the source code for the relevant bean class to identify its @PropertyPrefix and available setter methods [4]. You can browse the Narayana project repository directly to confirm if a specific feature or bean exists in the version you are using [1].

Citations:


🌐 Web query:

github jbosstm narayana JGroupsRaftSlots JGroupsRaftStoreEnvironmentBean setJGroupsRaftConfigFileName

💡 Result:

Based on an analysis of the JBoss Narayana (jbosstm/narayana) codebase and related technical documentation, there is no evidence of a class named JGroupsRaftSlots, JGroupsRaftStoreEnvironmentBean, or a method named setJGroupsRaftConfigFileName within the official Narayana project [1][2][3]. It appears there may be a confusion or mix-up in terminology or project scope: 1. JGroups Raft is a separate library (jgroups-extras/jgroups-raft) used for implementing the Raft consensus algorithm over JGroups [4]. It is frequently used with frameworks like Apache Camel (via the camel-jgroups-raft component) [5][6][7] or custom applications [8], but it is not a native part of the core Narayana transaction manager's object store configuration. 2. The Narayana project contains classes like ObjectStoreEnvironmentBean [1][9], which manage configuration for its internal object store (e.g., file-based, JDBC-based, or cache-based stores) [1]. These beans are configured using properties defined in the Narayana configuration, often loaded via a BeanPopulator [10]. If you are attempting to configure JGroups Raft for use alongside Narayana, you should refer to the documentation for JGroups Raft directly [11] or the specific integration framework you are using [5][12]. If this was expected as part of an internal Narayana API, it is possible the class names provided are either from a custom downstream extension, a different project, or contain typos.

Citations:


🌐 Web query:

jgroups-raft 1.1.4.Final JGroupsRaftSlots

💡 Result:

There is no class or component named JGroupsRaftSlots in the jgroups-raft library version 1.1.4.Final [1][2]. The jgroups-raft project is a library that implements the Raft consensus protocol within the JGroups framework [3][4]. Its core components include: - RaftHandle: The main entry point for users to interact with the Raft consensus, allowing for state changes and state machine registration [4][5]. - StateMachine: An interface implemented by users to define replicated state machines, which are updated by jgroups-raft during consensus events [4][5]. - Building Blocks: Pre-built components that use RaftHandle to provide specialized functionality, such as distributed counters, locks, or replicated hash maps [4][5]. - Protocol Stack: A JGroups protocol stack containing specific protocols like RAFT (log management/consensus), ELECTION (leader election), and REDIRECT [4][5]. The term slots or hash slots is frequently associated with other distributed systems, such as Redis-compatible clustering architectures (e.g., FrogDB or Garnet), which use hash slots to shard keys across nodes [6][7]. While JGroups contains a utility class called RequestTable, which manages a buffer of elements and provides methods to check for contiguous space, it is a general JGroups utility and not a specific component named JGroupsRaftSlots [8].

Citations:


🌐 Web query:

github narayana 7.3.5.Final-SNAPSHOT JGroupsRaftSlots JGroupsRaftStoreEnvironmentBean setJGroupsConfigFileName

💡 Result:

In the Narayana project, JGroups-Raft support is integrated as an object store mechanism, notably evidenced by the introduction of infrastructure such as JGroupsRaftStoreEnvironmentBean [1]. This bean is used to configure JGroups-Raft-based storage backends within the transaction recovery system [1]. The setJGroupsConfigFileName(String) method (or similar setter patterns for JGroups configuration) is a standard configuration approach for JGroups-based components, allowing you to specify the path to a JGroups XML configuration file [2][3][4]. Within the context of Narayana's JGroupsRaftStoreEnvironmentBean, this method is used to point the underlying JGroups channel to the appropriate XML configuration [2][3], which defines the Raft protocol stack (e.g., raft.RAFT, raft.ELECTION) [2][3][5]. If you are working with version 7.3.5.Final-SNAPSHOT or similar recent releases, configuration for these environment beans is typically handled via the BeanPopulator utility [6][7], which initializes the beans from property files or system properties [6]. When programmatically configuring the bean in your code, you would use an instance of JGroupsRaftStoreEnvironmentBean and call setJGroupsConfigFileName to specify your JGroups configuration resource [2][3]. For definitive usage, please check the source code in the ArjunaCore module of the Narayana repository (specifically under com.arjuna.ats.internal.arjuna.objectstore.slot.jgroups) for the exact method signature of JGroupsRaftStoreEnvironmentBean [1].

Citations:


🌐 Web query:

github jbosstm narayana "class JGroupsRaftStoreEnvironmentBean" "jGroupsRaftConfigFileName"

💡 Result:

A search of the JBoss Narayana (jbosstm/narayana) codebase and documentation does not reveal a class named JGroupsRaftStoreEnvironmentBean or a property named jGroupsRaftConfigFileName [1][2][3]. While Narayana uses JGroups for various distributed transaction features, and JGroups Raft is a distinct library for distributed consensus [4][5], there is no evidence that the specific class or configuration property mentioned exists within the Narayana project. The standard configuration class for object store settings in Narayana is ObjectStoreEnvironmentBean [1][3][6], which handles properties for various storage implementations but does not include JGroups Raft-specific configuration fields [1][7][8].

Citations:


🌐 Web query:

github narayana JGroupsRaftStoreEnvironmentBean "void setJGroupsRaftConfigFileName"

💡 Result:

There is no evidence of a class named "JGroupsRaftStoreEnvironmentBean" or a method named "setJGroupsRaftConfigFileName" within the JBoss Narayana codebase [1][2][3]. The Narayana project primarily utilizes "EnvironmentBean" classes (such as ObjectStoreEnvironmentBean) for configuration management [1][4], and these are typically configured via property files or the BeanPopulator utility, rather than through JGroups Raft-specific configuration methods [5]. It is possible that you may be conflating Narayana's configuration classes with the "JGroups Raft" library (often used for consensus in distributed systems) or a specific component like Apache Camel's JGroups-Raft component [6][7][8]. For instance, Apache Camel's JGroups-Raft component uses a configuration property often referred to as "channelProperties" (which defaults to "raft.xml") to specify JGroups Raft configuration, but it does not have a method named setJGroupsRaftConfigFileName [7][8][9].

Citations:


🌐 Web query:

github "JGroupsRaftStoreEnvironmentBean" "jGroupsRaftConfigFileName"

💡 Result:

The term "JGroupsRaftStoreEnvironmentBean" does not appear in official JGroups Raft or Apache Camel JGroups-Raft documentation [1][2][3][4]. It is likely a custom class name specific to a particular project's implementation rather than a standard library component. In the context of JGroups Raft and its integration with Apache Camel, configuration is typically handled as follows: 1. JGroups Raft Configuration: The underlying JGroups Raft protocol stack is configured via an XML file (commonly named raft.xml), which defines protocols like UDP, PING, GMS, RAFT, and others [1]. 2. Camel JGroups-Raft Component: When using the Apache Camel JGroups-Raft component, the configuration properties for the RaftHandle JChannel are specified using the channelProperties option (often defaulting to raft.xml) [5][3][6]. If you are encountering "JGroupsRaftStoreEnvironmentBean" in a codebase, it is recommended to search the specific repository for that class definition to understand its purpose, as it is not part of the standard JGroups-Raft or Camel JGroups-Raft APIs [3][4].

Citations:


🌐 Web query:

repo:jboss-transaction-manager/narayana "JGroupsRaftStoreEnvironmentBean"

💡 Result:

There is no class named JGroupsRaftStoreEnvironmentBean in the official JBoss Narayana repository [1]. Narayana is a transaction management toolkit that supports various object store implementations for transaction logging, such as file-based, JDBC, and Redis stores [2][3]. While Narayana integrates with JGroups for various distributed messaging and coordination needs, and JGroups itself provides a separate library called jgroups-raft for implementing the Raft consensus algorithm [4], there is no native Narayana environment bean under the name JGroupsRaftStoreEnvironmentBean. If you encountered this name in documentation or code, it may be a custom internal class, a misnomer, or related to a third-party extension rather than the core Narayana codebase. Narayana's configuration is managed through standard environment beans (e.g., ObjectStoreEnvironmentBean, CoordinatorEnvironmentBean, CoreEnvironmentBean) which allow you to specify the store implementation type [5][6][7].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Local Maven repository jars for arjunacore containing JGroupsRaftStoreEnvironmentBean or JGroupsRaftSlots:\n'
if [[ -d "$HOME/.m2/repository" ]]; then
  find "$HOME/.m2/repository" -path '*arjunacore*' -name '*.jar' | while read -r jar; do
    if unzip -l "$jar" 2>/dev/null | rg -q 'JGroupsRaft(Slots|StoreEnvironmentBean)\.class'; then
      echo "JAR: $jar"
      unzip -l "$jar" | rg 'JGroupsRaft(Slots|StoreEnvironmentBean)\.class|jgroups.*raft|Raft.*ConfigFileName|setJGroupsRa' || true
    fi
  done
fi

printf '\nMaven search metadata for narayana release candidates/versions:\n'
curl -fsSL 'https://repo1.maven.org/maven2/org/jboss/narayana/arjuna/maven-metadata.xml' | sed -n '1,220p' || true

Repository: jbosstm/quickstart

Length of output: 377


🌐 Web query:

jgroups-raft 1.1.4.Final "jGroupsRaftConfigFileName"

💡 Result:

There is no standard configuration property or setting named jGroupsRaftConfigFileName in the JGroups-Raft library (version 1.1.4.Final) [1][2][3]. In JGroups-Raft, cluster membership and protocol configurations are typically handled through standard JGroups XML configuration files [4][5]. Users define their Raft configuration—including the <raft.RAFT> and <raft.ELECTION> protocols—within an XML file (often named raft.xml by convention) [4][5][6][7]. If you are encountering the term jGroupsRaftConfigFileName, it may originate from: 1. Custom Integration Code: It could be a variable or property name defined in your specific application or framework to track the path to your raft.xml file. 2. Third-Party Integrations: Integrations such as Apache Camel's jgroups-raft component have their own configuration properties for the channel [8]. For instance, Apache Camel uses camel.component.jgroups-raft.channel-properties to specify the configuration file for the RaftHandle JChannel, which defaults to raft.xml [8]. To configure your Raft-enabled JChannel, you pass the path of your XML configuration file to the JGroups API (e.g., when instantiating a JChannel or a RaftHandle), rather than using a global property with that specific name [4][8][5].

Citations:


Use the Raft-specific filename property for the TCP stack.

arjuna-jboss-properties defines JGroupsRaftStoreEnvironmentBean.jGroupsRaftConfigFileName for Raft, and this example configures the TCP file via that property. The programmatic config still uses setJGroupsConfigFileName, which only sets the non-Raft JGroups path. Node1 and Node2 can fail to load the TCP Raft stack from jgroups-raft-tcp-config.xml.

Proposed fix
-        config.setJGroupsConfigFileName("jgroups-raft-tcp-config.xml");
+        config.setJGroupsRaftConfigFileName("jgroups-raft-tcp-config.xml");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private static void setupStore(ClusterExampleSupport support) {
JGroupsRaftStoreEnvironmentBean config = new JGroupsRaftStoreEnvironmentBean();
backingSlots = new JGroupsRaftSlots();
config.setJGroupsConfigFileName("jgroups-raft-tcp-config.xml");
config.setNodeAddress(support.nodeId());
config.setCacheName("raftClusterTxStore");
config.setClusterName("raftClusterTxStore");
config.setStoreDir("RaftStore-" + support.nodeId());
config.setBackingSlots(backingSlots);
if (support.isNode1()) {
// Node1 bootstraps a single-member cluster
config.setRaftMembers("node1");
}
// Other nodes join dynamically (no raftMembers set)
BeanPopulator.getDefaultInstance(ObjectStoreEnvironmentBean.class)
.setObjectStoreType(SlotStoreAdaptor.class.getName());
BeanPopulator.setBeanInstanceIfAbsent(
SlotStoreEnvironmentBean.class.getName(), config);
}
private static void setupStore(ClusterExampleSupport support) {
JGroupsRaftStoreEnvironmentBean config = new JGroupsRaftStoreEnvironmentBean();
backingSlots = new JGroupsRaftSlots();
config.setJGroupsRaftConfigFileName("jgroups-raft-tcp-config.xml");
config.setNodeAddress(support.nodeId());
config.setCacheName("raftClusterTxStore");
config.setClusterName("raftClusterTxStore");
config.setStoreDir("RaftStore-" + support.nodeId());
config.setBackingSlots(backingSlots);
if (support.isNode1()) {
// Node1 bootstraps a single-member cluster
config.setRaftMembers("node1");
}
// Other nodes join dynamically (no raftMembers set)
BeanPopulator.getDefaultInstance(ObjectStoreEnvironmentBean.class)
.setObjectStoreType(SlotStoreAdaptor.class.getName());
BeanPopulator.setBeanInstanceIfAbsent(
SlotStoreEnvironmentBean.class.getName(), config);
}
🤖 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
`@ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreClusterExample.java`
around lines 68 - 89, Update setupStore in JGroupsRaftSlotStoreClusterExample to
configure the TCP stack through the Raft-specific jGroupsRaftConfigFileName
property, replacing the non-Raft setJGroupsConfigFileName call while preserving
the existing jgroups-raft-tcp-config.xml value.

Comment on lines +89 to +102
CountDownLatch dataArrived = new CountDownLatch(1);
ReplCache.ChangeListener listener = dataArrived::countDown;
cache.addChangeListener(listener);
cache.start();

boolean transferred = dataArrived.await(10, TimeUnit.SECONDS);
int entryCount = cache.getL2Cache().getSize();
cache.removeChangeListener(listener);
cache.stop();
if (transferred) {
support.log("State transfer complete: %d cache entries", entryCount);
} else {
support.log("WARN: state transfer timed out after 10 s (%d cache entries)", entryCount);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '80,105p' \
  ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreClusterExample.java

Repository: jbosstm/quickstart

Length of output: 1547


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreClusterExample.java"

echo "Try-catch/finally context:"
sed -n '1,150p' "$file" | cat -n

echo
echo "ReplCache references in file:"
rg -n "ReplCache|addChangeListener|removeChangeListener|stop\(|start\(" "$file"

Repository: jbosstm/quickstart

Length of output: 6492


🌐 Web query:

Java CountDownLatch await throws InterruptedException Java 8 or later Javadoc

💡 Result:

In Java 8 and all subsequent versions (such as Java 11, 22, 24, and 26), the await methods of java.util.concurrent.CountDownLatch are documented to throw InterruptedException [1][2][3][4]. The Javadoc specifies that InterruptedException is thrown under the following conditions [1][2][3]: - The current thread has its interrupted status set upon entry to the method [1][5][6]. - The current thread is interrupted while it is waiting [1][2][3]. When this exception is thrown, the method also ensures that the current thread's interrupted status is cleared [1][2][3]. This behavior is consistent across both the no-argument await method and the timed await(long timeout, TimeUnit unit) method [1][2][3].

Citations:


🌐 Web query:

JGroups ReplCache start stop addChangeListener removeChangeListener Javadoc

💡 Result:

JGroups ReplCache is a distributed cache implementation that allows for per-item replication factors [1][2][3]. Based on the available Javadoc and project documentation, here is the information regarding the requested methods. Start and Stop ReplCache does not provide explicit start or stop methods directly in its public API to manage its lifecycle [1][2][4]. Instead, the cache is initialized via its constructor, which typically accepts a configuration (such as an XML properties string) and a cluster name [5][6]. Membership and lifecycle management are generally handled by the underlying JGroups channel, which is configured via these properties [7][3]. ChangeListener Methods ReplCache includes methods to manage listeners for cache changes, specifically through the Cache.ChangeListener interface [2][5][6][8]. The relevant methods are: void addChangeListener(ReplCache.ChangeListener l): Registers a listener to receive notifications about cache changes [8]. void removeChangeListener(ReplCache.ChangeListener l): Unregisters a previously added listener [8]. These methods allow users to monitor modifications within the cache. The ReplCache class itself implements the MembershipListener and Cache.ChangeListener interfaces [2][5][6], facilitating its role as a clustered, partitioned, and replicated cache [7][3]. General Usage The core API for interacting with the cache is simple and consists of put, get, and remove methods [3]. For example, the put method allows you to specify a replication count, defining how many nodes should store the key-value pair [1][2][3]: void put(K key, V val, short repl_count, long timeout) A replication count of -1 stores the item on all nodes, 1 stores it on a single node, and K > 1 stores it on a subset of nodes [1][6][3]. For the most accurate technical details specific to your JGroups version, please refer to the Javadoc corresponding to your implementation, as API signatures for advanced features can vary across versions (e.g., JGroups 3.x vs 4.x vs 5.x) [2][4][6].

Citations:


Release the pre-started cache on every exit path.

If dataArrived.await(10, TimeUnit.SECONDS) throws after cache.start(), removeChangeListener(listener) and cache.stop() do not run. Move those cleanups into a finally block and stop the cache only after it has started.

🤖 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
`@ArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreClusterExample.java`
around lines 89 - 102, Update the cache lifecycle around dataArrived.await in
JGroupsSlotStoreClusterExample so listener removal and cache.stop() always
execute in a finally block, including when await throws. Keep cache.stop() after
cache.start(), and preserve the existing transferred/timeout logging after
cleanup.

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