Jbtm 4038 JGroups and JGroups+RAFT object store examples - #775
Conversation
… configure the store and run a transaction.
📝 WalkthroughWalkthroughChangesAdds 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
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
Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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
📒 Files selected for processing (19)
ArjunaJTA/object_store/README.mdArjunaJTA/object_store/pom.xmlArjunaJTA/object_store/run-jgroups-cluster.shArjunaJTA/object_store/run-jgroups-raft-cluster.shArjunaJTA/object_store/run-jgroups-wal-recovery.shArjunaJTA/object_store/run.shArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreClusterExample.javaArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreConfigExample.javaArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreExample.javaArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreClusterExample.javaArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreConfigExample.javaArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreExample.javaArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreWALRecoveryExample.javaArjunaJTA/object_store/src/main/resources/jgroups-config.xmlArjunaJTA/object_store/src/main/resources/jgroups-jbossts-properties.xmlArjunaJTA/object_store/src/main/resources/jgroups-raft-config.xmlArjunaJTA/object_store/src/main/resources/jgroups-raft-jbossts-properties.xmlArjunaJTA/object_store/src/main/resources/jgroups-raft-tcp-config.xmlArjunaJTA/object_store/src/main/resources/jgroups-tcp-config.xml
| 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 |
There was a problem hiding this comment.
🎯 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.
| 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()); |
There was a problem hiding this comment.
🩺 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=javaRepository: 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:
- 1: http://jgroups.org/javadoc/org/jgroups/blocks/ReplCache.html
- 2: http://jgroups.org/javadoc/org/jgroups/blocks/Cache.html
- 3: https://www.javatips.net/api/JGroups-master/src/org/jgroups/demos/ReplCacheDemo.java
- 4: http://www.jgroups.org/javadoc5/org/jgroups/blocks/ReplCache.html
- 5: https://docs.jboss.org/jbossas/javadoc/7.1.2.Final/org/jgroups/blocks/ReplCache.html
- 6: http://www.jgroups.org/javadoc4/org/jgroups/blocks/ReplCache.html
- 7: http://www.jgroups.org/javadoc3/org/jgroups/blocks/ReplCache.html
- 8: https://www.javatips.net/api/JGroups-master/src/org/jgroups/blocks/Cache.java
- 9: http://www.jgroups.org/javadoc4/org/jgroups/blocks/Cache.html
- 10: https://docs.huihoo.com/javadoc/jboss/7.1.2/org/jgroups/blocks/Cache.html
🏁 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 || trueRepository: 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 || trueRepository: 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.
| } catch (Exception e) { | ||
| log("Error scanning recovery store: %s", e.getMessage()); | ||
| } |
There was a problem hiding this comment.
📐 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.
| } 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.
|
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. |
There was a problem hiding this comment.
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
📒 Files selected for processing (21)
ArjunaJTA/object_store/README.mdArjunaJTA/object_store/pom.xmlArjunaJTA/object_store/run-jgroups-cluster.shArjunaJTA/object_store/run-jgroups-raft-cluster.shArjunaJTA/object_store/run-jgroups-wal-recovery.shArjunaJTA/object_store/run.shArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/ClusterExampleSupport.javaArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreClusterExample.javaArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreConfigExample.javaArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsRaftSlotStoreExample.javaArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreClusterExample.javaArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreConfigExample.javaArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreExample.javaArjunaJTA/object_store/src/main/java/org/jboss/narayana/jta/quickstarts/JGroupsSlotStoreWALRecoveryExample.javaArjunaJTA/object_store/src/main/resources/jgroups-config.xmlArjunaJTA/object_store/src/main/resources/jgroups-jbossts-properties.xmlArjunaJTA/object_store/src/main/resources/jgroups-raft-config.xmlArjunaJTA/object_store/src/main/resources/jgroups-raft-jbossts-properties.xmlArjunaJTA/object_store/src/main/resources/jgroups-raft-tcp-config.xmlArjunaJTA/object_store/src/main/resources/jgroups-tcp-config.xmlpom.xml
| 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=$! |
There was a problem hiding this comment.
🩺 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.
| 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); | ||
| } |
There was a problem hiding this comment.
🩺 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.
| 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); | ||
| } |
There was a problem hiding this comment.
🎯 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"
fiRepository: 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
fiRepository: 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"
fiRepository: 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 || trueRepository: 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:
- 1: https://github.com/jbosstm/narayana
- 2: https://github.com/jbosstm/narayana/
- 3: https://docs.redhat.com/en/documentation/red_hat_fuse/7.3/html/apache_karaf_transaction_guide/configuring-narayana
- 4: https://lairdnelson.wordpress.com/2020/03/11/configuring-narayana/
- 5: https://jgroups-extras.github.io/jgroups-raft/manual/index.html
- 6: https://github.com/jgroups-extras/jgroups-raft
- 7: https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/ObjectStoreEnvironmentBean.java
- 8: https://github.com/jbosstm/narayana/blob/JBTM-3762/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/objectstore/RedisStoreTest.java
🌐 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:
- 1: https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/ObjectStoreEnvironmentBean.java
- 2: https://github.com/jbosstm/narayana
- 3: https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/arjPropertyManager.java
- 4: https://github.com/jgroups-extras/jgroups-raft
- 5: https://camel.apache.org/components/4.14.x/jgroups-raft-component.md
- 6: https://github.com/apache/camel/blob/master/components/camel-jgroups-raft/src/main/docs/jgroups-raft-component.adoc
- 7: https://javadoc.io/static/org.apache.camel/camel-jgroups-raft/4.0.0/org/apache/camel/component/jgroups/raft/JGroupsRaftComponent.html
- 8: https://gist.github.com/qinqd/defa6c8088ef3cf50b6794cb76c4a0dc
- 9: https://docs.jboss.org/jbosstm/4.17.17.Final/api/jta/com/arjuna/ats/arjuna/common/ObjectStoreEnvironmentBean.html
- 10: https://github.com/jbosstm/narayana/blob/master/common/classes/com/arjuna/common/internal/util/propertyservice/BeanPopulator.java
- 11: https://jgroups-extras.github.io/jgroups-raft/manual/index.html
- 12: https://camel.apache.org/components/4.14.x/jgroups-raft-component.html
🌐 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:
- 1: https://github.com/jgroups-extras/jgroups-raft/releases/tag/jgroups-raft-1.1.4.Final
- 2: https://javadoc.io/doc/org.jgroups/jgroups-raft/latest/index.html
- 3: https://github.com/jgroups-extras/jgroups-raft
- 4: https://jgroups-extras.github.io/jgroups-raft/manual/index.html
- 5: https://github.com/jgroups-extras/jgroups-raft/blob/main/doc/manual/overview.adoc
- 6: https://frogdb.dev/operations/clustering/
- 7: https://microsoft.github.io/garnet/docs/commands/cluster
- 8: http://jgroups.org/javadoc/org/jgroups/util/RequestTable.html
🌐 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:
- 1: jbosstm/narayana@7.3.3.Final...7.3.4.Final
- 2: https://belaban.github.io/jgroups-raft/manual/index.html
- 3: https://jgroups-extras.github.io/jgroups-raft/manual/index.html
- 4: http://jgroups.org/javadoc/org/jgroups/conf/ConfiguratorFactory.html
- 5: https://gist.github.com/qinqd/defa6c8088ef3cf50b6794cb76c4a0dc
- 6: https://github.com/jbosstm/narayana/blob/cc46def573a1a0692bd531aaa0cc39c7a4b52a41/common/classes/com/arjuna/common/internal/util/propertyservice/BeanPopulator.java
- 7: https://github.com/jbosstm/narayana/blob/JBTM-3762/ArjunaCore/arjuna/tests/classes/com/hp/mwtests/ts/arjuna/objectstore/RedisStoreTest.java
🌐 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:
- 1: https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/ObjectStoreEnvironmentBean.java
- 2: https://github.com/jbosstm/narayana
- 3: https://github.com/jbosstm/narayana/blob/cc46def573a1a0692bd531aaa0cc39c7a4b52a41/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/ObjectStoreEnvironmentBean.java
- 4: https://jgroups-extras.github.io/jgroups-raft/manual/index.html
- 5: https://github.com/jgroups-extras/jgroups-raft
- 6: https://docs.jboss.org/jbosstm/4.17.17.Final/api/jta/com/arjuna/ats/arjuna/common/ObjectStoreEnvironmentBean.html
- 7: https://docs.jboss.org/jbosstm/5.0.0.Final/api/jta/com/arjuna/ats/arjuna/common/ObjectStoreEnvironmentBean.html
- 8: https://javadoc.io/static/org.jboss.narayana.jta/narayana-jta/5.9.8.Final/com/arjuna/ats/arjuna/common/ObjectStoreEnvironmentBeanMBean.html
🌐 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:
- 1: https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/ObjectStoreEnvironmentBean.java
- 2: https://github.com/jbosstm/narayana
- 3: https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/arjPropertyManager.java
- 4: https://docs.jboss.org/jbosstm/4.17.17.Final/api/jta/com/arjuna/ats/arjuna/common/ObjectStoreEnvironmentBean.html
- 5: https://github.com/jbosstm/narayana/blob/master/common/classes/com/arjuna/common/internal/util/propertyservice/BeanPopulator.java
- 6: https://jgroups-extras.github.io/jgroups-raft/manual/index.html
- 7: https://camel.apache.org/components/4.14.x/jgroups-raft-component.md
- 8: https://javadoc.io/static/org.apache.camel/camel-jgroups-raft/4.0.0/org/apache/camel/component/jgroups/raft/JGroupsRaftComponent.html
- 9: https://camel.apache.org/components/4.14.x/jgroups-raft-component.html
🌐 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:
- 1: https://jgroups-extras.github.io/jgroups-raft/manual/index.html
- 2: https://github.com/belaban/jgroups-raft
- 3: https://camel.apache.org/components/next/jgroups-raft-component.html
- 4: https://javadoc.io/static/org.apache.camel/camel-jgroups-raft/4.0.0/org/apache/camel/component/jgroups/raft/JGroupsRaftComponent.html
- 5: https://camel.apache.org/camel-spring-boot/next/starters/jgroups-raft.html
- 6: https://camel.apache.org/components/4.18.x/jgroups-raft-component.md
🌐 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:
- 1: https://github.com/jbosstm/narayana
- 2: https://www.narayana.io/narayana-features/
- 3: https://github.com/jbosstm/narayana/blob/JBTM-3762/redis-demo/redis-store-demo.md
- 4: https://github.com/jgroups-extras/jgroups-raft
- 5: https://github.com/jbosstm/narayana/blob/master/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/ObjectStoreEnvironmentBean.java
- 6: https://github.com/jbosstm/narayana/blob/main/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/CoordinatorEnvironmentBean.java
- 7: https://github.com/jbosstm/narayana/blob/main/ArjunaCore/arjuna/classes/com/arjuna/ats/arjuna/common/CoreEnvironmentBean.java
🏁 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' || trueRepository: 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:
- 1: https://github.com/jgroups-extras/jgroups-raft
- 2: https://javadoc.io/doc/org.jgroups/jgroups-raft/latest/index.html
- 3: https://github.com/jgroups-extras/jgroups-raft/releases/tag/jgroups-raft-1.1.4.Final
- 4: https://jgroups-extras.github.io/jgroups-raft/manual/index.html
- 5: https://belaban.github.io/jgroups-raft/manual/index.html
- 6: https://github.com/zendesk/maxwell/blob/08a7bd5079eeae0f7a8f322dc12b90a02ceea2e0/raft.xml.example
- 7: https://maxwells-daemon.io/high_availability/
- 8: https://camel.apache.org/components/next/jgroups-raft-component.md
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.
| 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.
| 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); | ||
| } |
There was a problem hiding this comment.
🩺 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.javaRepository: 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:
- 1: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CountDownLatch.html
- 2: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/CountDownLatch.html
- 3: https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/util/concurrent/CountDownLatch.html
- 4: https://docs.oracle.com/en/java/javase/26/docs/api/java.base/java/util/concurrent/CountDownLatch.html
- 5: https://javadoc.scijava.org/Java/java/util/concurrent/CountDownLatch.html
- 6: https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/CountDownLatch.html
🌐 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:
- 1: http://jgroups.org/javadoc/org/jgroups/blocks/ReplCache.html
- 2: http://www.jgroups.org/javadoc4/org/jgroups/blocks/ReplCache.html
- 3: http://www.jgroups.org/replcache/replcache.html
- 4: http://www.jgroups.org/javadoc5/org/jgroups/blocks/ReplCache.html
- 5: https://docs.jboss.org/jbossas/javadoc/7.1.2.Final/org/jgroups/blocks/ReplCache.html
- 6: http://www.jgroups.org/javadoc-3.x/org/jgroups/blocks/ReplCache.html
- 7: http://www.jgroups.org/replcache.html
- 8: http://www.jgroups.org/javadoc3/index.html?org%2Fjgroups%2Fblocks%2FReplCache.html=
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.
https://issues.redhat.com/browse/JBTM-4038
JDK25