diff -Nru libjgroups-java-2.7.0.GA/bin/clusterperformancetest.sh libjgroups-java-2.12.2.Final/bin/clusterperformancetest.sh
--- libjgroups-java-2.7.0.GA/bin/clusterperformancetest.sh 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/clusterperformancetest.sh 1970-01-01 00:00:00.000000000 +0000
@@ -1,90 +0,0 @@
-#!/bin/bash
-#Script file used for automated performance tests. Prior to running this script
-#user should use org.jgroups.tests.perf.PerformanceTestGenerator to generate
-#performance tests input files.
-#
-#For a succesful performance test running user should ensure the following:
-# - can log into all machines listed in CLUSTER_NODES variable
-# - CLASSPATH variable points to existing lib files
-# - CONFIG_FILES is initialized to proper performance tests input files
-# - JGROUPS_CONFIG_FILE is initialized to an existing JGroups stack conf file
-
-#lists all the computer nodes used for performance tests
-CLUSTER_NODES=( cluster01.qa.atl.jboss.com cluster02.qa.atl.jboss.com cluster03.qa.atl.jboss.com cluster04.qa.atl.jboss.com cluster05.qa.atl.jboss.com cluster06.qa.atl.jboss.com cluster07.qa.atl.jboss.com cluster08.qa.atl.jboss.com )
-
-USERID=bela
-
-
-#classpath for performance tests
-CLASSPATH='commons-logging.jar:log4j-1.2.6.jar:concurrent.jar:jgroups-all.jar'
-
-#finds test configuration files
-#note the running directory of this script and make sure that find command can
-#actually find configuration files
-CONFIG_FILES=`find . -name 'config_*.txt'`
-
-#JGroups configuration stack used in performance tests
-JGROUPS_CONFIG_FILE="/home/${USERID}/udp.xml"
-#JGROUPS_CONFIG_FILE="/home/${USERID}/tcp-nio.xml"
-
-#sleeptime between performance test rounds (should be big enough to prevent test
-#overlapping)
-SLEEP_TIME=30
-
-LOGIN_COMMAND='ssh -i rgreathouse@jboss.com.id_dsa vblagojevic@'
-
-JVM_COMMAND='/opt/jdk1.5.0_06/bin/java -Djava.net.preferIPv4Stack=true'
-
-LOGIN_COMMAND="${USERID}@"
-
-JVM_COMMAND='java -Djava.net.preferIPv4Stack=true'
-
-JVM_PARAM="-Xmx500M -Xms500M -XX:NewRatio=1 -XX:+AggressiveHeap -XX:+DisableExplicitGC -XX:CompileThreshold=100 -Dbind.address=\${MYTESTIP_1}"
-
-#verify that we found configuration files
-config_file_count=${#CONFIG_FILES[*]}
-if [ $config_file_count -le "0" ] ; then
- echo Did not find performance test configuration files!
- exit
-fi
-
-echo "starting performance tests..."
-node_count=${#CLUSTER_NODES[@]}
-for file in $CONFIG_FILES;
-do
- num_senders_line=`grep num_senders $file`
- num_senders=${num_senders_line:12}
-
- num_members_line=`grep num_members $file`
- num_members=${num_members_line:12}
-
- sender_count=1
- sender_or_receiver=" -sender "
- echo "starting performance test round for $file..."
- for (( i = 0 ; i < node_count ; i++ ))
- do
- node=${CLUSTER_NODES[$i]}
- if [ $sender_count -le $num_senders ] ; then
- let "sender_count++"
- else
- sender_or_receiver=" -receiver "
- fi
- let j=$i+1
- if [ $j -eq $node_count ] ; then
- SSH_CMD="ssh"
- output_file="-f result-${file#.*/}"
- else
- SSH_CMD="ssh -f"
- output_file=""
- fi
- args="-config $file -props $JGROUPS_CONFIG_FILE $sender_or_receiver $output_file"
- final_command="$SSH_CMD $LOGIN_COMMAND$node $JVM_COMMAND $JVM_PARAM org.jgroups.tests.perf.Test $args > /dev/null"
- echo starting $final_command on $node
- $final_command
- sleep 5
- done
- echo "Tests round is now running, waiting $SLEEP_TIME seconds for this test round to finish..."
- sleep $SLEEP_TIME
-done
-
-
diff -Nru libjgroups-java-2.7.0.GA/bin/concurrent.sh libjgroups-java-2.12.2.Final/bin/concurrent.sh
--- libjgroups-java-2.7.0.GA/bin/concurrent.sh 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/concurrent.sh 2011-10-18 11:22:35.000000000 +0000
@@ -1,37 +1,12 @@
#!/bin/bash
-BIN=`dirname $0`
-
-LIB=$BIN/../lib
-
-LIBS=$LIB/commons-logging.jar
-
-CLASSPATH=$BIN/../classes:$CLASSPATH:$LIBS
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false;
-case "`uname`" in
- CYGWIN*)
- cygwin=true
- ;;
-esac
-
-if [ $cygwin = "true" ]; then
- CP=`cygpath -wp $CLASSPATH`
-else
- CP=$CLASSPATH
-fi
-
-#java -classpath $CP -Dbind.address=192.168.2.5 org.jgroups.demos.Draw -props /home/bela/udp.xml &
-#sleep 5
-
count=0
while [ $count -lt 20 ]
do
echo "Starting Draw instance #$count"
# change the IP address to your system
- java -classpath $CP -Dbind.address=192.168.1.5 org.jgroups.demos.Draw -props /home/bela/udp.xml &
+ jgroups.sh org.jgroups.demos.Draw -props /home/bela/udp.xml -name $count &
# sleep 1
count=$(($count+1))
done
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/bin/draw.bat libjgroups-java-2.12.2.Final/bin/draw.bat
--- libjgroups-java-2.7.0.GA/bin/draw.bat 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/draw.bat 2011-10-18 11:22:35.000000000 +0000
@@ -1,7 +1,7 @@
@rem Convenience launcher for the Draw demo (contributed by Laran Evans lc278@cornell.edu)
@echo off
-set CPATH=../classes;../conf;../lib/commons-logging.jar;../lib/log4j-1.2.6.jar;../lib/concurrent.jar
+set CPATH=../classes;../conf;
set JAVA_OPTS=
if -debug==%1 set JAVA_OPTS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_shmem,server=y,suspend=y,address=jgc1
@@ -15,7 +15,7 @@
set PROPS=%PROPS%:UNICAST(timeout=600,1200,2400,4800)
set PROPS=%PROPS%:pbcast.STABLE(desired_avg_gossip=20000)
set PROPS=%PROPS%:FRAG(frag_size=8096;down_thread=false;up_thread=false)
-set PROPS=%PROPS%:pbcast.GMS(join_timeout=5000;shun=false;print_local_addr=true)
+set PROPS=%PROPS%:pbcast.GMS(join_timeout=5000;print_local_addr=true)
@echo on
java -classpath %CPATH% %JAVA_OPTS% org.jgroups.demos.Draw -props %PROPS%
diff -Nru libjgroups-java-2.7.0.GA/bin/drawnio.bat libjgroups-java-2.12.2.Final/bin/drawnio.bat
--- libjgroups-java-2.7.0.GA/bin/drawnio.bat 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/drawnio.bat 1970-01-01 00:00:00.000000000 +0000
@@ -1,13 +0,0 @@
-@rem Convenience launcher for the Draw demo (contributed by Laran Evans lc278@cornell.edu)
-@echo off
-
-set CPATH=../classes;../conf;../lib/commons-logging.jar;../lib/log4j.jar;../lib/log4j-1.2.6.jar;../lib/concurrent.jar;../conf/log4j.properties
-
-set JAVA_OPTS=
-if -debug==%1 set JAVA_OPTS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_shmem,server=y,suspend=y,address=jgc1
-
-if "%LOCALHOSTIP%"=="" echo Warning: You should set environment variable 'LOCALHOSTIP' to your local ip address before running this script.
-if "%LOCALHOSTIP%"=="" set LOCALHOSTIP=192.168.1.103
-
-@echo on
-java -classpath %CPATH% %JAVA_OPTS% -Djgroups.bind_addr=%LOCALHOSTIP% -Djgroups.tcpping.initial_hosts=%LOCALHOSTIP%[7800],%LOCALHOSTIP%[7801] org.jgroups.demos.Draw -props c:\jboss\JGroups\conf\tcp-nio.xml
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/bin/draw.sh libjgroups-java-2.12.2.Final/bin/draw.sh
--- libjgroups-java-2.7.0.GA/bin/draw.sh 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/draw.sh 2011-10-18 11:22:35.000000000 +0000
@@ -24,7 +24,7 @@
done
-CLASSPATH="$relpath/../classes$SEP$relpath/../conf$SEP$relpath/../lib/commons-logging.jar$SEP$relpath/../lib/log4j-1.2.6.jar$SEP$relpath/../lib/concurrent.jar"
+CLASSPATH="$relpath/../classes$SEP$relpath/../conf$SEP"
if [ "$debug" = "true" ]; then
JAVA_OPTS="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_shmem,server=y,suspend=y,address=jgc1"
@@ -39,7 +39,7 @@
UNICAST(timeout=600,1200,2400,4800):\
pbcast.STABLE(desired_avg_gossip=20000):\
FRAG(frag_size=8096;down_thread=false;up_thread=false):\
-pbcast.GMS(join_timeout=5000;shun=false;print_local_addr=true)"
+pbcast.GMS(join_timeout=5000;print_local_addr=true)"
if [ "$cygwin" = "true" ]; then
diff -Nru libjgroups-java-2.7.0.GA/bin/frag_size.bat libjgroups-java-2.12.2.Final/bin/frag_size.bat
--- libjgroups-java-2.7.0.GA/bin/frag_size.bat 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/frag_size.bat 1970-01-01 00:00:00.000000000 +0000
@@ -1,13 +0,0 @@
-@echo off
-
-REM Determines the fragmentation size of your system
-
-set CLASSPATH=..\classes
-
-set CP=%CLASSPATH%
-set LOG4J=etc/log4j.xml
-set L4J=%LOG4J%
-
-
-
-java -cp %CP% org.jgroups.tests.DetermineFragSize
diff -Nru libjgroups-java-2.7.0.GA/bin/frag_size.sh libjgroups-java-2.12.2.Final/bin/frag_size.sh
--- libjgroups-java-2.7.0.GA/bin/frag_size.sh 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/frag_size.sh 1970-01-01 00:00:00.000000000 +0000
@@ -1,24 +0,0 @@
-#!/bin/sh
-
-# Determines the fragmentation size of your system
-
-BIN=`dirname $0`
-
-CLASSPATH=$BIN/../classes
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false;
-case "`uname`" in
- CYGWIN*)
- cygwin=true
- ;;
-esac
-
-if [ $cygwin = "true" ]; then
- CP=`cygpath -wp $CLASSPATH`
-else
- CP=$CLASSPATH
-fi
-
-
-java -cp $CP org.jgroups.tests.DetermineFragSize
diff -Nru libjgroups-java-2.7.0.GA/bin/gaps.sh libjgroups-java-2.12.2.Final/bin/gaps.sh
--- libjgroups-java-2.7.0.GA/bin/gaps.sh 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/gaps.sh 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,2 @@
+#!/bin/bash
+java org.jgroups.tests.CheckGaps $*
diff -Nru libjgroups-java-2.7.0.GA/bin/get_interfaces.bat libjgroups-java-2.12.2.Final/bin/get_interfaces.bat
--- libjgroups-java-2.7.0.GA/bin/get_interfaces.bat 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/get_interfaces.bat 1970-01-01 00:00:00.000000000 +0000
@@ -1,9 +0,0 @@
-@echo off
-
-REM Determines the interfaces on a machine
-
-set CLASSPATH=..\classes
-
-set CP=%CLASSPATH%
-
-java -cp %CP% org.jgroups.util.GetNetworkInterfaces
diff -Nru libjgroups-java-2.7.0.GA/bin/get_interfaces.sh libjgroups-java-2.12.2.Final/bin/get_interfaces.sh
--- libjgroups-java-2.7.0.GA/bin/get_interfaces.sh 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/get_interfaces.sh 1970-01-01 00:00:00.000000000 +0000
@@ -1,24 +0,0 @@
-#!/bin/sh
-
-# Determines the network interfaces on a machine
-
-BIN=`dirname $0`
-
-CLASSPATH=$BIN/../classes
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false;
-case "`uname`" in
- CYGWIN*)
- cygwin=true
- ;;
-esac
-
-if [ $cygwin = "true" ]; then
- CP=`cygpath -wp $CLASSPATH`
-else
- CP=$CLASSPATH
-fi
-
-
-java -cp $CP org.jgroups.util.GetNetworkInterfaces
diff -Nru libjgroups-java-2.7.0.GA/bin/gossiprouter.sh libjgroups-java-2.12.2.Final/bin/gossiprouter.sh
--- libjgroups-java-2.7.0.GA/bin/gossiprouter.sh 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/gossiprouter.sh 2011-10-18 11:22:35.000000000 +0000
@@ -9,5 +9,8 @@
OPTS="-Dlog4j.configuration=file:$HOME/log4j.properties -Djava.net.preferIPv4Stack=true"
OPTS="$OPTS -Dcom.sun.management.jmxremote"
-java $OPTS -classpath $CLASSPATH $JAVA_OPTS org.jgroups.stack.GossipRouter -port 12001 $*
+## Uncomment for remote JMX access. Also modify JAVA_HOME/jre/lib/management/jmxremote.passwords
+# OPTS="$OPTS -Dcom.sun.management.jmxremote.port=7000 -Dcom.sun.management.jmxremote.ssl=false"
+
+java $OPTS -classpath $CP $JAVA_OPTS org.jgroups.stack.GossipRouter -port 12001 $*
diff -Nru libjgroups-java-2.7.0.GA/bin/jg libjgroups-java-2.12.2.Final/bin/jg
--- libjgroups-java-2.7.0.GA/bin/jg 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/jg 2011-10-18 11:22:35.000000000 +0000
@@ -1,6 +1,5 @@
# Author: Bela Ban
-# Version: $Id: jg,v 1.3 2008/09/26 10:53:20 belaban Exp $
#!/bin/bash
diff -Nru libjgroups-java-2.7.0.GA/bin/jg-2.6 libjgroups-java-2.12.2.Final/bin/jg-2.6
--- libjgroups-java-2.7.0.GA/bin/jg-2.6 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/jg-2.6 1970-01-01 00:00:00.000000000 +0000
@@ -1,10 +0,0 @@
-
-# Author: Bela Ban
-# Version: $Id$
-
-
-#!/bin/bash
-
-JG=$HOME/JGroups-2.6-branch
-
-jgroups.sh org.jgroups.demos.$*
diff -Nru libjgroups-java-2.7.0.GA/bin/jgroups.bat libjgroups-java-2.12.2.Final/bin/jgroups.bat
--- libjgroups-java-2.7.0.GA/bin/jgroups.bat 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/jgroups.bat 2011-10-18 11:22:35.000000000 +0000
@@ -7,7 +7,7 @@
set JG=.
set LIB=%JG%
-set CP=%JG%\classes\;%JG%\conf\;%LIB%\jgroups-all.jar\;%LIB%\commons-logging.jar\;%LIB%\concurrent.jar\;%LIB%\jmxri.jar\;%LIB%\log4j.jar\;%JG%\keystore
+set CP=%JG%\classes\;%JG%\conf\;%LIB%\jgroups-all.jar\;%LIB%\log4j.jar\;%JG%\keystore
set VMFLAGS=-Xmx500M -Xms500M -XX:NewRatio=1 -XX:+AggressiveHeap -verbose:gc -XX:+DisableExplicitGC -XX:ThreadStackSize=32 -XX:CompileThreshold=100
diff -Nru libjgroups-java-2.7.0.GA/bin/jgroups.sh libjgroups-java-2.12.2.Final/bin/jgroups.sh
--- libjgroups-java-2.7.0.GA/bin/jgroups.sh 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/jgroups.sh 2011-10-18 11:22:35.000000000 +0000
@@ -1,6 +1,4 @@
-
# Author: Bela Ban
-# version: $Id: jgroups.sh,v 1.7 2008/10/28 12:19:28 belaban Exp $
#!/bin/bash
@@ -10,19 +8,38 @@
CP=$JG/classes:$JG/conf
+# If this is a bin dist, JARs are in the $JG directory.
+if [ ! -d $LIB ]; then
+ LIB=$JG
+fi;
+
for i in $LIB/*.jar
do
CP=$CP:$i
done
-LOG="-Dlog4j.configuration=file:$HOME/log4j.properties"
+if [ -f $HOME/log4j.properties ]; then
+ LOG="-Dlog4j.configuration=file:$HOME/log4j.properties"
+fi;
+
JG_FLAGS="-Dresolve.dns=false -Djgroups.bind_addr=$IP_ADDR -Djboss.tcpping.initial_hosts=$IP_ADDR[7800]"
-FLAGS="-server -Xmx600M -Xms600M -Xmn500M"
-FLAGS="$FLAGS -XX:CompileThreshold=10000 -XX:+AggressiveHeap -XX:ThreadStackSize=64 -XX:SurvivorRatio=8"
+JG_FLAGS="$JG_FLAGS -Djava.net.preferIPv4Stack=true -Djgroups.timer.num_threads=4"
+FLAGS="-server -Xmx600M -Xms600M -Xmn500M -Xss128K"
+FLAGS="$FLAGS -XX:CompileThreshold=10000 -XX:+AggressiveHeap -XX:ThreadStackSize=64K -XX:SurvivorRatio=8"
FLAGS="$FLAGS -XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=31"
-FLAGS="$FLAGS -Djava.net.preferIPv4Stack=true -Djgroups.timer.num_threads=4"
-FLAGS="$FLAGS -Xshare:off -XX:+UseBiasedLocking"
+FLAGS="$FLAGS -Xshare:off"
JMX="-Dcom.sun.management.jmxremote"
-EXPERIMENTAL="-XX:+UseFastAccessorMethods -XX:+UseTLAB -XX:+DoEscapeAnalysis"
+#EXPERIMENTAL="-XX:+UseFastAccessorMethods -XX:+UseTLAB"
+
+#EXPERIMENTAL="$EXPERIMENTAL -XX:+DoEscapeAnalysis -XX:+EliminateLocks -XX:+UseBiasedLocking"
+EXPERIMENTAL="$EXPERIMENTAL -XX:+EliminateLocks -XX:+UseBiasedLocking"
+
+#EXPERIMENTAL="$EXPERIMENTAL -XX:+AggressiveOpts -XX:+DoEscapeAnalysis -XX:+EliminateLocks -XX:+UseBiasedLocking -XX:+UseCompressedOops"
+#EXPERIMENTAL="$EXPERIMENTAL -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC"
+
+#java -Xrunhprof:cpu=samples,monitor=y,interval=5,lineno=y,thread=y -classpath $CP $LOG $JG_FLAGS $FLAGS $EXPERIMENTAL $JMX $*
+
+#DEBUG="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5000"
+
+java -classpath $CP $DEBUG $LOG $JG_FLAGS $FLAGS $EXPERIMENTAL $JMX $*
-java -classpath $CP $LOG $JG_FLAGS $FLAGS $EXPERIMENTAL $JMX $*
diff -Nru libjgroups-java-2.7.0.GA/bin/jt libjgroups-java-2.12.2.Final/bin/jt
--- libjgroups-java-2.7.0.GA/bin/jt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/jt 2011-10-18 11:22:35.000000000 +0000
@@ -1,5 +1,4 @@
# Author: Bela Ban
-# Version: $Id: jt,v 1.4 2008/09/26 10:52:57 belaban Exp $
#!/bin/bash
diff -Nru libjgroups-java-2.7.0.GA/bin/jt-2.6 libjgroups-java-2.12.2.Final/bin/jt-2.6
--- libjgroups-java-2.7.0.GA/bin/jt-2.6 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/jt-2.6 1970-01-01 00:00:00.000000000 +0000
@@ -1,10 +0,0 @@
-
-# Author: Bela Ban
-# Version: $Id$
-
-
-#!/bin/bash
-
-JG=$HOME/JGroups-2.6-branch
-
-jgroups.sh org.jgroups.tests.$*
diff -Nru libjgroups-java-2.7.0.GA/bin/probe.bat libjgroups-java-2.12.2.Final/bin/probe.bat
--- libjgroups-java-2.7.0.GA/bin/probe.bat 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/probe.bat 2011-10-18 11:22:35.000000000 +0000
@@ -8,7 +8,7 @@
set LIB=..\lib
-set LIBS=%LIB%\log4j-1.2.6.jar;%LIB%\commons-logging.jar;%LIB%\concurrent.jar
+set LIBS=%LIB%\log4j.jar;
set CP=%CLASSPATH%;%LIBS%
diff -Nru libjgroups-java-2.7.0.GA/bin/probe.sh libjgroups-java-2.12.2.Final/bin/probe.sh
--- libjgroups-java-2.7.0.GA/bin/probe.sh 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/probe.sh 2011-10-18 11:22:35.000000000 +0000
@@ -8,7 +8,7 @@
LIB=$BIN/../lib
-LIBS=$LIB/log4j-1.2.6.jar:$LIB/commons-logging.jar:$LIB/concurrent.jar
+LIBS=$LIB/log4j.jar
#echo $CLASSPATH
diff -Nru libjgroups-java-2.7.0.GA/bin/release_to_local_repo.sh libjgroups-java-2.12.2.Final/bin/release_to_local_repo.sh
--- libjgroups-java-2.7.0.GA/bin/release_to_local_repo.sh 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/release_to_local_repo.sh 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+
+# Uploads the artifacts in ./dist (JAR and src JAR) to the local repo ($HOME/.ms/jboss-repository)
+# so we can do local testing before uploading to the Nexus maven repo
+
+
+# Author: Bela Ban
+
+
+DIST=../dist
+POM=../pom.xml
+
+JAR=`find $DIST -name "jgroups-*.jar" | grep -v source`
+SRC_JAR=`find $DIST -name "jgroups-*.jar" | grep source`
+
+REPO=file:$HOME/.m2/jboss-repository
+FLAGS="-Dpackaging=jar -DrepositoryId=jboss-releases-repository"
+
+
+echo "Deploying $JAR to $REPO"
+mvn deploy:deploy-file -Dfile=$JAR -Durl=$REPO -DpomFile=$POM $FLAGS
+
+
+echo "Deploying $SRC_JAR to $REPO"
+mvn deploy:deploy-file -Dfile=$SRC_JAR -Durl=$REPO -DpomFile=$POM -Dclassifier=sources $FLAGS
+
diff -Nru libjgroups-java-2.7.0.GA/bin/release_to_nexus.sh libjgroups-java-2.12.2.Final/bin/release_to_nexus.sh
--- libjgroups-java-2.7.0.GA/bin/release_to_nexus.sh 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/release_to_nexus.sh 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+
+# Uploads the artifacts in ./dist (JAR and src JAR) to the Nexus Maven repo at repository.jboss.org/nexus
+# The artifacts will be in the staging repo, go to repository.jboss.org/nexus and promote them to the releases repo in
+# the next step
+
+# Author: Bela Ban
+
+
+DIST=../dist
+POM=../pom.xml
+
+JAR=`find $DIST -name "jgroups-*.jar" | grep -v source`
+SRC_JAR=`find $DIST -name "jgroups-*.jar" | grep source`
+
+REPO=https://repository.jboss.org/nexus/service/local/staging/deploy/maven2
+FLAGS="-Dpackaging=jar -DrepositoryId=jboss-releases-repository"
+
+
+echo "Deploying $JAR to $REPO"
+mvn deploy:deploy-file -Dfile=$JAR -Durl=$REPO -DpomFile=$POM $FLAGS
+
+
+echo "Deploying $SRC_JAR to $REPO"
+mvn deploy:deploy-file -Dfile=$SRC_JAR -Durl=$REPO -DpomFile=$POM -Dclassifier=sources $FLAGS
+
+
diff -Nru libjgroups-java-2.7.0.GA/bin/runtest.sh libjgroups-java-2.12.2.Final/bin/runtest.sh
--- libjgroups-java-2.7.0.GA/bin/runtest.sh 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/runtest.sh 1970-01-01 00:00:00.000000000 +0000
@@ -1,49 +0,0 @@
-#!/bin/sh
-
-# Runs a single test class from command line, circumventing ant altogether. Useful for
-# quick debugging.
-
-TESTCLASS=org.jgroups.tests.stack.RouterTest
-
-reldir=`dirname $0`
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false;
-case "`uname`" in
- CYGWIN*)
- cygwin=true
- ;;
-esac
-
-if [ $cygwin = true ]; then
- SEP=";"
-else
- SEP=":"
-fi
-
-while [ "$1" != "" ]; do
- if [ "$1" = "-debug" ]; then
- if [ $cygwin = false ]; then
- JAVA_OPTS="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=12348"
- else
- JAVA_OPTS="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_shmem,server=y,suspend=y,address=jgroups"
- fi
- fi
- shift
-done
-
-
-CLASSPATH="$reldir/../classes${SEP}\
-$reldir/../conf${SEP}\
-$reldir/../lib/junit.jar${SEP}\
-$reldir/../lib/log4j-1.2.6.jar${SEP}\
-$reldir/../lib/commons-logging.jar"
-
-#if [ $cygwin = "true" ]; then
-# CP=`cygpath -wp $CLASSPATH`
-#else
-# CP=$CLASSPATH
-#fi
-
-#echo $CLASSPATH
-java $JAVA_OPTS -cp $CLASSPATH junit.textui.TestRunner $TESTCLASS
diff -Nru libjgroups-java-2.7.0.GA/bin/upload_javadocs.sh libjgroups-java-2.12.2.Final/bin/upload_javadocs.sh
--- libjgroups-java-2.7.0.GA/bin/upload_javadocs.sh 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/upload_javadocs.sh 1970-01-01 00:00:00.000000000 +0000
@@ -1,5 +0,0 @@
-#!/bin/sh
-#
-# Uploads the javadoc to SourceForge
-
-scp -r ../dist/javadoc/* belaban,javagroups@web.sourceforge.net:/home/groups/j/ja/javagroups/htdocs/javagroupsnew/docs/javadoc/
diff -Nru libjgroups-java-2.7.0.GA/bin/upload_manual.sh libjgroups-java-2.12.2.Final/bin/upload_manual.sh
--- libjgroups-java-2.7.0.GA/bin/upload_manual.sh 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/bin/upload_manual.sh 1970-01-01 00:00:00.000000000 +0000
@@ -1,6 +0,0 @@
-#!/bin/sh
-#
-# Uploads the manual to SourceForge
-
-scp -r ../doc/manual/build/en/* belaban,javagroups@web.sourceforge.net:/home/groups/j/ja/javagroups/htdocs/javagroupsnew/docs/manual
-scp -r ../doc/tutorial/build/en/* belaban,javagroups@web.sourceforge.net:/home/groups/j/ja/javagroups/htdocs/javagroupsnew/docs/tutorial
diff -Nru libjgroups-java-2.7.0.GA/build.bat libjgroups-java-2.12.2.Final/build.bat
--- libjgroups-java-2.7.0.GA/build.bat 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/build.bat 2011-10-18 11:22:35.000000000 +0000
@@ -8,7 +8,7 @@
set LIB=lib
-set LIBS=%LIB%\log4j-1.2.6.jar;%LIB%\commons-logging.jar;%LIB%\concurrent.jar
+set LIBS=%LIB%\log4j.jar
set LIBS=%LIB%\ant.jar;%LIB%\ant-junit.jar;%LIB%\ant-launcher.jar;%LIB%\junit.jar;%LIB%\xalan.jar;%LIB%\serializer.jar;
REM echo LIBS=%LIBS%
diff -Nru libjgroups-java-2.7.0.GA/build.properties libjgroups-java-2.12.2.Final/build.properties
--- libjgroups-java-2.7.0.GA/build.properties 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/build.properties 1970-01-01 00:00:00.000000000 +0000
@@ -1,10 +0,0 @@
-# add your own properties in here
-
-# the network interface (NIC) which will be used by the unit tests, change this to
-# the one you want to use. Note that 'localhost' usually resolved to 127.0.0.1,
-# which may not work on Linux unless you have a multicast route set up for loopback
-jgroups.bind_addr=localhost
-jgroups.tcpping.initial_hosts=localhost[7800]
-jgroups.udp.mcast_addr=232.10.10.10
-jgroups.udp.mcast_port=45588
-jgroups.udp.ip_ttl=5
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/build.properties.template libjgroups-java-2.12.2.Final/build.properties.template
--- libjgroups-java-2.7.0.GA/build.properties.template 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/build.properties.template 2011-10-18 11:22:35.000000000 +0000
@@ -4,7 +4,12 @@
# the one you want to use. Note that 'localhost' usually resolved to 127.0.0.1,
# which may not work on Linux unless you have a multicast route set up for loopback
jgroups.bind_addr=localhost
-jgroups.tcpping.initial_hosts=localhost[7800]
+jgroups.tcpping.initial_hosts=localhost[7800],localhost[7801]
+jgroups.tunnel.gossip_router_hosts=localhost[12001]
jgroups.udp.mcast_addr=232.10.10.10
jgroups.udp.mcast_port=45588
-jgroups.udp.ip_ttl=5
\ No newline at end of file
+jgroups.udp.ip_ttl=5
+# use true for IPv6 and false for IPv4
+jgroups.useIPv6=false
+
+
diff -Nru libjgroups-java-2.7.0.GA/build.properties.template.ipv6 libjgroups-java-2.12.2.Final/build.properties.template.ipv6
--- libjgroups-java-2.7.0.GA/build.properties.template.ipv6 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/build.properties.template.ipv6 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,16 @@
+# Example of IPv6 based build.properties
+# Replace the IPv6 addresses with your own
+
+# the network interface (NIC) which will be used by the unit tests, change this to
+# the one you want to use. Note that 'localhost' usually resolved to 127.0.0.1,
+# which may not work on Linux unless you have a multicast route set up for loopback
+jgroups.bind_addr=fe80::21b:21ff:fe07:a3b0%3
+jgroups.tcpping.initial_hosts=fe80::21b:21ff:fe07:a3b0%3[7800],fe80::21b:21ff:fe07:a3b0%3[7801]
+jgroups.tunnel.gossip_router_hosts=fe80::21b:21ff:fe07:a3b0%3[12001]
+jgroups.udp.mcast_addr=ff0e::5:6:7
+jgroups.udp.mcast_port=45588
+jgroups.udp.ip_ttl=5
+# use true for IPv6 and false for IPv4
+jgroups.useIPv6=true
+
+
diff -Nru libjgroups-java-2.7.0.GA/build.sh libjgroups-java-2.12.2.Final/build.sh
--- libjgroups-java-2.7.0.GA/build.sh 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/build.sh 2011-10-18 11:22:35.000000000 +0000
@@ -20,12 +20,6 @@
LIB=lib
-#if [ "$cygwin" = "true" ]; then
-# CP=${LIB}/ant.jar\;${LIB}/ant-launcher.jar\;${LIB}/ant-junit.jar\;${LIB}/xalan.jar\;${LIB}/junit.jar
-#else
-# CP=${LIB}/ant.jar:${LIB}/ant-launcher.jar:${LIB}/ant-junit.jar:${LIB}/xalan.jar:${LIB}/junit.jar
-#fi
-
if [ "$cygwin" = "true" ]; then
for i in ${LIB}/*.jar
diff -Nru libjgroups-java-2.7.0.GA/build.xml libjgroups-java-2.12.2.Final/build.xml
--- libjgroups-java-2.7.0.GA/build.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/build.xml 2011-10-18 11:22:35.000000000 +0000
@@ -1,13 +1,12 @@
-
build.xml file for JGroups. Needs Ant (jakarta.apache.org) to run
-
+
@@ -16,6 +15,7 @@
+
@@ -32,19 +32,17 @@
-
+
+
+
-
+
-
-
-
-
@@ -54,6 +52,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -62,10 +71,6 @@
-
-
-
-
@@ -80,17 +85,16 @@
-
-
-
+
+ description="Compiles all Java files">
+
+
+
+
+
+
+
+
+
+
+ depends="jgroups.jar,jgroups-sources.jar">
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
@@ -147,103 +167,17 @@
+ includes="org/jgroups/**">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -260,28 +194,69 @@
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -290,10 +265,11 @@
+
-
+
@@ -306,7 +282,7 @@
-
+
@@ -315,6 +291,7 @@
+
@@ -342,7 +319,7 @@
-
+
@@ -352,23 +329,30 @@
-
-
+
+
-
+
-
+
-
+
+
+
+
+
+
-
-
+
+
+
@@ -379,13 +363,30 @@
usedefaultlisteners="false"
outputdir="${tmp.dir}/test-results/xml"
listeners="org.jgroups.util.JUnitXMLReporter"
- threadcount="20"
+ threadcount="10"
parallel="methods"
>
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
@@ -422,28 +412,48 @@
-
+
-
+
+
+
+
+
+
+
+
+
+
@@ -453,12 +463,14 @@
@@ -486,14 +498,16 @@
-
+
+
+
@@ -502,18 +516,32 @@
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
diff -Nru libjgroups-java-2.7.0.GA/.classpath libjgroups-java-2.12.2.Final/.classpath
--- libjgroups-java-2.7.0.GA/.classpath 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/.classpath 2011-10-18 11:22:35.000000000 +0000
@@ -1,19 +1,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/auth_fixedlist.xml libjgroups-java-2.12.2.Final/conf/auth_fixedlist.xml
--- libjgroups-java-2.7.0.GA/conf/auth_fixedlist.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/auth_fixedlist.xml 2011-10-18 11:22:35.000000000 +0000
@@ -1,9 +1,8 @@
-
+ />
+ max_bytes="4m"/>
-
+ />
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/conf/auth_md5.xml libjgroups-java-2.12.2.Final/conf/auth_md5.xml
--- libjgroups-java-2.7.0.GA/conf/auth_md5.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/auth_md5.xml 2011-10-18 11:22:35.000000000 +0000
@@ -2,7 +2,6 @@
+ />
+ max_bytes="4m"/>
-
+ />
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/conf/auth_regex.xml libjgroups-java-2.12.2.Final/conf/auth_regex.xml
--- libjgroups-java-2.7.0.GA/conf/auth_regex.xml 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/auth_regex.xml 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/auth_simple.xml libjgroups-java-2.12.2.Final/conf/auth_simple.xml
--- libjgroups-java-2.7.0.GA/conf/auth_simple.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/auth_simple.xml 2011-10-18 11:22:35.000000000 +0000
@@ -1,16 +1,16 @@
-
+
+ />
-
-
+ max_bytes="4m"/>
+
+ />
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/conf/auth_X509.xml libjgroups-java-2.12.2.Final/conf/auth_X509.xml
--- libjgroups-java-2.7.0.GA/conf/auth_X509.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/auth_X509.xml 2011-10-18 11:22:35.000000000 +0000
@@ -2,7 +2,6 @@
+ />
+ max_bytes="4m"/>
-
+ />
diff -Nru libjgroups-java-2.7.0.GA/conf/bare-bones.xml libjgroups-java-2.12.2.Final/conf/bare-bones.xml
--- libjgroups-java-2.7.0.GA/conf/bare-bones.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/bare-bones.xml 2011-10-18 11:22:35.000000000 +0000
@@ -12,9 +12,10 @@
done on the application level in this case
-->
-
+
diff -Nru libjgroups-java-2.7.0.GA/conf/bsh.xml libjgroups-java-2.12.2.Final/conf/bsh.xml
--- libjgroups-java-2.7.0.GA/conf/bsh.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/bsh.xml 2011-10-18 11:22:35.000000000 +0000
@@ -2,19 +2,20 @@
-
+
-
+
-
+
+ desired_avg_gossip="20000" max_bytes="4m"/>
-
+
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/conf/causal.xml libjgroups-java-2.12.2.Final/conf/causal.xml
--- libjgroups-java-2.7.0.GA/conf/causal.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/causal.xml 1970-01-01 00:00:00.000000000 +0000
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/conf/compress.xml libjgroups-java-2.12.2.Final/conf/compress.xml
--- libjgroups-java-2.7.0.GA/conf/compress.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/compress.xml 2011-10-18 11:22:35.000000000 +0000
@@ -2,20 +2,21 @@
-
+
-
+
-
+
-
-
+
diff -Nru libjgroups-java-2.7.0.GA/conf/config.txt libjgroups-java-2.12.2.Final/conf/config.txt
--- libjgroups-java-2.7.0.GA/conf/config.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/config.txt 2011-10-18 11:22:35.000000000 +0000
@@ -1,6 +1,5 @@
#
# This file contains configuration for the JGroups performance tests (org.jgroups.tests.perf package)
-# $Id: config.txt,v 1.12 2006/12/11 10:16:54 belaban Exp $
#
# Class implementing the org.jgroups.tests.perf.Transport interface
diff -Nru libjgroups-java-2.7.0.GA/conf/discard.xml libjgroups-java-2.12.2.Final/conf/discard.xml
--- libjgroups-java-2.7.0.GA/conf/discard.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/discard.xml 1970-01-01 00:00:00.000000000 +0000
@@ -1,38 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/conf/encrypt-entire-message.xml libjgroups-java-2.12.2.Final/conf/encrypt-entire-message.xml
--- libjgroups-java-2.7.0.GA/conf/encrypt-entire-message.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/encrypt-entire-message.xml 2011-10-18 11:22:35.000000000 +0000
@@ -2,18 +2,19 @@
-
+
-
+
-
+
-
+
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/conf/EncryptKeyStore.xml libjgroups-java-2.12.2.Final/conf/EncryptKeyStore.xml
--- libjgroups-java-2.7.0.GA/conf/EncryptKeyStore.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/EncryptKeyStore.xml 2011-10-18 11:22:35.000000000 +0000
@@ -2,9 +2,10 @@
-
+
diff -Nru libjgroups-java-2.7.0.GA/conf/EncryptNoKeyStore.xml libjgroups-java-2.12.2.Final/conf/EncryptNoKeyStore.xml
--- libjgroups-java-2.7.0.GA/conf/EncryptNoKeyStore.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/EncryptNoKeyStore.xml 2011-10-18 11:22:35.000000000 +0000
@@ -2,18 +2,20 @@
-
+
+ loopback="true" ucast_send_buf_size="32000" ip_ttl="32"/>
-
+
-
+
-
+
diff -Nru libjgroups-java-2.7.0.GA/conf/encrypt.xml libjgroups-java-2.12.2.Final/conf/encrypt.xml
--- libjgroups-java-2.7.0.GA/conf/encrypt.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/encrypt.xml 2011-10-18 11:22:35.000000000 +0000
@@ -2,18 +2,19 @@
-
+
-
+
-
+
-
+
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/conf/execution-service.xml libjgroups-java-2.12.2.Final/conf/execution-service.xml
--- libjgroups-java-2.7.0.GA/conf/execution-service.xml 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/execution-service.xml 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/fast-local.xml libjgroups-java-2.12.2.Final/conf/fast-local.xml
--- libjgroups-java-2.7.0.GA/conf/fast-local.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/fast-local.xml 2011-10-18 11:22:35.000000000 +0000
@@ -5,12 +5,12 @@
Therefore, this configuration will NOT work to cluster members residing on different hosts !
Author: Bela Ban
- Version: $Id: fast-local.xml,v 1.1 2008/09/26 16:01:28 belaban Exp $
-->
-
+
+ oob_thread_pool.rejection_policy="discard"/>
@@ -52,19 +58,20 @@
-
+ max_bytes="8m"/>
-
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/flush-tcp-nio.xml libjgroups-java-2.12.2.Final/conf/flush-tcp-nio.xml
--- libjgroups-java-2.7.0.GA/conf/flush-tcp-nio.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/flush-tcp-nio.xml 2011-10-18 11:22:35.000000000 +0000
@@ -5,21 +5,21 @@
Note that TCP.bind_addr and TCPPING.initial_hosts should be set, possibly via system properties, e.g.
-Djgroups.bind_addr=192.168.5.2 and -Djgroups.tcpping.initial_hosts=192.168.5.2[7800]".
author: Bela Ban
- version: $Id: flush-tcp-nio.xml,v 1.7 2008/09/25 14:20:45 belaban Exp $
-->
-
+
-
+
-
+ max_bytes="4m"/>
-
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/flush-tcp.xml libjgroups-java-2.12.2.Final/conf/flush-tcp.xml
--- libjgroups-java-2.7.0.GA/conf/flush-tcp.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/flush-tcp.xml 2011-10-18 11:22:35.000000000 +0000
@@ -5,18 +5,19 @@
-Djgroups.bind_addr=192.168.5.2 and -Djgroups.tcpping.initial_hosts=192.168.5.2[7800]"
-->
-
+
-
+
-
+
+ max_bytes="4m"/>
-
+ view_bundling="true"/>
+
+
-
\ No newline at end of file
+
diff -Nru libjgroups-java-2.7.0.GA/conf/flush-udp.xml libjgroups-java-2.12.2.Final/conf/flush-udp.xml
--- libjgroups-java-2.7.0.GA/conf/flush-udp.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/flush-udp.xml 2011-10-18 11:22:35.000000000 +0000
@@ -3,16 +3,17 @@
Default flush stack using IP multicasting.
-->
-
+
-
+
@@ -46,14 +47,16 @@
-
-
+ max_bytes="4m"/>
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/jboss-service.xml libjgroups-java-2.12.2.Final/conf/jboss-service.xml
--- libjgroups-java-2.7.0.GA/conf/jboss-service.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/jboss-service.xml 2011-10-18 11:22:35.000000000 +0000
@@ -6,7 +6,6 @@
jgroups:name=DemoChannel
@@ -22,22 +21,22 @@
-
+ loopback="true"/>
-
+
-
+
+ print_local_addr="true"/>
diff -Nru libjgroups-java-2.7.0.GA/conf/jg-magic-map.xml libjgroups-java-2.12.2.Final/conf/jg-magic-map.xml
--- libjgroups-java-2.7.0.GA/conf/jg-magic-map.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/jg-magic-map.xml 2011-10-18 11:22:35.000000000 +0000
@@ -2,7 +2,6 @@
-
@@ -18,24 +17,43 @@
-
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/jg-protocol-ids.xml libjgroups-java-2.12.2.Final/conf/jg-protocol-ids.xml
--- libjgroups-java-2.7.0.GA/conf/jg-protocol-ids.xml 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/jg-protocol-ids.xml 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/log4j.properties libjgroups-java-2.12.2.Final/conf/log4j.properties
--- libjgroups-java-2.7.0.GA/conf/log4j.properties 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/log4j.properties 2011-10-18 11:22:35.000000000 +0000
@@ -23,7 +23,8 @@
log4j.logger.org.jgroups=warn
-#log4j.logger.org.jgroups.protocols.pbcast.FLUSH=WARN
+log4j.logger.org.jgroups.protocols.pbcast.FLUSH=DEBUG
+log4j.logger.org.jgroups.protocols.MERGE2=DEBUG
#log4j.logger.org.jgroups.protocols.pbcast.GMS=WARN
#log4j.additivity.org.jgroups.protocols.pbcast.STABLE=false
diff -Nru libjgroups-java-2.7.0.GA/conf/manifest.mf libjgroups-java-2.12.2.Final/conf/manifest.mf
--- libjgroups-java-2.7.0.GA/conf/manifest.mf 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/manifest.mf 2011-10-18 11:22:35.000000000 +0000
@@ -1,4 +1,4 @@
Manifest-Version: 1.0
-Created-By: Apache Ant 1.5Beta2
+Created-By: Apache Ant 1.6.5
Main-Class: org.jgroups.Version
-Implementation-Version: 2.7.0.GA
\ No newline at end of file
+Implementation-Version: 2.12.2.Final
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/conf/mping.xml libjgroups-java-2.12.2.Final/conf/mping.xml
--- libjgroups-java-2.7.0.GA/conf/mping.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/mping.xml 2011-10-18 11:22:35.000000000 +0000
@@ -2,18 +2,17 @@
-
-
+
-
+ max_bytes="4m"/>
+ />
+
+
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/multiplexer-service.xml libjgroups-java-2.12.2.Final/conf/multiplexer-service.xml
--- libjgroups-java-2.7.0.GA/conf/multiplexer-service.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/multiplexer-service.xml 2011-10-18 11:22:35.000000000 +0000
@@ -1,23 +1,22 @@
-
-
-
-
-
-
-
-
-
- jgroups.mux
- stacks.xml
- true
- true
-
-
-
-
+
+
+
+
+
+
+
+
+
+ jgroups.mux
+ stacks.xml
+ true
+ true
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/multiplexer-xmbean.xml libjgroups-java-2.12.2.Final/conf/multiplexer-xmbean.xml
--- libjgroups-java-2.7.0.GA/conf/multiplexer-xmbean.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/multiplexer-xmbean.xml 2011-10-18 11:22:35.000000000 +0000
@@ -1,140 +1,139 @@
-
-
-
-
-
-
-
-
-
- JGroups Multiplexer
- org.jgroups.jmx.JChannelFactory
-
-
-
- The default constructor
- JChannelFactory
-
-
-
-
- The domain which is used as prefix for all channels and protocols exposed via JMX
- Domain
- java.lang.String
-
-
-
-
-
-
- The file used for configuration. If this is not an absolute pathname, it will need to be found on the classpath
- MultiplexerConfig
- java.lang.String
-
-
-
-
-
-
- Whether or not to expose channels via JMX
- ExposeChannels
- boolean
-
-
-
-
-
-
- Whether or not to expose protocols via JMX (if true, will set ExposeChannels to true too)
- ExposeProtocols
- boolean
-
-
-
-
-
-
-
-
- The create() life cycle operation
- create
-
-
-
- The start lifecycle operation.
- start
-
-
-
- The stop lifecycle operation.
- stop
-
-
-
- The destroy() life cycle operation
- destroy
-
-
-
-
- Dumps the channels
- dumpChannels
- java.lang.String
-
-
-
- Dumps the configuration
- dumpConfiguration
- java.lang.String
-
-
-
-
- createMultiplexerChannel
-
- The name of the stack, as defined e.g. in stacks.xml
- stack_name
- java.lang.String
-
-
- The application ID, all IDs need to be unique across a Multiplexer
- id
- java.lang.String
-
-
- Whether this application wants to register for state transfer, getState() will only return when *all* registered listeners called it
- register_for_state_transfer
- boolean
-
-
- The ID of the substate to be retrieved (or null)
- substate_id
- java.lang.String
-
- org.jgroups.Channel
-
-
-
-
- createMultiplexerChannel
-
- The name of the stack, as defined e.g. in stacks.xml
- stack_name
- java.lang.String
-
-
- The application ID, all IDs need to be unique across a Multiplexer
- id
- java.lang.String
-
- org.jgroups.Channel
-
-
-
-
+
+
+
+
+
+
+
+
+
+ JGroups Multiplexer
+ org.jgroups.jmx.JChannelFactory
+
+
+
+ The default constructor
+ JChannelFactory
+
+
+
+
+ The domain which is used as prefix for all channels and protocols exposed via JMX
+ Domain
+ java.lang.String
+
+
+
+
+
+
+ The file used for configuration. If this is not an absolute pathname, it will need to be found on the classpath
+ MultiplexerConfig
+ java.lang.String
+
+
+
+
+
+
+ Whether or not to expose channels via JMX
+ ExposeChannels
+ boolean
+
+
+
+
+
+
+ Whether or not to expose protocols via JMX (if true, will set ExposeChannels to true too)
+ ExposeProtocols
+ boolean
+
+
+
+
+
+
+
+
+ The create() life cycle operation
+ create
+
+
+
+ The start lifecycle operation.
+ start
+
+
+
+ The stop lifecycle operation.
+ stop
+
+
+
+ The destroy() life cycle operation
+ destroy
+
+
+
+
+ Dumps the channels
+ dumpChannels
+ java.lang.String
+
+
+
+ Dumps the configuration
+ dumpConfiguration
+ java.lang.String
+
+
+
+
+ createMultiplexerChannel
+
+ The name of the stack, as defined e.g. in stacks.xml
+ stack_name
+ java.lang.String
+
+
+ The application ID, all IDs need to be unique across a Multiplexer
+ id
+ java.lang.String
+
+
+ Whether this application wants to register for state transfer, getState() will only return when *all* registered listeners called it
+ register_for_state_transfer
+ boolean
+
+
+ The ID of the substate to be retrieved (or null)
+ substate_id
+ java.lang.String
+
+ org.jgroups.Channel
+
+
+
+
+ createMultiplexerChannel
+
+ The name of the stack, as defined e.g. in stacks.xml
+ stack_name
+ java.lang.String
+
+
+ The application ID, all IDs need to be unique across a Multiplexer
+ id
+ java.lang.String
+
+ org.jgroups.Channel
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/pbcast.xml libjgroups-java-2.12.2.Final/conf/pbcast.xml
--- libjgroups-java-2.7.0.GA/conf/pbcast.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/pbcast.xml 1970-01-01 00:00:00.000000000 +0000
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff -Nru libjgroups-java-2.7.0.GA/conf/pulltheplug.xml libjgroups-java-2.12.2.Final/conf/pulltheplug.xml
--- libjgroups-java-2.7.0.GA/conf/pulltheplug.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/pulltheplug.xml 1970-01-01 00:00:00.000000000 +0000
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff -Nru libjgroups-java-2.7.0.GA/conf/sequencer.xml libjgroups-java-2.12.2.Final/conf/sequencer.xml
--- libjgroups-java-2.7.0.GA/conf/sequencer.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/sequencer.xml 2011-10-18 11:22:35.000000000 +0000
@@ -3,19 +3,19 @@
Default stack using IP multicasting. It is similar to the "udp"
stack in stacks.xml, but doesn't use streaming state transfer and flushing
author: Bela Ban
- version: $Id: sequencer.xml,v 1.11 2008/11/03 07:43:27 belaban Exp $
-->
-
+
-
+ max_bytes="4m"/>
-
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/settings.xml libjgroups-java-2.12.2.Final/conf/settings.xml
--- libjgroups-java-2.7.0.GA/conf/settings.xml 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/settings.xml 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,86 @@
+
+
+
+
+
+ /home/bela/.m2/jboss-repository
+
+
+
+ jboss-releases-repository
+ USERNAME
+ PASSWORD
+
+
+
+
+
+
+
+ jboss-public-repository
+
+
+ jboss-public-repository-group
+ JBoss Public Maven Repository Group
+ https://repository.jboss.org/nexus/content/groups/public/
+ default
+
+ true
+ never
+
+
+ true
+ never
+
+
+
+
+
+ jboss-public-repository-group
+ JBoss Public Maven Repository Group
+ https://repository.jboss.org/nexus/content/groups/public/
+ default
+
+ true
+ never
+
+
+ true
+ never
+
+
+
+
+
+
+
+ jboss-deprecated-repository
+
+
+ jboss-deprecated-repository
+ JBoss Deprecated Maven Repository
+ https://repository.jboss.org/nexus/content/repositories/deprecated/
+ default
+
+ true
+ never
+
+
+ false
+ never
+
+
+
+
+
+
+
+
+
+ jboss-public-repository
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/sfc.xml libjgroups-java-2.12.2.Final/conf/sfc.xml
--- libjgroups-java-2.7.0.GA/conf/sfc.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/sfc.xml 2011-10-18 11:22:35.000000000 +0000
@@ -2,19 +2,19 @@
-
+
-
+
-
+ max_bytes="4m" />
+ view_bundling="true" />
diff -Nru libjgroups-java-2.7.0.GA/conf/smack_tunnel.xml libjgroups-java-2.12.2.Final/conf/smack_tunnel.xml
--- libjgroups-java-2.7.0.GA/conf/smack_tunnel.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/smack_tunnel.xml 2011-10-18 11:22:35.000000000 +0000
@@ -4,9 +4,11 @@
-
+
-
+
diff -Nru libjgroups-java-2.7.0.GA/conf/smack.xml libjgroups-java-2.12.2.Final/conf/smack.xml
--- libjgroups-java-2.7.0.GA/conf/smack.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/smack.xml 2011-10-18 11:22:35.000000000 +0000
@@ -9,9 +9,11 @@
acks (sender sends message, receiver sends ack, if
sender doesn't receive ack within timeout, message
will be retransmitted). Compared to smack.xml, this stack uses TUNNEL as transport-->
-
-
+
+
-
+
diff -Nru libjgroups-java-2.7.0.GA/conf/stacks.xml libjgroups-java-2.12.2.Final/conf/stacks.xml
--- libjgroups-java-2.7.0.GA/conf/stacks.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/stacks.xml 2011-10-18 11:22:35.000000000 +0000
@@ -2,21 +2,19 @@
-
+
+ max_bytes="4m"/>
-
+
+
@@ -73,14 +73,13 @@
run out of memory">
-
+
+ max_bytes="4m"/>
@@ -141,9 +140,8 @@
max_bundle_size="64000"
max_bundle_timeout="30"
enable_bundling="true"
- use_send_queues="false"
+ use_send_queues="true"
sock_conn_timeout="300"
- skip_suspected_members="true"
thread_pool.enabled="true"
thread_pool.min_threads="1"
@@ -168,7 +166,7 @@
-
+
+ max_bytes="4m"/>
-
+
+
@@ -204,10 +204,9 @@
max_bundle_size="64000"
max_bundle_timeout="30"
enable_bundling="true"
- use_send_queues="false"
+ use_send_queues="true"
sock_conn_timeout="300"
- skip_suspected_members="true"
-
+
thread_pool.enabled="true"
thread_pool.min_threads="1"
thread_pool.max_threads="25"
@@ -231,7 +230,7 @@
-
+
+ max_bytes="4m"/>
@@ -259,14 +258,14 @@
-
+
+ max_bytes="4m"/>
-
+
+
@@ -312,14 +313,14 @@
-
+
+ max_bytes="4m"/>
@@ -364,7 +365,7 @@
gossip_port="12001"/>
-
+
+ max_bytes="4m"/>
-
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/tcpgossip.xml libjgroups-java-2.12.2.Final/conf/tcpgossip.xml
--- libjgroups-java-2.7.0.GA/conf/tcpgossip.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/tcpgossip.xml 2011-10-18 11:22:35.000000000 +0000
@@ -1,17 +1,59 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/tcp_nio.xml libjgroups-java-2.12.2.Final/conf/tcp_nio.xml
--- libjgroups-java-2.7.0.GA/conf/tcp_nio.xml 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/tcp_nio.xml 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/tcp-nio.xml libjgroups-java-2.12.2.Final/conf/tcp-nio.xml
--- libjgroups-java-2.7.0.GA/conf/tcp-nio.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/tcp-nio.xml 2011-10-18 11:22:35.000000000 +0000
@@ -5,9 +5,10 @@
Note that TCP.bind_addr and TCPPING.initial_hosts should be set, possibly via system properties, e.g.
-Djgroups.bind_addr=192.168.5.2 and -Djgroups.tcpping.initial_hosts=192.168.5.2[7800]".
author: Bela Ban
- version: $Id: tcp-nio.xml,v 1.14 2008/09/25 14:20:44 belaban Exp $
-->
-
+
-
+
-
+ max_bytes="4m"/>
-
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/tcp.xml libjgroups-java-2.12.2.Final/conf/tcp.xml
--- libjgroups-java-2.7.0.GA/conf/tcp.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/tcp.xml 2011-10-18 11:22:35.000000000 +0000
@@ -4,28 +4,34 @@
Note that TCP.bind_addr and TCPPING.initial_hosts should be set, possibly via system properties, e.g.
-Djgroups.bind_addr=192.168.5.2 and -Djgroups.tcpping.initial_hosts=192.168.5.2[7800]
author: Bela Ban
- version: $Id: tcp.xml,v 1.25 2008/09/25 14:26:07 belaban Exp $
-->
-
+
+ oob_thread_pool.rejection_policy="discard"/>
-
+
-
+
-
+ max_bytes="4M"/>
-
-
+
+
+
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/conf/testng/stack-independent.xml libjgroups-java-2.12.2.Final/conf/testng/stack-independent.xml
--- libjgroups-java-2.7.0.GA/conf/testng/stack-independent.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/testng/stack-independent.xml 2011-10-18 11:22:35.000000000 +0000
@@ -9,6 +9,7 @@
+
diff -Nru libjgroups-java-2.7.0.GA/conf/testng/testng-single.xml libjgroups-java-2.12.2.Final/conf/testng/testng-single.xml
--- libjgroups-java-2.7.0.GA/conf/testng/testng-single.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/testng/testng-single.xml 1970-01-01 00:00:00.000000000 +0000
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff -Nru libjgroups-java-2.7.0.GA/conf/testng/testng-tcp-flush.xml libjgroups-java-2.12.2.Final/conf/testng/testng-tcp-flush.xml
--- libjgroups-java-2.7.0.GA/conf/testng/testng-tcp-flush.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/testng/testng-tcp-flush.xml 2011-10-18 11:22:35.000000000 +0000
@@ -1,8 +1,7 @@
+ thread-count="5">
diff -Nru libjgroups-java-2.7.0.GA/conf/testng/testng-tcp-stress.xml libjgroups-java-2.12.2.Final/conf/testng/testng-tcp-stress.xml
--- libjgroups-java-2.7.0.GA/conf/testng/testng-tcp-stress.xml 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/testng/testng-tcp-stress.xml 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/testng/testng-tcp.xml libjgroups-java-2.12.2.Final/conf/testng/testng-tcp.xml
--- libjgroups-java-2.7.0.GA/conf/testng/testng-tcp.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/testng/testng-tcp.xml 2011-10-18 11:22:35.000000000 +0000
@@ -1,7 +1,7 @@
@@ -13,7 +13,8 @@
-
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/testng/testng-udp-flush.xml libjgroups-java-2.12.2.Final/conf/testng/testng-udp-flush.xml
--- libjgroups-java-2.7.0.GA/conf/testng/testng-udp-flush.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/testng/testng-udp-flush.xml 2011-10-18 11:22:35.000000000 +0000
@@ -1,8 +1,7 @@
+ thread-count="5">
diff -Nru libjgroups-java-2.7.0.GA/conf/testng/testng-udp.xml libjgroups-java-2.12.2.Final/conf/testng/testng-udp.xml
--- libjgroups-java-2.7.0.GA/conf/testng/testng-udp.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/testng/testng-udp.xml 2011-10-18 11:22:35.000000000 +0000
@@ -1,7 +1,7 @@
diff -Nru libjgroups-java-2.7.0.GA/conf/testng/time-sensitive.xml libjgroups-java-2.12.2.Final/conf/testng/time-sensitive.xml
--- libjgroups-java-2.7.0.GA/conf/testng/time-sensitive.xml 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/testng/time-sensitive.xml 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/tunnel.xml libjgroups-java-2.12.2.Final/conf/tunnel.xml
--- libjgroups-java-2.7.0.GA/conf/tunnel.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/tunnel.xml 2011-10-18 11:22:35.000000000 +0000
@@ -4,17 +4,15 @@
-
-
-
+
+
+
+
-
+
+ max_bytes="4m"/>
-
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/udp-largecluster.xml libjgroups-java-2.12.2.Final/conf/udp-largecluster.xml
--- libjgroups-java-2.7.0.GA/conf/udp-largecluster.xml 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/udp-largecluster.xml 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/conf/udp.xml libjgroups-java-2.12.2.Final/conf/udp.xml
--- libjgroups-java-2.7.0.GA/conf/udp.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/conf/udp.xml 2011-10-18 11:22:35.000000000 +0000
@@ -3,27 +3,33 @@
Default stack using IP multicasting. It is similar to the "udp"
stack in stacks.xml, but doesn't use streaming state transfer and flushing
author: Bela Ban
- version: $Id: udp.xml,v 1.29 2008/09/26 15:59:33 belaban Exp $
-->
-
+
-
+ max_bytes="4M"/>
-
-
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/debian/changelog libjgroups-java-2.12.2.Final/debian/changelog
--- libjgroups-java-2.7.0.GA/debian/changelog 2011-10-24 03:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/debian/changelog 2011-12-27 23:06:24.000000000 +0000
@@ -1,3 +1,19 @@
+libjgroups-java (2.12.2.Final-2) unstable; urgency=low
+
+ * Upload to unstable.
+
+ -- Brian Thomason Tue, 27 Dec 2011 22:36:12 +0100
+
+libjgroups-java (2.12.2.Final-1) experimental; urgency=low
+
+ * New upstream release
+ * Added Red Hat to copyright list
+ * Patch no longer required
+ [ Steffen Moeller ]
+ * Added Brian to uploaders.
+
+ -- Brian Thomason Tue, 06 Dec 2011 22:43:17 +0000
+
libjgroups-java (2.7.0.GA-4) unstable; urgency=low
* Team upload.
diff -Nru libjgroups-java-2.7.0.GA/debian/compat libjgroups-java-2.12.2.Final/debian/compat
--- libjgroups-java-2.7.0.GA/debian/compat 2007-10-27 15:10:52.000000000 +0000
+++ libjgroups-java-2.12.2.Final/debian/compat 2011-12-22 01:00:28.000000000 +0000
@@ -1 +1 @@
-5
+7
diff -Nru libjgroups-java-2.7.0.GA/debian/control libjgroups-java-2.12.2.Final/debian/control
--- libjgroups-java-2.7.0.GA/debian/control 2011-10-22 22:04:44.000000000 +0000
+++ libjgroups-java-2.12.2.Final/debian/control 2011-12-22 22:48:08.000000000 +0000
@@ -2,7 +2,9 @@
Section: java
Priority: optional
Maintainer: Debian Java Maintainers
-Uploaders: Varun Hiremath , Torsten Werner
+Uploaders: Varun Hiremath ,
+ Torsten Werner ,
+ Brian Thomason
Build-Depends: cdbs, debhelper (>= 5)
Build-Depends-Indep: ant, default-jdk, glassfish-javaee, bsh, junit,
libxalan2-java, libbcprov-java, libcommons-logging-java,
@@ -11,10 +13,11 @@
Homepage: http://www.jgroups.org/javagroupsnew/docs/index.html
Vcs-Svn: svn://svn.debian.org/svn/pkg-java/trunk/libjgroups-java
Vcs-Browser: http://svn.debian.org/wsvn/pkg-java/trunk/libjgroups-java/
+DM-Upload-Allowed: yes
Package: libjgroups-java
Architecture: all
-Depends: ${shlibs:Depends}, ${misc:Depends}, openjdk-6-jre-headless | java5-runtime
+Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Toolkit for Reliable Multicast Communication
JGroups is a toolkit for reliable multicast communication. (Note
that this doesn't necessarily mean IP Multicast, JGroups can also use
diff -Nru libjgroups-java-2.7.0.GA/debian/copyright libjgroups-java-2.12.2.Final/debian/copyright
--- libjgroups-java-2.7.0.GA/debian/copyright 2008-08-16 21:38:07.000000000 +0000
+++ libjgroups-java-2.12.2.Final/debian/copyright 2011-12-22 01:00:28.000000000 +0000
@@ -20,8 +20,9 @@
Chris Mills
Copyright:
-(C) 2005 JBoss Inc., Chris Mills
-(C) 2002 Filip Hanik and Bela Ban
+Copyright 2006 Red Hat, Inc.
+Copyright 2005 JBoss Inc., Chris Mills
+Copyright 2002 Filip Hanik and Bela Ban
License:
This library is free software; you can redistribute it and/or
@@ -42,10 +43,10 @@
src/org/jgroups/annotations/GuardedBy.java
src/org/jgroups/annotations/Immutable.java
-Copyright: (c) 2008 Torsten Werner
+Copyright: 2008 Torsten Werner
License: same license as jgroups (LGPL, see above)
-------
-The Debian packaging is (C) 2007, Varun Hiremath and
+The Debian packaging is Copyright 2007, Varun Hiremath and
is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
diff -Nru libjgroups-java-2.7.0.GA/debian/orig-tar.sh libjgroups-java-2.12.2.Final/debian/orig-tar.sh
--- libjgroups-java-2.7.0.GA/debian/orig-tar.sh 2008-08-16 21:38:07.000000000 +0000
+++ libjgroups-java-2.12.2.Final/debian/orig-tar.sh 2011-12-22 01:00:28.000000000 +0000
@@ -1,17 +1,29 @@
#!/bin/sh -e
# called by uscan with '--upstream-version'
-TAR=libjgroups-java_$2.orig.tar.gz
-DIR=libjgroups-java-$2.orig
+VER=`echo $2|sed -e 's/\_/\./g'`
+TAR=../libjgroups-java_$VER.orig.tar.gz
+DIR=libjgroups-java-$VER.orig
# clean up the upstream tarball
-unzip $3
-mv JGroups-* $DIR
+if [ -r "$3" ]; then
+ echo "Found existing tarball - presumably from get-orig-soruce/uscan - fixing it"
+ tar xfz $3
+fi
+if find . -type d -a -name "belaban*"; then
+ echo "Renaming belaban* to '$DIR'"
+ mv belaban* $DIR
+fi
# replace CC licensed files by my own simple implementation
cp -f debian/annotations/* $DIR/src/org/jgroups/annotations/
-tar -c -z -f $TAR --exclude '*.jar' --exclude '*/out/*' --exclude '*/lib/*' $DIR
+if GZIP="-9n" tar -c -z -f $TAR --exclude '*.jar' --exclude '*/out/*' --exclude '*/lib/*' $DIR; then
+ echo "Created tar file in '$TAR'."
+else
+ echo "Error packing directory '$DIR' to '$TAR'"
+ exit
+fi
rm -rf $3 $DIR
# move to directory 'tarballs'
@@ -20,3 +32,6 @@
mv $TAR $origDir
echo "moved $TAR to $origDir"
fi
+
+
+echo "[OK]"
diff -Nru libjgroups-java-2.7.0.GA/debian/patches/0001-define-jg.classpath-before-using-it.patch libjgroups-java-2.12.2.Final/debian/patches/0001-define-jg.classpath-before-using-it.patch
--- libjgroups-java-2.7.0.GA/debian/patches/0001-define-jg.classpath-before-using-it.patch 2010-02-28 10:17:05.000000000 +0000
+++ libjgroups-java-2.12.2.Final/debian/patches/0001-define-jg.classpath-before-using-it.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,35 +0,0 @@
-From: Torsten Werner
-Date: Sun, 28 Feb 2010 11:09:15 +0100
-Subject: [PATCH] define jg.classpath before using it
-
----
- build.xml | 8 ++++----
- 1 files changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/build.xml b/build.xml
-index 596e909..20baae7 100644
---- a/build.xml
-+++ b/build.xml
-@@ -41,10 +41,6 @@
-
-
-
--
--
--
--
-
-
-
-@@ -54,6 +50,10 @@
-
-
-
-+
-+
-+
-+
-
-
-
---
diff -Nru libjgroups-java-2.7.0.GA/debian/patches/series libjgroups-java-2.12.2.Final/debian/patches/series
--- libjgroups-java-2.7.0.GA/debian/patches/series 2010-02-28 10:17:05.000000000 +0000
+++ libjgroups-java-2.12.2.Final/debian/patches/series 1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-0001-define-jg.classpath-before-using-it.patch
diff -Nru libjgroups-java-2.7.0.GA/debian/rules libjgroups-java-2.12.2.Final/debian/rules
--- libjgroups-java-2.7.0.GA/debian/rules 2011-10-22 22:04:44.000000000 +0000
+++ libjgroups-java-2.12.2.Final/debian/rules 2011-12-22 01:00:28.000000000 +0000
@@ -10,13 +10,15 @@
#DEB_ANT_CHECK_TARGET := -Djgroups.bind_addr=`hostname` all-tests
DEB_JARS := xalan2 serializer junit log4j-1.2 bsh commons-logging bcprov glassfish-javaee ant-junit \
testng
-ANT_OPTS := -Dant.build.javac.source=1.5 -Dant.build.javac.target=1.5
+ANT_OPTS := -Dant.build.javac.source=1.6 -Dant.build.javac.target=1.6
install/libjgroups-java::
- mh_installpom -plibjgroups-java jgroups-pom.xml
- mh_installjar -plibjgroups-java jgroups-pom.xml -l dist/jgroups-core.jar
- install -m 644 -D dist/jgroups-all.jar $(DEB_DESTDIR)/usr/share/java/jgroups-all-$(DEB_UPSTREAM_VERSION).jar
- dh_link /usr/share/java/jgroups-all-$(DEB_UPSTREAM_VERSION).jar /usr/share/java/jgroups-all.jar
+ mh_installpom -plibjgroups-java pom.xml
+ mh_installjar -plibjgroups-java pom.xml -l dist/jgroups-2.12.2.Final.jar
get-orig-source:
- uscan --download-version $(DEB_UPSTREAM_VERSION) --force-download --rename
+ uscan --debug --download-version `echo $(DEB_UPSTREAM_VERSION) | sed -e 's/\./_/g'` --force-download --rename
+
+clean::
+ rm -rf debian/.mh
+ rm -f build.properties
diff -Nru libjgroups-java-2.7.0.GA/doc/Announcement-2.4.txt libjgroups-java-2.12.2.Final/doc/Announcement-2.4.txt
--- libjgroups-java-2.7.0.GA/doc/Announcement-2.4.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/Announcement-2.4.txt 1970-01-01 00:00:00.000000000 +0000
@@ -1,165 +0,0 @@
-
-// $Id: Announcement-2.4.txt,v 1.2 2006/10/31 12:44:45 belaban Exp $
-
-
-Finally, after almost 5 months, JGroups 2.4 is here !
-
-There are some cool features that I'll describe in more detail
-below. Over 80 JIRA issues were resolved in 2.4, mostly bug fixes and
-new functionality.
-
-The good news is that 2.4 is API-backward compatible with all previous
-versions down to and including 2.2.7. So, for those folks who are
-using JBoss 4.0.x, which ships with JGroups 2.2.7 by default, this
-means that they can simply replace their JGroups JAR file with the one
-from 2.4 and benefit from the performance enhancements and bug fixes
-that went into 2.4. For details on the JBoss/JGroups combinations see
-http://labs.jboss.com/portal/jbosscache/compatibility/index.html.
-
-I'll now describe the new features briefly, check out the
-documentation (URL below) for a full discussion.
-
-
-FLUSH
------
-
-Flush is a feature that - whenever the group membership is to be
-changed, or a state to be transferred - we tell every node in the
-cluster to stop sending messages and then join/leave a node, or
-transfer the state. When done, we tell all members to resume message
-sending.
-
-Why is this needed ?
-
-In 2 cases: (1) when we use a Multiplexer (see below) and have
-multiple services sharing the same channel that require state transfer
-and (2) when we want virtual synchrony (see below).
-
-So, if you don't use the Multiplexer or don't need virtual synchrony,
-you don't need the FLUSH protocol in your configuration. FLUSH is
-quite expensive because it uses multiple rounds of multicasts across
-the cluster, so remove it if you don't need it. Note that JBoss 5
-requires FLUSH because it uses the Multiplexer: all cluster services
-share one JGroups channel.
-
-
-Multiplexer
------------
-
-The Multiplexer was mainly developed to accommodate multiple services
-running on top of the *same* channel. JGroups channel are quite
-expensive in their use of resources (mainly threads) and sharing a
-channel amortizes a channel over multiple services.
-
-This is beneficial in JBoss where we had 5 clustered services (in
-4.0.x), each using its own channel. In JBoss 5, we switched to the
-Multiplexer, and all 5 services use the same shared channel. Startup
-time in JBoss 5 ('all' configuration) was 43s on my laptop before the
-change, and 23s afterwards !
-
-If multiple services sharing a channel require state transfer, we run
-into the problems described in
-JGroups/doc/design/PartialStateTransfer.txt. FLUSH is required to
-prevent those problems.
-
-The Multiplexer is described in chapter 6.3 of the documentation (see
-below).
-
-
-Streaming state transfer
-------------------------
-
-So far, state has always been transferred using a byte[] buffer. This
-forced a user to serialize the entire state into a byte[] buffer at
-the state provider and unserialize the byte[] buffer into the
-application state at the state requester. If the state is 2GB or more,
-this might likely result in memory exhaustion.
-
-Streaming state transfer uses input and output streams, so users can
-stream their state to the output stream in *chunks* and don't need to
-have the entire state in memory as required by a byte[] buffer. On the
-receiving side, an input stream is provided from which the user can
-read the entire state and set the application state to it.
-
-Streaming state transfer is essential for large states !
-
-
-Partial state transfer
-----------------------
-
-This allows a programmer to transfer a subset of the entire state,
-identified by an ID. We use this (via JBossCache) in JBoss HTTP
-session replication/buddy replication, where only the state
-represented by a buddy is transferred.
-
-
-Virtual Synchrony
------------------
-
-Virtual Synchrony is a model of group communication, developed by Ken
-Birman at Cornell, which has the following properties:
-#1 All non-faulty members see the same set of messages between views
-#2 A message M sent by P in view V must be received by P in V, unless
-P crashes
-#3 All non-faulty members receive the same sequence of views
-
-With FLUSH, we re-implemented the old virtual synchrony implementation
-of JGroups (vsync.xml), which I wrote in 1998/1999, but which has
-never been tested rigorously. We will phase out the old implementation
-in 3.0, along with other reorganizations of the protocol stack
-packages.
-
-Note that we have not yet *fully* implemented virtual synchrony as
-flushing only flushes out messages *sent* by member P, but not those
-*received* by P. Therefore, if member A sends a message M to {A,B,C},
-and crashes immediately afterwards, and only B received M, then C will
-*not* receive M (violating rule #1 above). We will fully implement
-this in JGroups 2.5 (http://jira.jboss.com/jira/browse/JGRP-341).
-
-
-View bundling
--------------
-
-When a large number of nodes join or leave a cluster at about the same
-time, we can collect all JOIN/LEAVE requests and create only 1
-view. View installation is quite costly, especially if FLUSH is used,
-which requires some round trips across the cluster, and so we minimize
-them.
-
-
-Failure detection
------------------
-
-We have 2 new protocols: FD_PING and FD_ICMP which allow for scripts
-to be run in order to check the health of a node (FD_PING) and ICMP to
-ping a machine (FD_ICMP). These can of course be combined with other
-failure detection protocols, such as FD or FD_SOCK.
-
-
-Updated documentation
----------------------
-
-The new features have been added to the documentation at
-http://www.jgroups.org/javagroupsnew/docs/manual/html/index.html
-
-
-JIRA issues
------------
-
-The issues that went into 2.4 can be found at
-http://jira.jboss.com/jira/browse/JGRP.
-
-
-Acknowledgments
----------------
-
-I'd like to thank Vladimir Blagojevic for writing the FLUSH and
-streaming/partial state transfer features, and for testing them
-thoroughly !
-
-
-
-Enjoy !
-
-Bela Ban, Red Hat Inc
-Kreuzlingen, Oct 31 2006
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/bugs/Digest.txt libjgroups-java-2.12.2.Final/doc/bugs/Digest.txt
--- libjgroups-java-2.7.0.GA/doc/bugs/Digest.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/bugs/Digest.txt 1970-01-01 00:00:00.000000000 +0000
@@ -1,28 +0,0 @@
-
-Digest on view changes
-======================
-
-Author: Bela Ban
-Version: $Id: Digest.txt,v 1.1 2006/01/26 09:23:16 belaban Exp $
-
-
-With STATE_TRANSFER we disable message garbage collection with SUSPEND_STABLE for the duration of the state transfer
-and later resume it with RESUME_STABLE. However, we don't do this for regular view changes, e.g. when a new member joins.
-
-The problem is:
-- Member A is in the group
-- Member B joins
-- Member A (as coord) sent 5 messages and therefore returns 5 as digest (assuming it has received all 5 messages yet)
-- Member B receives the JoinRsp and installs the digest of A:5
-- In the meantime, member A sent another 10 messages, which triggered garbage collection of messages
- A:0 - A:13 (just as example), so A has only messages 13-15 in its sent_table
-- A sends another message (A:16)
-- Upon reception of A:16, B requests retransmission of A:6 - A:16
-- A will not be able to serve that request because it garbage collected messages up to 13
-
-
-SOLUTION:
-- Same as with STATE_TRANSFER:
-- On JOIN request, send down a SUSPEND_STABLE
-- When JOIN request handling has processed (e.g. after receiving all VIEW_ACKs ?), send a RESUME_STABLE down
-- Does this need to be done only on JOIN or also on LEAVE ?
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/bugs/MergeProblem.txt libjgroups-java-2.12.2.Final/doc/bugs/MergeProblem.txt
--- libjgroups-java-2.7.0.GA/doc/bugs/MergeProblem.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/bugs/MergeProblem.txt 1970-01-01 00:00:00.000000000 +0000
@@ -1,79 +0,0 @@
-
-
-Merge problem in GMS/MERGE2
-===========================
-
-Author: Bela Ban
-Version: $Id: MergeProblem.txt,v 1.1 2006/01/27 14:46:11 belaban Exp $
-
-Symptom: first merge works, subsequent merges don't work
-Unit test: MergeStressTest
-
-The problem is that when many members join, we increment the VID (ViewID) every time we multicast a new view.
-Say we have subgroups {A,B,C} and {D,E}. The merge is now started by MERGE2, detecting 2 coordinators (A and D).
-The VID are 4 for {A,B,C} and 6 for {D,E}.
-The merge coordinator (A) therefore picks VID=7 for the MergeView. It now sends a request to both A and D, to multicast
-the new MergeView to their respective subgroups.
-However, let's assume that in the meantime, other members have joined one of the 2 subgroups, so that the VIDs are now:
-
-{A,B,C}: VID=9
-{D,E}: VID=5
-
-When the MergeView is received, it will be rejected by {A,B,C} because its own VID of 9 is greater than the
-MergeView's VID of 7. However, subgroup {D,E} will accept the MergeView because its own VID of 5 is smaller than the
-MergeView's VID of 7 !
-
-So now the
-A, B and C have a membership of {A,B,C} with VID=9
-but
-D and E have a membership of {A,B,C,D,E} with VID=7 !
-
-One of the consequences of this is that D will cease sending out MERGE2 requests, because it thinks it is not
-the coordinator anymore ! This means we will not get any MERGE2 events into the GMS layer anymore, which would
-cause another merge, this time with a higher VID for the MergeView.
-
-Possible SOLUTIONs:
-
-#1 Pick a VID for MergeViews that is high enough to be accepted by all subgroups
-#2 Suspend generating view changes while a merge is in progress
-#3 All JOIN, LEAVE and MERGE requests need to be handled by ViewBroadcaster (rename this!), check out
- ViewHandling.txt for details
-
-Comments:
-
-- #1 doesn't work well because then all previously generated views will be discarded, but clients already
- *have* the views !
-
-- We have to process VIEWS and MERGE requests in order, possibly we need to flush the ViewBroadcaster and suspend
- view generation until the merge has been handled, then resume view generation
-
-- Therefore #2 looks more promising: on merge() we flush the ViewBroadcaster (send out all pending views) on *all*
- coordinators involved. Then we process the merge, generate and mcast the new MergeView, then resume
- ViewBroadcaster. Probably JOIN and LEAVE requests need to be handled by ViewBroadcaster too
-
-
-Design:
--------
-
-On MERGE_REQ:
-- suspendViewHandler()
-
-On CANCEL_MERGE:
-- resumeViewHandler()
-
-On firing of MergeCanceller:
-- If MergeCancellers merge_id == current merge_id:
- - resumeViewHandler()
-
-On INSTALL_MERGE_VIEW:
-- Install view
-- resumeViewHandler()
-
-suspendViewHandler():
-- Complete current task, remove all other requests from queue
-- Make view handler discard all new requests from now on
-- Start MergeCanceller (if not started yet)
-
-resumeViewHandler():
-- Stop MergeCanceller
-- Make view handler accept all requests from now on
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/CONFIGURATIONS libjgroups-java-2.12.2.Final/doc/CONFIGURATIONS
--- libjgroups-java-2.7.0.GA/doc/CONFIGURATIONS 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/CONFIGURATIONS 1970-01-01 00:00:00.000000000 +0000
@@ -1,133 +0,0 @@
-## $Id: CONFIGURATIONS,v 1.2 2007/11/19 16:07:53 belaban Exp $
-
-
- Frequently used protocol stack specifications
- =============================================
-
-
-
-
-Virtual Synchrony & State Transfer Protocol Stack
--------------------------------------------------
-
-UDP:
-PING(num_initial_members=2;timeout=3000):
-FD:
-STABLE:
-NAKACK:
-UNICAST:
-FRAG:
-FLUSH:
-GMS:
-VIEW_ENFORCER:
-STATE_TRANSFER:
-QUEUE
-
-
-Properties:
-
-Uses Virtual Synchrony. All messages sent in a view V1 are delivered in
-that view. The FLUSH protocol makes sure that, when a new view V2 is to
-be installed, that all messages sent in V1 will be seen by all members
-of V1 before V2 is installed. The FLUSH protocol stops all sending
-until V2 has been installed successfully at all members. Messages sent
-after the block has been received and before V2 is installed will be
-sent in V2.
-
-
-Protocols:
-
-UDP: uses UDP/IP multicast as transport
-
-PING: discovers initial set of members, determines coordinator to
- which the join-request will be sent
-
-FD: failure detection based on periodic pinging of member 'to the
- right' in the membership ring
-
-STABLE: garbage collection of messages seen by all members
-
-NAKACK: guarantees lossless 1-m message delivery, uses negative acks
- to retransmit lost messages
-
-UNICAST: guarantees lossless 1-1 message delivery, uses positive acks
- to retransmit lost messages
-
-FRAG: fragments large messages into smaller ones and reassembles them
- at the receiving side
-
-FLUSH: flushes all pending multicasts out of the system before
- transitioning to a new view. Ensures that all members of view
- V1 agree on the set of messages they delivered in V1.
-
-GMS: group membership service. Takes care of joining/leaving members
-
-VIEW_ENFORCER: only accepts messages from senders in the same
- view. Stores messages for future view, discards messages
- sent in previous view.
-
-STATE_TRANSFER: allows any member to fetch the state from any other
- member (usually done immediately after joining)
-
-QUEUE: queues messages sent during a view transition. When the new
- view is installed, the stored messages will be sent.
-
-
-
-
-
-
-Pbcast-based Protocol Stack
----------------------------
-
-UDP(mcast_addr=228.1.2.3;mcast_port=45566;ip_ttl=0):
-PING(timeout=5000;num_initial_members=6):
-FD_SOCK:
-VERIFY_SUSPECT(timeout=1500):
-pbcast.STABLE(desired_avg_gossip=10000):
-pbcast.NAKACK(gc_lag=5;retransmit_timeout=3000;trace=true):
-UNICAST(timeout=5000;min_wait_time=2000):
-FRAG(down_thread=false;up_thread=false):
-pbcast.GMS(join_timeout=5000;shun=false;print_local_addr=true)
-
-
-Properties:
-
-Defines a stack with weaker reliability semantics than the Virtual Synchrony protocol
-stack. The biggest difference is that there is no guarantee that the set of messages
-sent between views is the same (no FLUSH protocol). Essentially defines a reliable 1-m
-protocol, where views are just regular messages and have no special semantics.
-
-
-Protocols:
-
-UDP: uses UDP/IP multicast as transport. Uses a time-to-live of 0
-
-PING: discovers initial set of members, determines coordinator to
- which the join-request will be sent. Will wait for 5 seconds or 6 members to
- respond (whichever is first)
-
-FD_SOCK: failure detection based on TCP socket connection from each member to the
- member 'to the right' in the membership ring. When connection breaks, member
- is suspected. Compared to FD, there are no periodic ping messages sent
-
-VERIFY_SUSPECT: reduces false suspicions. Verifies that a member P that is suspected
- is really dead by sending a ping message to P.
-
-pbcast.STABLE: garbage collection of messages seen by all members using gossips. A
- gossip is multicast every 10 seconds on average by each member.
-
-pbcast.NAKACK: guarantees lossless 1-m message delivery, uses negative acks
- to retransmit lost messages
-
-UNICAST: guarantees lossless 1-1 message delivery, uses positive acks
- to retransmit lost messages
-
-FRAG: fragments large messages into smaller ones and reassembles them
- at the receiving side
-
-pbcast.GMS: group membership service. Takes care of joining/leaving members
-
-
-
-
diff -Nru libjgroups-java-2.7.0.GA/doc/design/AddressTranslation.txt libjgroups-java-2.12.2.Final/doc/design/AddressTranslation.txt
--- libjgroups-java-2.7.0.GA/doc/design/AddressTranslation.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/AddressTranslation.txt 2011-10-18 11:22:35.000000000 +0000
@@ -1,4 +1,3 @@
-// $Id: AddressTranslation.txt,v 1.1 2006/01/27 14:46:12 belaban Exp $
On multi-homed systems, the identity of a member is bound to a NIC (either chosen by the OS, or by the
user through bind_addr): Address. When a message is sent, the msg contains this address as the sender's
diff -Nru libjgroups-java-2.7.0.GA/doc/design/AUTH.txt libjgroups-java-2.12.2.Final/doc/design/AUTH.txt
--- libjgroups-java-2.7.0.GA/doc/design/AUTH.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/AUTH.txt 2011-10-18 11:22:35.000000000 +0000
@@ -4,7 +4,6 @@
========================================
Author: Roland Raez, Bela Ban, Chris Mills
-Version: $Id: AUTH.txt,v 1.1 2006/01/27 14:46:12 belaban Exp $
Goal: to prevent random members from joining a group. Members have to pass authentication
to join a group, otherwise they will be rejected
diff -Nru libjgroups-java-2.7.0.GA/doc/design/Bundling.txt libjgroups-java-2.12.2.Final/doc/design/Bundling.txt
--- libjgroups-java-2.7.0.GA/doc/design/Bundling.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/Bundling.txt 2011-10-18 11:22:35.000000000 +0000
@@ -4,7 +4,6 @@
Message bundling
================
-// Version: $Id: Bundling.txt,v 1.1 2006/01/27 14:46:12 belaban Exp $
// Author: Bela Ban
Init:
diff -Nru libjgroups-java-2.7.0.GA/doc/design/CLOUD_TCP.txt libjgroups-java-2.12.2.Final/doc/design/CLOUD_TCP.txt
--- libjgroups-java-2.7.0.GA/doc/design/CLOUD_TCP.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/CLOUD_TCP.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,43 @@
+
+
+Changes to TCP to make it scale better in a cloud
+=================================================
+
+Author: Bela Ban
+
+
+Problem:
+--------
+
+In many cloud services (EC2, rackspace, GAE), IP multicasting is not allowed, therefore users of JGroups have to switch
+to TCPGOSSIP:TCP in conjunction with a GossipRouter for initial lookup.
+
+With TCP, we send a cluster wide message to N-1 nodes (with UDP, we send it only once). This doesn't scale with
+increasing clusters. Even if we parallelize this, all the traffic from us to each node has to go through the switch,
+taxing our full-duplex line to the switch.
+
+Solution:
+---------
+
+Eliminate the N-1 problem by sending a cluster-wide message only to our neighbor. The neighbor then sends it to its
+neighbor and so on. Each message has a header with a TTL, which is equal to the cluster size. When a (cluster wide)
+message is received, we decrement the TTL in the header and forward it to our neighbor (unless the TTL is 0, then we
+discard it).
+
+For retransmissions, we send an XMIT-REQ to the original sender the first time, then to its neighbor, then to the
+next neighbor and so on.
+
+
+Implementation:
+---------------
+
+This functionality can probably be done in a subclass of TCP (or maybe even be integrated into TP !).
+
+Update: IMO a better approach is to create a new protocol layered on top of the transport. This way, we can use this
+functionality with other transports as well.
+
+Take a look at Ron Levy's EPFL paper [1] for a similar approach.
+
+
+[1] http://infoscience.epfl.ch/getfile.py?docid=7701&name=paper&format=pdf&version=1
+[2] infoscience.epfl.ch/record/149218/files/paper.pdf
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/design/ConcurrentConnectionEstablishment.txt libjgroups-java-2.12.2.Final/doc/design/ConcurrentConnectionEstablishment.txt
--- libjgroups-java-2.7.0.GA/doc/design/ConcurrentConnectionEstablishment.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/ConcurrentConnectionEstablishment.txt 2011-10-18 11:22:35.000000000 +0000
@@ -1,6 +1,5 @@
-// Version: $Id: ConcurrentConnectionEstablishment.txt,v 1.3 2007/09/19 12:42:43 belaban Exp $
// Author: Bela Ban
diff -Nru libjgroups-java-2.7.0.GA/doc/design/ConcurrentStack.txt libjgroups-java-2.12.2.Final/doc/design/ConcurrentStack.txt
--- libjgroups-java-2.7.0.GA/doc/design/ConcurrentStack.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/ConcurrentStack.txt 2011-10-18 11:22:35.000000000 +0000
@@ -4,7 +4,6 @@
================
Author: Bela Ban
-Version: $Id: ConcurrentStack.txt,v 1.1 2006/12/27 10:02:04 belaban Exp $
JIRAs:
http://jira.jboss.com/jira/browse/JGRP-180 (harden stack)
http://jira.jboss.com/jira/browse/JGRP-181 (concurrent stack)
diff -Nru libjgroups-java-2.7.0.GA/doc/design/ConcurrentStartupTest.txt libjgroups-java-2.12.2.Final/doc/design/ConcurrentStartupTest.txt
--- libjgroups-java-2.7.0.GA/doc/design/ConcurrentStartupTest.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/ConcurrentStartupTest.txt 2011-10-18 11:22:35.000000000 +0000
@@ -3,7 +3,6 @@
=====================================
// Author: Bela Ban
-// Version: $Id: ConcurrentStartupTest.txt,v 1.2 2006/05/20 22:02:12 belaban Exp $
The unit test org.jgroups.tests.ConcurrentStartupTest simulates multiple nodes in a cluster being started at the same
diff -Nru libjgroups-java-2.7.0.GA/doc/design/DataCenterReplication.txt libjgroups-java-2.12.2.Final/doc/design/DataCenterReplication.txt
--- libjgroups-java-2.7.0.GA/doc/design/DataCenterReplication.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/DataCenterReplication.txt 2011-10-18 11:22:35.000000000 +0000
@@ -3,7 +3,6 @@
================================
Author: Bela Ban
-Version: $Id: DataCenterReplication.txt,v 1.9 2008/07/02 11:24:37 belaban Exp $
We have data centers in New York (NYC) and San Francisco (SFO). The idea is to replicate traffic from NYC to SFO
asynchronously. In case of a site failure of NYC, all clients can be switched over to SFO and continue working with
@@ -100,4 +99,8 @@
No, doesn't work ! The relay would have to be active on every node ! This is not feasible as this would require
every node to have a TCP connection to NYC ! We still need to do it on reception not sending. However, messages
-cannot exclude the sender
\ No newline at end of file
+cannot exclude the sender
+
+*****************************************************
+*** UPDATE: this design is continued in RELAY.txt ***
+*****************************************************
diff -Nru libjgroups-java-2.7.0.GA/doc/design/FILE_PING.txt libjgroups-java-2.12.2.Final/doc/design/FILE_PING.txt
--- libjgroups-java-2.7.0.GA/doc/design/FILE_PING.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/FILE_PING.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,41 @@
+
+
+Design of FILE_PING
+===================
+
+Author: Bela Ban
+
+
+Goal
+----
+
+FILE_PING is a shared storage based discovery; during the discovery process,
+new nodes read the addresses of existing members from a shared store.
+
+Members write their addresses to the store and remove them on leaving the cluster.
+
+
+Design
+------
+
+FILE_PING takes as property a 'location' which is the location of a directory in a shared store, e.g. /share/jgroups.
+Each cluster X creates a subdirectory X, where all files for cluster X reside.
+
+A member writes its local address (plus physical address mappings) to a file which is named after the local address.
+Example: /share/jgroups/DemoCluster/linux-433234.dat. (Maybe we should use the UUID !)
+
+A new member reads all files in DemoCluster and sends the discovery request to all addresses resulting from this.
+
+When a member leaves, it removes its file from DemoCluster. We could use File.removeOnExit() to do this automatically.
+(However, kill -9 doesn't remove the file).
+
+We still need to periodically clean up members who crashed (kill -9). This could be done via an age out cache.
+
+
+Notes
+-----
+
+In 2.6.x, we don't have logical addresses, therefore we don't need the discovery messages to ship logical-physical
+address mappings around. As an optimization, we could read all files and see if we have an element tagged as
+coordinator. If so, we could directly send a JOIN request to the coord, rather than sending discovery messages.
+If there is no coordinator, we go through the regular discovery message sending process.
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/design/FlowControl.txt libjgroups-java-2.12.2.Final/doc/design/FlowControl.txt
--- libjgroups-java-2.7.0.GA/doc/design/FlowControl.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/FlowControl.txt 2011-10-18 11:22:35.000000000 +0000
@@ -1,4 +1,3 @@
-// Version: $Id: FlowControl.txt,v 1.1 2006/01/27 14:38:35 belaban Exp $
// Author: Bela Ban
diff -Nru libjgroups-java-2.7.0.GA/doc/design/FLUSH2.txt libjgroups-java-2.12.2.Final/doc/design/FLUSH2.txt
--- libjgroups-java-2.7.0.GA/doc/design/FLUSH2.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/FLUSH2.txt 2011-10-18 11:22:35.000000000 +0000
@@ -4,7 +4,6 @@
=============
Author: Bela Ban
-Version: $Id: FLUSH2.txt,v 1.5 2007/10/22 19:46:52 belaban Exp $
Prerequisites:
- A flush is always started and stopped by the *same* member, both for joins and state transfer
@@ -82,4 +81,63 @@
Reconciliation phase (in NAKACK):
- Sends XMIT requests for message not in local digest, but in digest received from REBROADCAST_MSGS
- Wait until local digest (updated when missing messages are received) is same as digest received from REBROADCAST_MSGS
-- Takes suspects into account
\ No newline at end of file
+- Takes suspects into account
+
+
+
+
+Concurrent flushes
+------------------
+
+- Concurrent flushes to overlapping member sets will cause only 1 flush to succeed, and all others to fail
+
+- A failed flush set the flushInProgress flag back to false on all members on which it successfully set it
+
+- Algorithm:
+ - Send a START-FLUSH to all members in the target set
+ - Every member sets the flushInProgress flag to true
+ - If this succeeds, the member sends back an OK
+ - Else a FAIL is sent back
+ - If we received OKs from all members, startFlush() succeeded and returns true
+ - If 1 FAIL is received:
+ - Send an ABORT-FLUSH to all members which took part in the flush, causes flushInProgress to be set to false
+ - startFlush() failed and returns false
+
+
+Concurrent total flushing (members={A,B,C,D})
+---------------------------------------------
+
+- In general, concurrent total flushes are not allowed
+
+- Concurrent flushes on the same member:
+ - The first thread to call Channel.startFlush() runs the flush phase
+ - Subsequent threads to call Channel.startFlush() block until the current flush phase has completed
+ (Channel.stopFlush())
+
+- Concurrent flushes on different members:
+ - A.startFlush() and B.startFlush() are called concurrently
+ - A sends a START-FLUSH to all members, and so does B
+ - When a START-FLUSH is received, a flag 'flushing-in-progress' is set
+ - If flushing-in-progress cannot be set (because another flush protocol is running), we send back a
+ START-FLUSH-FAIL. (We might add a small timeout to block until flushing-in-progress can be acquired)
+ - On reception of a START-FLUSH-FAIL, we 'roll back' the flush, setting all of our acquired 'flushing-in-progess'
+ flags back to false
+ - SUMMARY: either A fails, or B fails, or both A and B fail in a concurrent flush phase (similar to concurrent
+ transactions)
+
+
+Concurrent partial flushing (members={A,B,C,D})
+-----------------------------------------------
+
+- In general, concurrent partial flushes are not allowed (same as for concurrent total flushes)
+
+
+
+
+
+
+
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/doc/design/FLUSH.txt libjgroups-java-2.12.2.Final/doc/design/FLUSH.txt
--- libjgroups-java-2.7.0.GA/doc/design/FLUSH.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/FLUSH.txt 2011-10-18 11:22:35.000000000 +0000
@@ -3,7 +3,6 @@
================================
Author: Bela Ban
-Version: $Id: FLUSH.txt,v 1.11 2007/11/08 14:34:52 vlada Exp $
See http://jira.jboss.com/jira/browse/JGRP-82
Overview
diff -Nru libjgroups-java-2.7.0.GA/doc/design/GossipRouterChanges-1.8.txt libjgroups-java-2.12.2.Final/doc/design/GossipRouterChanges-1.8.txt
--- libjgroups-java-2.7.0.GA/doc/design/GossipRouterChanges-1.8.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/GossipRouterChanges-1.8.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,108 @@
+
+
+Changes to GossipRouter in 2.8
+==============================
+Author: Bela Ban
+
+
+Motivation
+----------
+
+The changes are mainly due to logical addresses and shared transport.
+
+TCPGOSSIP currently doesn't work, as the GossipRouter doesn't return logical addresses *and* their associated physical
+addresses, but only returns logical addresses (UUIDs) [1].
+
+In TUNNEL, RouterStubs are conceptually associated with a single channel, and cannot process traffic from multiple
+channels on top of a shared transport.
+
+[1] https://jira.jboss.org/jira/browse/JGRP-1005
+[2] https://jira.jboss.org/jira/browse/JGRP-924
+
+
+Design overview
+---------------
+
+A RouterStub will simply establish a TCP connection with a GossipRouter, but doesn't send the CONNECT message on
+socket establishment. This is typically done in init() of TUNNEL (or TCPGOSSIP).
+
+On channel connection, a CONNECT(groupname, logical_addr, logical_name, physical_addresses) is sent to the
+GossipRouter.
+
+On a GET-MEMBERS(groupname), the GR returns a list of elements.
+
+On a ROUTE(groupname, logical_addr, message), the GR pick the single destination (if logical-addr is not null) and
+routes the message. If logical_addr is null, then the GR routes the message to all members keyed by groupname.
+
+The GossipRouter maintains the following data structures:
+
+- RoutingTable:
+ - A hashmap with groupnames as keys and hashmaps as values
+ - The 2nd level hashmaps have logical addresses as keys and ConnectionHandlers as values
+ - A ConnectionHandler represent a physical connection to a client. It has a thread listening for messages on the
+ input stream, and it also has a list of logical_addrs from which it received CONNECT messages.
+ - When the socket in the ConnectionHandler is closed by the peer, we remove all entries associated with all
+ logical_addrs of ConnectionHandler from the other data structures.
+
+- AddressMappings:
+ - Maintains a hashmap with logical_addrs as keys and the physical_addrs as value
+ - This is used to map logical addresses to their physical addresses, and is only used by TCPGOSSIP
+
+
+Implementation
+--------------
+
+RouterStub
+----------
+- When started, the RouterStub establishes a socket to the GossipRouter's address:port given
+- When the connection is closed by the GR, the stub goes into reconnecting mode. When reconnected, it issues
+ a notification so registered listeners can send a CONNECT (see below) to the GR again
+- When the CONNECT event is received by TUNNEL / TCPGOSSIP, RouterStub.connect() is called with
+ - the groupname
+ - the logical address
+ - the logical name
+ - a list of physical addresses (might be null, only used by TCPGOSSIP)
+- This generates a CONNECT message which is sent to the GossipRouter
+
+
+GossipRouter
+------------
+
+- On accept():
+ - Create a new ConnectionHandler on a new thread (from the thread pool)
+ - This stores the client socket, input and output stream, then listens on the input stream
+ [- We might add the ConnectionHandler to a separate list, just to keep track of open connections]
+
+- On peer (RouterStub) closing the socket:
+ - The ConnectionHandler gets an exception when listening on the input stream
+ - We remove the entries in connection-list from all tables
+
+- On CONNECT(groupname, logical_addr, logical_name, physical_addrs) [received by ConnectionHandler.run()]:
+ - The ConnectionHandler adds the logical address to its connection-list
+ - An entry is added to RoutingTable under groupname, and the value (hashmap) is updated:
+ - key is the logical addr, value the ConnectionHandler (this)
+ - If CONNECT ships with non-null physical_addrs, then an entry is added to AddressMappings
+
+
+- On DISCONNECT(logical_addr):
+ - Remove the entry for logical_addr from all tables (RoutingTable, AddressMappings)
+ - Do *not* close the socket in ConnectionHandler: others may still be connected through the same connection !
+
+
+- On GET_MEMBERS(groupname):
+ - Grabs the members for groupname (from RoutingTable and AddressMappings) and passes them back, for each member:
+ - The logical address
+ - The logical name
+ - (if available) a list of physical addresses
+
+- On ROUTE(groupname, dest, message):
+ - If dest == null (multicast):
+ - Grab all ConnectionHandler's from RoutingTable for groupname and send the message to all
+ - Else (unicast)
+ - Find the ConnectionHandler keyed by 'dest' and send the message to it
+
+TUNNEL
+------
+
+- On stub reconnect:
+ - Send a CONNECT message. With a shared transort, this has to be done for all channels sharing the transport
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/design/JDBC_PING.txt libjgroups-java-2.12.2.Final/doc/design/JDBC_PING.txt
--- libjgroups-java-2.7.0.GA/doc/design/JDBC_PING.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/JDBC_PING.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,71 @@
+
+
+Design of JDBC_PING
+===================
+
+Author: Sanne Ginovero
+
+
+Goal
+----
+
+JDBC_PING is a discovery protocol making use of a shared database; during the discovery process,
+new nodes read the addresses of existing members from a JDBC connection.
+
+The design is derived from FILE_PING, and the implementation extends it as there are many similarities.
+As with FILE_PING, also with JDBC_PING members write their addresses to the store and remove them on leaving the cluster.
+
+
+Usage
+------
+
+A database is needed, and a single table will be used. Something like the following is expected:
+
+CREATE TABLE JGROUPSPING (
+ own_addr varchar(200) NOT NULL,
+ cluster_name varchar(200) NOT NULL,
+ ping_data varbinary(5000) DEFAULT NULL,
+ PRIMARY KEY (own_addr, cluster_name)
+ )
+
+It's possible to change the table definitions, make sure to update the three SQL statements accordingly using the appropriate
+configuration properties:
+
+ initialize_sql - to customize the table creation SQL instructions
+ insert_single_sql - to insert a new row
+ delete_single_sql - to delete a single row
+ select_all_pingdata_sql - to load all ping_data having a specific cluster_name
+
+Connection properties to be set are either:
+
+1) JDBC direct connection
+
+ connection_url
+ connection_username
+ connection_password
+ connection_driver
+
+2) via a JNDI registered DataSource
+
+ datasource_jndi_name
+
+
+Design
+------
+
+Each node connects to the same database, and reads all Addresses related to his same cluster to find it's peers,
+and adds himself to the list.
+
+At stop(), a node attempts to cleanup the table by removing himself.
+
+Members who crashed should be removed by the same strategy of FILE_PING, actually it should inherit each eventual
+improvement.
+
+Warning:
+While the node stores the PingData instance of himself, to be retrieved by other nodes, it will nullify the View,
+as there's no interest in restoring the View instance and this could potentially not fit in the fixed column dimension
+allocated for a serialized PingData, or at least this variable is not fixed so storing View might make it hard to
+select a proper size.
+So consider that a restored PingData will have lost the information about the original View.
+
+
diff -Nru libjgroups-java-2.7.0.GA/doc/design/LargeClusters.txt libjgroups-java-2.12.2.Final/doc/design/LargeClusters.txt
--- libjgroups-java-2.7.0.GA/doc/design/LargeClusters.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/LargeClusters.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,38 @@
+
+
+Considerations for large clusters
+=================================
+
+Author: Bela Ban
+JIRA: https://jira.jboss.org/browse/JGRP-100
+
+
+Discovery
+---------
+
+
+
+ConcurrentHashMap
+-----------------
+
+CCHMs have a default initial capacity (16), load factor (0.75) and concurrency level (16). These are OK for most
+scenarios, but we have to investigate whether these values are sufficient for 1000 node clusters.
+
+When for example 1000 threads from different senders access the same CCHM, we need to make sure we don't have high
+contention, ie. by spreading a 1000 senders over 16 buckets.
+
+Investigate whether we should add CCHM initial sizes, load factors and concurrency levels as properties.
+
+With ergonomics [1], we could for example set bucket sizes for CCHMs dynamically, e.g. based on cluster size.
+
+
+
+[1] https://jira.jboss.org/jira/browse/JGRP-1037
+
+
+Misc
+----
+
+- MERGE2: num_initial_members in Discovery should be large, so that we detect partitions sooner
+- GMS: view bundling should be enabled, and max_bundling_time should be a bit larger than the default, as this
+ will allow for more concurrent joins and leaves before starting the view installation process
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/design/LargeMessages.txt libjgroups-java-2.12.2.Final/doc/design/LargeMessages.txt
--- libjgroups-java-2.7.0.GA/doc/design/LargeMessages.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/LargeMessages.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,53 @@
+
+Large messages in large clusters
+================================
+
+Author: Bela Ban
+
+Requirements
+------------
+- Large cluster
+- 1 sender, many receivers
+- Sender sends messages between 10MB and 200MB, in bursts
+
+Goals:
+------
+- Receivers discard message (purge it from memory) as soon as it has been delivered to the application
+- Sender discards message as soon as it has received acks from all receivers or a timeout has elapsed
+--> We don't want to keep 200MB messages in buffers longer than necessary
+- Don't allow single receiver to bog down the whole cluster (in times and memory foot print)
+
+
+Issues with existing protocols:
+-------------------------------
+- We cannot use STABLE for agreement, so that a sender can purge a message, because one or more slow receivers could
+ prevent stability messages to be sent. This is because STABLE requires agreement from all group members, and slow
+ members won't be able to agree, at least not fast enough.
+- We therefore wait for agreement from all members, but if a timeout elapses, the sender will purge the message anyway
+- Receivers are not guaranteed to receive all messages: if the sender purged a message after not having received acks
+ from all members, the receiver will not receive that message
+- However, even with message loss, all *received* messages will be delivered in order
+- We cannot use SMACK, which uses positive acks for each message, because that would lead to too many acks. If we for
+ example send a 200MB message and it is fragmented into 2000 fragments, we don't want to send an ack / fragment, but
+ we only want to send an ack per message, so after the entire 200MB message has been received
+
+Design:
+-------
+- A new protocol ACK, layered above FRAG2 (or any other fragmentation protocol)
+- When sending a message, ACK creates a list of members from which it needs to receive acks and starts a timer
+- When ACK receives a message it sends an ack back to the sender
+- When all acks have been received, ACK sends down a STABLE event, which will cause the sender's NAKACK protocol to
+ purge the message
+- When the timer kicks in, it returns if all acks have been received or (if not) sends a stability message around,
+ which causes all receivers to ask for retransmission of messages they haven't received yet. The timer cancels itself
+ after N attempts or when all acks have been received
+- The receivers also start a timer when the first retransmission of a message occurs
+- If a message has not been received after a timeout, the receivers will flag that message as not-received and stop
+ retransmission requests for it. When the special not-received message is removed, it won't be passed up
+
+
+Flow control:
+-------------
+
+- We cannot have a sender block on a credit missing from a slow member
+- Solution: use max_block_times in FC, which is already implemented
diff -Nru libjgroups-java-2.7.0.GA/doc/design/LogicalAddresses.txt libjgroups-java-2.12.2.Final/doc/design/LogicalAddresses.txt
--- libjgroups-java-2.7.0.GA/doc/design/LogicalAddresses.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/LogicalAddresses.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,243 @@
+
+
+Logical addresses
+=================
+
+Author: Bela Ban
+JIRA: https://jira.jboss.org/jira/browse/JGRP-129
+
+The address chosen by each node is essentially the IP address and port of the receiver socket. However, for the
+following reasons, this is not good enough:
+
+- Reincarnation: if we use fixed ports (bind_port is set), then a restarted (or shunned) node will have the same
+ address. If other nodes in the cluster don't clear their states before the reincarnated node comes up again, we'll
+ have issues (see JGRP-130 for details)
+
+- NIC failover: a NIC goes down, we want to continue sending/receiving on a different NIC
+
+- The sender sends on all available NICs (send_on_all_interfaces="true"). This means that -if we take the receiver's
+ datagram packet's address to be the identity of the sender - we get N different identities; 1 for each interface
+ the message is sent on
+
+- Network Address Translation: the sender's address might get changed by the NAT
+
+DESIGN:
+
+- A logical address consists of a unique identifier (UUID) and a logical name. The name is passed to JGroups when a
+ channel is created (new JChannel(String logical_name, String props)). If logical_name is null, JGroups picks a
+ logical name (which is not guaranteed to be unique though). The logical name stays with the channel until the latter
+ is destroyed
+
+- A UUID is represented by org.jgroups.util.UUID, which is a subclass of Address and consists of the least and
+ most significant bits variables copied from java.util.UUID. All other instance variables are omitted.
+ - The isMulticastAddress() method uses 1 bit out of the 128 bits of UUID
+ (Maybe we can remove this method and always represent multicast addresses as nulls, so UUIDs would only be used
+ to represent non multicast addresses)
+
+- All UUIDs have a reference to a static table which contains the mappings between logical names and UUIDs
+ (classloader issues ?)
+
+- The logical name is used in UUID.toString(), and the least and most significant bits are used for equals() and
+ hashCode()
+
+- A UUID is created on channel connect, deleted on channel disconnect and re-created on channel connect.
+ Since it is re-created on every connect(), it will prevent reincarnation issues
+
+Transport (TP)
+--------------
+
+TP maintains a cache of mappings between UUIDs and physical addresses. Whenever a message is sent, the physical address
+of the receiver is looked up from the cache.
+
+A UUID can have more than 1 physical address. We envisage providing a pluggable strategy which picks a physical
+address given a UUID. For example, a plugin could load balance between physical addresses.
+
+To exchange cache information, we'll use the existing Discovery protocol (see below).
+
+When a physical address for a given UUID is not present, a sender discards (or queues, TBD) the message and broadcasts
+a WHO-HAS message. Receivers then broadcast (or unicast) the UUID-physical address mapping.
+
+The discovery phase needs to return logical *and* physical addresses: on reception of a discovery request, we return
+our logical address (UUID) and the physical address(es) associated with it, plus the logical name. On reception
+of a discovery response, the transport places the physical addresses returned into its cache (if not yet present).
+See the scenarios below for details as to why this is needed.
+
+
+UDP startup
+-----------
+- The joiner multicasts a discovery request with its UUID, logical name and physical address(es)
+- The receivers' transports add this information into their caches
+- Each receiver unicasts a discovery response, containing the coordinator's address, plus its own UUID, logical
+ name and physical address(es)
+- On reception of a discovery response, the transport adds this information to its cache if not yet there
+
+
+TCPPING:TCP startup
+-------------------
+- The problem is that TCPPING has as initial_hosts the *physical* (not logical) addresses listed !
+- The joiner sends a discovery request to all physical addresses listed in initial_hosts
+- The dest_addr field of a discovery request message is the physical address
+- The transport usually expects UUIDs as addresses and finds the associated physical address in the cache
+- However, in this case, the transport re-uses the physical address (dest_addr) in the message, bypasses the
+ translation UUID --> physical address, and nulls dest_addr in Message
+- The destination address is now *null*. This works because Discovery/PING/TCPPING don't check the messages's
+ dest_addr field ! (Otherwise 'null' would be interpreted as a multicast destination !)
+- On the receiver side, the destination is not used for discovery
+- The response is sent back to the sender (Message.getSrc()), this is a UUID and will be translated back
+ into a physical address
+
+
+TCPGOSSIP:TCP startup
+---------------------
+- The joiner asks the GossipRouter for a list of nodes for a given cluster name
+- The information returned contains a list of nodes, for each node:
+ - The logical address (UUID)
+ - The logical name
+ - The physical address(es) associated with the UUID
+- The joiner's transport adds this information to its cache
+- Then each node of the initial membership is sent a discovery request
+- The rest is the same as for UDP
+
+
+TCPGOSSIP:TUNNEL startup
+------------------------
+- Same as for TCPGOSSIP:TCP, but here we don't really need the physical addresses, because we send every request
+ to the GossipRouter anyway (via our TCP connection to it)
+- The physical address will simply be ignored
+
+
+ARP-like functionality
+----------------------
+- This is handled by Discovery
+- We'll add WHO-HAS, I-HAVE and INVALIDATE message handling to Discovery
+- The Discovery and transport protocols communicate via events
+- When the transport wants to send a message whose destination UUID is not in its cache, it sends a (non-blocking)
+ WHO-HAS up the stack which is handled by Discovery. Meanwhile the message is queued (bounded queue).
+- Discovery sends a WHO-HAS(UUID) message (multicast if PING, sent to initial_hosts in TCPPING, or sent to the
+ GossipRouter if TCPGOSSIP)
+- On reception of I-HAVE, Discovery sends the result down the stack via an I-HAVE event
+- When the transport receives an I-HAVE event, it updates its local cache and then tries to send the queued messages
+- A discovery request also ships the logical name and physical address(es)
+- A discovery response also contains these items
+- When a discovery request or response is received, the cache is updated if necessary
+- When a channel is closed, we send an INVALIDATE(UUID) message around, which removes the UUID from UUID.cache and
+ the transport's cache in all cluster nodes
+
+
+
+Runtime scenarios
+-----------------
+
+Startup
+-------
+- The transport stores the logical name (generated if user didn't pass one to the JChannel() constructor)
+- On connect:
+ - The UUID is generated (local address) and associated with the logical name (in UUID.cache)
+ - The local socket is created and associated with the UUID in the transport's cache
+- On disconnect: the local_addr (UUID) is nulled and removed from the transport's cache and UUID.cache
+- On close: an INVALIDATE(UUID) message is broadcast so every node can remove UUID from the transport's cache
+ and from UUID.cache
+
+Discovery
+---------
+- Discovery fetches the local_addr (UUID), logical name and physical address(es) from the transport via a
+ GET_PHYSICAL_ADDRESS
+- A discovery request containing this info is sent out (multicast, unicast via TCP or sent to the GossipRouter)
+- The receivers (Discovery protocols) fetch this info from the message and send it down to the transport
+ (via a SET_PHYSICAL_ADDRESS), which adds it to its cache and to UUID.cache
+- The receivers then fetch their own local information from the transport and send it along with the discovery
+ response
+- On reception of the discovery response, the requester extracts this info from the message and sends it
+ down to its transport, which adds it to its own local cache
+
+Sending of a message with no physical address available for UUID
+----------------------------------------------------------------
+- The transport queues the message
+- The transport sends a GET_PHYSICAL_ADDRESS *event* up the stack
+- The Discovery protocol sends out a GET_MBRS_REQ *message* (via multicast, TCP unicast, or to the GossipRouter)
+- The receivers fetch their local information from the transport (exception: the GossipRouter has this information
+ in its local loookup cache), and return it with a GET_MBRS_RSP message
+- On reception of the GET_MBRS_RSP message, a SET_PHYSICAL_ADDRESS event is sent down the stack to the transport
+- The transport updates its local cache from the information
+- The transport sends all queued messages if the UUID are now available
+
+
+On view change
+--------------
+- The coordinator's Discovery protocol broadcasts an INVALIDATE(UUID) message for each node which left the cluster
+- On reception, every receiver sends down a REMOVE_PHYSICAL_ADDRESS(UUID)
+- The transport then removes the mapping for the given UUID
+
+
+IDs instead of UUIDs
+--------------------
+- Implemented in TP or a separate protocol (ID ?)
+- The coordinator dishes out IDs (shorts) for new nodes
+- The IDs are always increasing
+- Every new ID is broadcast across the cluster, so everyone knows the highest IDs
+- An ID is associated with a UUID, and UUIDs are also associated with physical addresses (2 tables)
+- When we send a message to dest UUID, we lookup the ID associated with UUID. If found, we send the ID (a short)
+ rather than the UUID
+- On reception, if an ID is found, we create an IdAddress, which work on the short field for equals() and hashCode()
+- IdAddress.equals() and IdAddress.compareTo() can compare to both IdAddress *and* UUIDs: in the latter case, they
+ fetch the ID from the table given the UUID as key and do the comparison. UUIDs can also compare to IdAddresses
+- We should probably either add a PhysicalAddress interface, which inherits from Address, and have physical addresses
+ implement PhysicalAddress (so we can do an instanceof PhysicalAddress), or have an isPhysicalAddress() method
+- ID canonicalization should be configurable: we can enable or disable it
+- This could be used by an ID protocol (sitting on top of the transport), which maintains a UUID-ID table and *replaces*
+ dest and src addresses for messages coming in and going out
+- This protocol would replace an UUID dest with an IdAddress and provide the physical address as well (?)
+
+
+Shared transport and UUIDs
+--------------------------
+- With a shared transport, every channel has a local_addr: the transport itself cannot have a local_addr anymore. The
+ reason is that a channel could get shunned, leaves the cluster and then reconnects. However, because the address
+ of the shared transport hasn't changed, the rejoined member has the same address, thus chances of reincarnation are
+ higher
+- When a channel connects, it creates a new local_addr (UUID) and sends it down via SET_LOCAL_ADDRESS. The transport
+ then adds the UUID/physical address mapping to its cache
+- When we send a multicast message (dest == null), but don't have a multicast capable transport (e.g. UDP.ip_mcast=false)
+ or TCP/TCP_NIO, then we simply send it to all *physical* addresses in the transport's UUID cache.
+ If we don't currently have all physical addresses, that's fine because MERGE2 will eventually fetch all physical
+ addresses in the cluster
+
+
+TODOs
+-----
+- Multicast messages should always be null, so Address.isMulticastAddress() should not be needed anymore
+- GossipRouter: we need to register logical *and* physical addresses, plus the logical name
+- Find all uses of IpAddress and change them to SocketAddress (if possible), or try to use Address rather than
+ IpAddress
+- UUID: generate a nice name from UUID if the logical name is not defined. Alternative: don't use the UUID to generate
+ the logical name, but maybe the host name and a random short
+- Util.writeAddress()/writeAddresses(): currently optimized for IpAddress, change to UUID.
+ Example: View.writeTo()/readFrom()
+- How are we going to associate logical names to channels when a shared transport is used ?
+- Marshalled size of UUID: 18 bytes, IpAddress: 9 bytes. Size in memory (without superclass, additional_data, on
+ 64 bit machine): 16 bytes for UUID, 32 bytes for IpAddress ! So while marshalling takes more space for UUID,
+ it is quite compact in memory !
+ If it turns out that UUIDs generate too much overhead on the wire (bandwidth), we should think about canonicalizing
+ UUIDs to shorts: run an agreement protocol which assigns cluster-wide unique shorts to UUIDs, and send the shorts
+ rather than the UUIDs around !
+- UDP.initial_hosts also needs to send to physical addresses
+- Implement getPhysicalAddress() in all transports
+- BasicTCP.handleDownEvent(): view has to be handled in ProtocolAdapter and connections have to be closed there, too
+ --> The semantics of retainAll() have to be inspected: do we handle UUIDs or PhysicalAddresses ?
+ --> Should we switch to a model where ConnectionTable never reaps connections based on view changes, but based on
+ idle time ? Ie. reap a connection that hasn't been used for more than 30 seconds
+- TCPPING.initial_hosts="A,B": how will we find out about C, D and E ?
+
+
+- Shared transport
+ - Move setSourceAddress() from TP to JChannel ?
+ - Check whether thread names in a shared transport are still correct.
+ - Do thread names use the logical or UUID name of a channel ?
+ - Is Global.DUMMY still needed when we set the local address top down ?
+ - The 'members' variable in TP is a union of all memberships in the shared transport case
+ - In BasicTCP, we need to change retainAll() to use physical addresses rather than UUIDs stored ib TP.members
+ - Dito for suspected_mbrs
+ - In general, change all addresses in TCP to PhysicalAddresses. Or should we use logical addresses ?
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/doc/design/MarshalingFormat.txt libjgroups-java-2.12.2.Final/doc/design/MarshalingFormat.txt
--- libjgroups-java-2.7.0.GA/doc/design/MarshalingFormat.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/MarshalingFormat.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,60 @@
+
+// Author: Bela Ban
+
+
+Binary format for marshalled messages
+=====================================
+
+An org.jgroups.Message is marshalled to a byte stream as follows.
+
+- version ID: short (2 bytes). Version.encode() encodes the major, minor and patch version into the short.
+- flags (byte):
+ - single message or list of messages (LIST)
+ If single message --> SingleMessage, else MessageList
+ - multicast (MULTICAST) or unicast message (for optimizations)
+
+SingleMessage:
+- leading: byte. Has bits set for null src and dest addresses, buf and headers
+- flags: byte
+- src address: Address
+- [length of buf]: int
+- [buf]: byte[] array
+- [Headers]: list of headers --> Headers
+
+
+MessageList:
+- length: int. Number of messages in the list
+- src address: Address
+- 1-m Messages: --> SingleMessage, but with no src and dest addresses
+
+
+
+Headers:
+- length: int. Number of headers
+- For each Header:
+ - Key: UTF-8 string
+ - Header
+
+
+Header:
+- magic_number (short)
+- if magic number == -1 (not present):
+ - no-op
+- else
+ - UTF-8 string (class name)
+- size in bytes (short)
+- contents (header-specific)
+
+
+UTF-8 strings:
+- All strings start with a short that is the length of the string (DataOutputStream.writeUTF(String))
+
+
+Notes:
+
+- In most cases, we don't need to send the dest address, because the sender knows whether the message
+ was received on the unicast or multicast socket, and can thus set the dest address in an incoming
+ message to its own local address, or multicast address
+
+- This is currently as used by UDP. Once we move to Transport (e.g. including TCP), this needs to be
+ revisited. Currently (2.2.8), TCP uses externalization, *not* Streamable.
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/design/MERGE4.txt libjgroups-java-2.12.2.Final/doc/design/MERGE4.txt
--- libjgroups-java-2.7.0.GA/doc/design/MERGE4.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/MERGE4.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,48 @@
+
+MERGE4
+------
+
+Author: Bela Ban
+JIRA: https://jira.jboss.org/jira/browse/JGRP-937
+
+Goal
+----
+
+To merge asymmetric partitions, e.g. A: {A,B,C}, B: {A,B}, C: {A,C}. The current merge algorithm wouldn't merge these
+partitions because B and C are not coordinators and therefore don't participate in the merge.
+
+The implementation involves creating a new protocol (MERGE4) and modifying GMS and CoordGmsImpl.
+
+MERGE4
+------
+- Periodically runs a discovery
+- The Discovery protocol is changed such that each participant additionally returns its view
+- If the consolidated discovery responses result in more than 1 view, send up a MERGE event with a
+ list of all (different) views
+
+GMS / CoordGmsImpl
+------------------
+- On MERGE(V1,V2,V3,...):
+ - Determine all coordinators, e.g. A for V1 and V2, D for V3
+ - Determine the membership for each coord, e.g. {A,B,C} for A and {D,E,F} for D
+ - Send a MERGE-REQ to A and D
+ - The MERGE-REQ for A includes {A,B,C}, the MERGE-REQ for D includes {D,E,F}
+ - A and D fetch digest information from {A,B,C} (A) and {D,E,F} (D) respectively
+ - This information is consolidated in A (merge leader) and installed in both partitions
+
+- Example:
+ - A: V3 {A,B,C}
+ - B: V1 {A,B}
+ - C: V2 {A,C}
+ - D: V7 {D,E,F}
+ - E: V6 {D,E}
+ - F: V5 {D,F}
+
+ - MERGE4 sends up a MERGE(V1,V2,V3,V5,V6,V7)
+ - CoordGmsImpl determines that the coords are A and D and the merge leader is A
+ - A sends a MERGE-REQ(A,B,C} to A and a MERGE-REQ(D,E,F} to D
+ - A fetches the digest and view for A,B,C and returns it to A
+ - D fetches the digest and view for D,E,F and returns it to A
+ - A consolidates the digests and views (into a MergeView) and tells A and D to install the new MergeView plus digests
+
+
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/design/MERGE.new.txt libjgroups-java-2.12.2.Final/doc/design/MERGE.new.txt
--- libjgroups-java-2.7.0.GA/doc/design/MERGE.new.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/MERGE.new.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,69 @@
+
+New merging algorithm
+=====================
+
+Author: Bela Ban
+JIRAs: https://jira.jboss.org/jira/browse/JGRP-948, https://jira.jboss.org/jira/browse/JGRP-940
+
+Goal
+----
+The digests on a merge should not include 'hearsay' information, e.g. if we have subpartitions {A,B,C} and {D,E,F},
+then B (for example) should only return its own digest, and not the digests of A and C.
+
+Design
+------
+On a merge, the merge leader sends a MERGE_REQ to all subpartition coordinators (in the example, this would be A and D).
+
+On reception of a MERGE_REQ, every coordinator multicasts a GET_DIGEST to its subpartition and waits N ms for all
+replies. Example: D wait for replies from itself, E and F. It returns the aggregated information for D, E and F after N
+milliseconds.
+
+A (the merge leader) waits for responses from itself and D. If it doesn't receive them within N ms, it cancels the merge.
+After reception of responses from itself and D, it makes sure it has digests for 6 nodes A, B, C, D, E and F. It not,
+it cancels the merge.
+
+Otherwise, A computes a MergeView and consolidates the digests, then unicasts the MERGE_VIEW to itself and D. Each
+coordinator then multicasts the new view in its subpartition (same as now).
+
+Consolidating the digests should be simple because we only have 1 entry for each member. However, in the following
+case we could have multiple overlapping entries:
+A: {A} B: {A,B}
+
+Here's B's view includes A, so B will return digests for A and B, and A will return the digest for itself (A). In this
+case, let's log a warning and make the digest for A be the maximum of all sequence numbers (seqnos). Example:
+
+A's digest:
+A: 7 20 (20)
+
+B's digest:
+A: 2 10 (10)
+B: 5 25 (25)
+
+The merged digest for A would then be A: 7 20 (20).
+
+This should actually not happen because:
+- B's digest is a result of contacting every member of its subpartition (A and B)
+- If A is reachable from B, and B gets a response, the response will actually contain the correct seqnos 7 20 (20)
+- However, if A's digest (for itself) contains 7 21 (21), because a message was sent in the meantime, then the
+ maximum would be 7 21 (21) which is correct
+
+
+Merging of local digests (NAKACK.mergeDigest())
+-----------------------------------------------
+- We have {A,B} and {C,D}
+- The digest is A:15, B:7, C:10, D:9
+- Before receiving the merge digest A and B multicast more messages, A's seqno is now #20 and B's #10
+- A receives the digest:
+ A:20, B:10, ...
+ + A:15, B:7, ...
+ = A:20, **B:10**
+ ================
+
+==> We currently do NOT overwrite our own digest entry, but overwrite all others. This is incorrect: we need to
+ not overwrite our own digest (as is done currently), but for all other members P, we need to:
+ - If P's seqno is higher than the one in the digest: don't overwrite
+ - Else: reset P's NakReceiverWindow and overwrite it with the new seqno
+
+==> If we didn't do this, in the example above, B's seqno would be #7 whereas we already received seqnos up to #10 from
+ P, so we'd receive seqnos #7-#10 from P twice !
+
diff -Nru libjgroups-java-2.7.0.GA/doc/design/MERGE_View_Separation.txt libjgroups-java-2.12.2.Final/doc/design/MERGE_View_Separation.txt
--- libjgroups-java-2.7.0.GA/doc/design/MERGE_View_Separation.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/MERGE_View_Separation.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,98 @@
+
+
+Separation of merges from view handling
+=======================================
+
+Author: Bela Ban
+JIRA: https://jira.jboss.org/jira/browse/JGRP-1009
+
+Goal:
+-----
+
+We don't want concurrent merges and view changes (join or leave processing). During a merge, join and leave requests
+should be discarded. Likewise, during a join/leave processing, merge requests should be discarded.
+
+We already do discard join or leave requests during a merge (ViewHandler is suspended), but not the other way round.
+
+JGRP-1009 leads to spurious merges: when a join or leave request is being processed and the view is being
+disseminated, if a merge is permitted to occur during this, the merge leader might detect different views
+(due to them arriving at different members at different times, maybe a few millisconds apart) and initiate a merge.
+
+This won't happen when the merge is discarded during view processing / installation.
+
+Design:
+-------
+
+There are 3 types of events we need to take into acccount:
+- The coord receiving a JOIN/JOIN_WITH_STATE/LEAVE/SUSPECT event (anything which leads to a new view being installed)
+- The coord receiving a MERGE event (e.g. from MERGE2 somewhere below in the stack)
+- The coord receiving a MERGE-REQ request (from a coord in a different partition)
+
+On reception of a JOIN/JOIN_WITH_STATE/LEAVE/SUSPECT event
+----------------------------------------------------------
+- If the ViewHandler is suspended --> discard the event
+- Else, add the event
+- When starting to process the event(s) in the queue:
+ - Suspend the ViewHandler
+ - Start the Resumer task (which resumes the ViewHandler after N seconds)
+ - Resume the ViewHandler when done processing
+
+
+On reception of a MERGE event
+-----------------------------
+- If the ViewHandler is suspended --> discard the event
+- Else:
+ - If there are JOIN/LEAVE/etc events in the queue: discard the event and start the processing of the queued events
+ - Else:
+ - Process the MERGE event
+ - Suspend the ViewHandler
+ - Start the Resumer task (which resumes the ViewHandler after N seconds)
+ - Resume the ViewHandler when done processing
+
+
+On reception of a MERGE-REQ
+---------------------------
+- If the ViewHandler is suspended --> reject the MERGE-REQ (send MERGE-RSP with merge_rejected=true)
+- Else:
+ - Suspend the ViewHandler
+ - Start the Resumer task
+ - When the merge is done --> resume the ViewHandler
+ - On Resumer timeout: resume the ViewHandler
+ (this could happen for instance when a remote coord starts a merge, then crashes before merge completion)
+
+
+Resuming the view handler:
+--------------------------
+
+The following 4 cases can resume the view handler
+
+#1 JOIN/LEAVE
+-------------
+- When the view has been installed by the coord, the view handler is resumed
+- The view handler needs to be resumed also if the view installation fails, e.g. due to a failed flush
+
+#2 MERGE
+--------
+- On competion of the merge (successful or failed), the view handler is resumed
+
+#3 MERGE-REQ
+------------
+- Resume the view handler when getting a MergeView
+- Special case: if the merge leader crashes before merge completion:
+ - On a MERGE-REQ, record the merge leader's address (when suspending the view handler)
+ - When the merge completes, null the merge leaders address again
+ - When we get a view excluding the merge leader, and the leader's address is non-null, resume the
+ view handler and null the merge leader's address
+
+#4 The Resumer kicks in
+-----------------------
+- The Resumer is started whenever the view handler is suspended
+- It resumes the view handler when run
+- When the view handler is resumed regularly, the Resumer is stopped
+
+
+Issues:
+-------
+
+- What if the client sends a JOIN_WITH_STATE, the coord processes the JOIN, but suspends the queue after it and before
+ processing the GET_STATE ?
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/design/Multiplexer.txt libjgroups-java-2.12.2.Final/doc/design/Multiplexer.txt
--- libjgroups-java-2.7.0.GA/doc/design/Multiplexer.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/Multiplexer.txt 2011-10-18 11:22:35.000000000 +0000
@@ -4,7 +4,6 @@
===========================
Author: Bela Ban
-Version: $Id: Multiplexer.txt,v 1.18 2006/07/11 12:36:37 belaban Exp $
JIRA: http://jira.jboss.com/jira/browse/JGRP-119, http://jira.jboss.com/jira/browse/JGRP-112
Overview
diff -Nru libjgroups-java-2.7.0.GA/doc/design/NAKACK.txt libjgroups-java-2.12.2.Final/doc/design/NAKACK.txt
--- libjgroups-java-2.7.0.GA/doc/design/NAKACK.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/NAKACK.txt 2011-10-18 11:22:35.000000000 +0000
@@ -6,7 +6,6 @@
Author: Bela Ban
Date: April 3, 2007
JIRA: http://jira.jboss.com/jira/browse/JGRP-281
-Version: $Id: NAKACK.txt,v 1.9 2007/04/19 21:01:17 belaban Exp $
diff -Nru libjgroups-java-2.7.0.GA/doc/design/NullDestAddresses.txt libjgroups-java-2.12.2.Final/doc/design/NullDestAddresses.txt
--- libjgroups-java-2.7.0.GA/doc/design/NullDestAddresses.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/NullDestAddresses.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,20 @@
+
+Nulling of destination addresses for optimized marshalling
+==========================================================
+
+Author: Bela Ban
+Date: Aug 26 2005
+
+When we marshall a message (org.jgroups.Message), we can transmit a null value for the destination, because
+the receiver can determine the destination:
+- for UDP: if received on the multicast receive socket, the destination is the multicast address (same as null)
+ if received on the unicast receive socket, the destination is the local_addr (ourself)
+- for TCP: we use the MULTICAST byet sent with the message when unmarshalling the message:
+ - if true, we leave the deatination null (= multicast destination)
+ - if not set, we set the destination to the address passed to use from the ConnectionTable
+
+This requires that when marshalling a message, we send a multicast byte with each Message (or once for bundled msgs)
+based on the destination address !
+
+Note that we *cannot* modify the destination address in the message itself, otherwise retransmissions might fail !
+
diff -Nru libjgroups-java-2.7.0.GA/doc/design/NullingSrcAddresses.txt libjgroups-java-2.12.2.Final/doc/design/NullingSrcAddresses.txt
--- libjgroups-java-2.7.0.GA/doc/design/NullingSrcAddresses.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/NullingSrcAddresses.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,19 @@
+
+Loopback adaptor issues on Windows
+----------------------------------
+
+JIRA: http://jira.jboss.com/jira/browse/JGRP-79
+
+On Windows, when a loopback adaptor is created, we can associate multiple (virtual) IP
+addresses with it, e.g. 10.0.0.1 and 10.0.0.2.
+
+However, when we have a member M1 bound to 10.0.0.1, and another member M2 bound to 10.0.0.2, and
+bind_to_all_interfaces is set to true, then it was observed that - regardless of the bind address -
+the sender's address in a DatagramPacket received was always 10.0.0.1 (the first address assigned) !
+
+Therefore, members would never find each other.
+
+The reason this shows up now (in 2.2.8) is that as an optimization, we *don't* send the src address
+in the Message anymore, so we can save a few bytes, but we null the src address, and set it to the sender's
+address when we *receive* the packet.
+This can be disabled by setting null_src_addresses to false (default is true)
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/design/PartialStateTransfer.txt libjgroups-java-2.12.2.Final/doc/design/PartialStateTransfer.txt
--- libjgroups-java-2.7.0.GA/doc/design/PartialStateTransfer.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/PartialStateTransfer.txt 2011-10-18 11:22:35.000000000 +0000
@@ -1,5 +1,4 @@
-// Version: $Id: PartialStateTransfer.txt,v 1.1 2006/01/27 14:46:12 belaban Exp $
// Author: Bela Ban
Partial state transfer
diff -Nru libjgroups-java-2.7.0.GA/doc/design/ProbabilisticBroadcast.txt libjgroups-java-2.12.2.Final/doc/design/ProbabilisticBroadcast.txt
--- libjgroups-java-2.7.0.GA/doc/design/ProbabilisticBroadcast.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/ProbabilisticBroadcast.txt 2011-10-18 11:22:35.000000000 +0000
@@ -1,8 +1,8 @@
- Probabilistic Broadcast for JavaGroups
- ======================================
+ Probabilistic Broadcast for JGroups
+ ===================================
diff -Nru libjgroups-java-2.7.0.GA/doc/design/Reincarnation.txt libjgroups-java-2.12.2.Final/doc/design/Reincarnation.txt
--- libjgroups-java-2.7.0.GA/doc/design/Reincarnation.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/Reincarnation.txt 2011-10-18 11:22:35.000000000 +0000
@@ -4,7 +4,6 @@
===========================
Author: Bela Ban
-Version: $Id: Reincarnation.txt,v 1.1 2006/01/27 14:46:12 belaban Exp $
JIRA: http://jira.jboss.com/jira/browse/JGRP-130
The identity of a JGroups member is always the IP address and a port. The port is usually chosen by the OS, unless
diff -Nru libjgroups-java-2.7.0.GA/doc/design/RELAY.fig libjgroups-java-2.12.2.Final/doc/design/RELAY.fig
--- libjgroups-java-2.7.0.GA/doc/design/RELAY.fig 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/RELAY.fig 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,74 @@
+#FIG 3.2 Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter
+100.00
+Single
+-2
+1200 2
+6 3375 4800 6375 9075
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3375 4800 6375 4800 6375 9075 3375 9075 3375 4800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3375 5400 6375 5400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3375 6000 6375 6000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3375 6675 6375 6675
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3375 7350 6375 7350
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3375 8025 6375 8025
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3375 8550 6375 8550
+4 0 0 50 -1 16 16 0.0000 4 195 885 4425 5175 RELAY\001
+-6
+6 1575 825 4575 4200
+6 3750 1950 4350 2550
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 4050 2250 270 270 4050 2250 4200 2475
+4 0 0 50 -1 16 16 0.0000 4 195 180 3975 2400 A\001
+-6
+6 2100 1500 2700 2100
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 2400 1800 270 270 2400 1800 2550 2025
+4 0 0 50 -1 16 16 0.0000 4 195 195 2325 1875 C\001
+-6
+6 2475 2850 3075 3450
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 2775 3150 270 270 2775 3150 2925 3375
+4 0 0 50 -1 16 16 0.0000 4 195 180 2700 3225 B\001
+-6
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 3069 2364 1479 1479 3069 2364 4344 3114
+4 0 0 50 -1 16 16 0.0000 4 240 450 2850 4125 udp\001
+-6
+6 10125 2700 10725 3300
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 10425 3000 270 270 10425 3000 10575 3225
+4 0 0 50 -1 16 16 0.0000 4 195 165 10350 3075 F\001
+-6
+6 10200 1200 10800 1800
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 10500 1500 270 270 10500 1500 10650 1725
+4 0 0 50 -1 16 16 0.0000 4 195 180 10425 1650 E\001
+-6
+6 8700 1950 9300 2550
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 9000 2250 270 270 9000 2250 9150 2475
+4 0 0 50 -1 16 16 0.0000 4 195 195 8925 2325 D\001
+-6
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 9969 2289 1479 1479 9969 2289 11244 3039
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 2175 9450 8400 9450
+2 1 0 2 0 7 50 -1 -1 0.000 0 0 7 1 0 2
+ 1 1 4.00 60.00 120.00
+ 5475 9450 5475 4050
+2 1 0 2 0 7 50 -1 -1 0.000 0 0 7 1 0 2
+ 1 1 4.00 60.00 120.00
+ 5475 5175 7425 5175
+2 4 0 3 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 9525 2925 3600 2925 3600 1950 9525 1950 9525 2925
+4 0 0 50 -1 18 18 0.0000 4 225 2445 1800 600 Data Center NYC\001
+4 0 0 50 -1 18 18 0.0000 4 225 2415 8775 525 Data Center SFO\001
+4 0 0 50 -1 16 16 0.0000 4 195 990 7350 9300 Network\001
+4 0 0 50 -1 16 16 0.0000 4 255 3465 6525 5025 Relaying to other data center\001
+4 0 0 50 -1 16 16 0.0000 4 240 1320 4875 3900 Application\001
+4 0 0 50 -1 16 16 0.0000 4 210 360 6300 2325 tcp\001
+4 0 0 50 -1 16 16 0.0000 4 240 450 9750 4050 udp\001
+4 0 0 50 -1 2 18 0.0000 4 195 225 3975 2850 X\001
+4 0 0 50 -1 2 18 0.0000 4 195 225 8925 2850 Y\001
Binary files /tmp/AYciA0_poF/libjgroups-java-2.7.0.GA/doc/design/RELAY.png and /tmp/XQ0f23GK1l/libjgroups-java-2.12.2.Final/doc/design/RELAY.png differ
diff -Nru libjgroups-java-2.7.0.GA/doc/design/RELAY.txt libjgroups-java-2.12.2.Final/doc/design/RELAY.txt
--- libjgroups-java-2.7.0.GA/doc/design/RELAY.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/RELAY.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,188 @@
+
+RELAY - replication between data centers
+========================================
+
+Author: Bela Ban
+
+This is an enhanced version of DataCenterReplication.txt with the ability to send unicast messages and to provide views
+to the application, which list members of all local clusters.
+
+We have data centers, each with a local cluster, in New York (NYC) and San Francisco (SFO). The idea is to relay
+traffic from NYC to SFO, and vice versa.
+
+In case of a site failure of NYC, the state is available in SFO, and all clients can be switched over to SFO and
+continue working with (almost) up-to-date data. The failing over of clients to SFO is outside the scope of this
+proposal, and could be done for example by changing DNS entries, load balancers etc.
+
+The data centers in NYC and SFO are *completely autonomous local clusters*. There are no stability, flow control or
+retransmission messages exchanged between NYC and SFO. This is critical because we don't want the SFO cluster to block
+for example on waiting for credits from a node in the NYC cluster !
+
+For the example, we assume that each site uses a UDP based stack, and relaying between the sites uses a
+TCP based stack, see figure RELAY.png.
+
+There is a local cluster, based on UDP, at each site and one global cluster, based on TCP, which connects the
+two sites. Each coordinator of the local cluster is also a member of the global cluster, e.g. member A in NYC
+(assuming it is the coordinator) is also member X of the TCP cluster. This is called a *relay* member. A relay
+member is always member of the local and global cluster, and therefore has 2 channels it joins.
+
+A relay member has a UDP stack which additionally contains a protocol RELAY at the top (shown in the bottom part
+of the figure). RELAY has a JChannel which connects to the TCP group, but *only* when it is (or becomes) coordinator
+of the local cluster. The configuration of the TCP channel is done via a property in RELAY.
+
+A multicast message received by RELAY traveling up the stack is wrapped and sent via the TCP channel to the
+other site. When received there, the corresponding RELAY protocol unwraps the original message and changes the sender
+of the message to a ProxyUUID, which wraps the original sender and the local sender.
+
+A ProxyUUID extends UUID and behaves like a normal UUID, but it also contains the original sender.
+
+A unicast message received by RELAY traveling down the stack is forwarded to the current relay if the destination is
+a ProxyUUID. The relay will then wrap the message and forward it to the other site via TCP.
+
+When boradcasting a relayed message on the local cluster, RELAY adds a header. When it receives the multicast message it
+forwarded itself, and a header is present, it does *not* relay it back to the other site but simply drops it.
+Otherwise, we would have a cycle.
+
+When a coordinator crashes or leaves, the next-in-line becomes coordinator and activates the RELAY protocol,
+connecting to the TCP channel and starting to relay messages.
+
+However, if we receive messages from the local cluster while the coordinator has crashed and the new one hasn't taken
+over yet, we'd lose messages. Therefore, we need additional functionality in RELAY which buffers the last N messages
+(or M bytes, or for T seconds) and numbers all messages sent. This is done by the second-in-line.
+
+When there is a coordinator failover, the new coordinator communicates briefly with the other site to determine
+which was the highest message relayed by it. It then forwards buffered messages with lower numbers and removes the
+remaining messages in the buffer. During this replay, message relaying is suspended.
+
+Therefore, a relay has to handle 3 types of messages from the global (TCP) cluster:
+ (1) Regular multicast messages
+ (2) A message asking for the highest sequence number received from another relay, and the response to this
+ (3) A message stating that the other side will go down gracefully (no need to replay buffered messages)
+
+
+Example walkthrough
+-------------------
+
+Multicasting a message:
+
+- C (in the NYC cluster, with coordinator A) multicasts a message
+- A, B and C receive the multicast
+- A is the relay. The byte buffer is extracted and a new message M is created. M's source is C, the dest is null
+ (= send to all). Note that the original headers are *not* sent with M. If this is needed, we need to revisit.
+- A then wraps M into a message sent from X to Y
+- X receives M, drops it (because it is the sender, determined by the header).
+- Y receives M, and unwraps it.
+- Y replaces the sender (C) with a ProxyUUID(D,C) (D is the sender and C the origial sender), adds a RelayHeader and
+ sends it down its local cluster
+- D, E and F receive M and deliver it
+- D does not relay M because M has a header
+
+Sending a unicast reply:
+
+- When F receives the multicast message M, it sends a unicast reply message R
+- R.dest=ProxyUUID(D,C) and R.src=F
+- RELAY.down() sees that R.dest is a ProxyUUID and therefore forwards R to the current relay (which is D)
+- RELAY.up() in D sees that the destination is a ProxyUUID and relays the message, via Y to X
+- D sets the destination of R to C, wraps the message and sends it to X (via the TCP cluster)
+- A receives R (from X) and replaces R.src with a ProxyUUID(C,F)
+- A puts R on the local channel where it is sent to C
+
+
+Implementation
+--------------
+
+Becoming coordinator:
+- Join TCP channel
+- Register receiver
+
+Ceasing to be coordinator:
+- Leave TCP channel
+
+
+RELAY.up(msg):
+- If RelayHeader present: // coord
+ - If FORWARD && coordinator: forward(msg.buf); return
+ - If DISSEMINATE: pass up and return
+ - If VIEW: // see below
+ - Return
+- Else:
+ - If multicast message && coordinator:
+ - Copy msg to M (don't copy headers)
+ - Serialize M into a buffer buf
+ - forward(buf)
+ - Pass up // unicast or multicast messages
+
+
+RELAY.down(msg):
+- If msg.dest is not a ProxyUUID: pass down, return
+- forwardToCoord(msg)
+- Return // don't pass down !
+
+
+Receive message M from TCP channel:
+- Switch RelayHeader:
+ - Case FORWARD:
+ - If sender = self: discard
+ - Else: deserialize M.buf into message M2 and putOnLocalCluster(M2)
+ - Case VIEW: // see below
+
+
+forward(buf): // buf is the serialized message to be forwarded
+- Create a message M with M.buf=buf, M.dst=null
+- Add RelayHeader.FORWARD to M
+- Put M onto the TCP channel
+
+
+forwardToCoord(msg):
+- Copy msg to M (don't copy headers)
+- Set M.dst=msg.dst.original, M.src=local_addr
+- Serialize M into a buffer buf
+- Create message M2 (M2.buf=buf)
+- Add RelayHeader.FORWARD to M2
+- Send M2 to the current relay (coordinator)
+
+putOnLocalCluster(M):
+- Set M.src=ProxyUUID(local_addr,M.src)
+- Add a RelayHeader.DISSEMINATE to M
+- Put M on the local channel
+
+
+View changes
+------------
+
+Local view changed:
+- Set local view
+- If coordinator:
+ - Broadcast remote and global view to local cluster
+ - Send remote view to remote cluster
+- Every node (on reception):
+ - Update(RV, GV)
+
+Remote view (RV) changed:
+- Broadcast remote and global view to local cluster
+- Every node (on reception):
+ - Update(RV, GV)
+
+
+Update(RV,GV):
+- Update remote view from RV if needed
+- Install GV:
+ - If GV != current global view: set current view = GV and viewAccepted(GV)
+
+
+Bridge view changed:
+- If coordinator: send local view to remote
+- If remote coordinator ('creator of remote view') crashed:
+ - Generate empty remote view V, generate global view and send RV and GV to local cluster
+
+
+
+
+
+Issues:
+- Do we copy the headers of a message M when M is relayed ? If not, an app won't be able to add their own headers
+- Should we pass logical name information between the clusters ? Or should this be part of ProxyAddress ?
+
+Todo:
+#3 Handling temp coordinator outage - how do we prevent message loss ?
+#4 State transfer - replication across clusters, to bootstrap initial coords in a local cluster
diff -Nru libjgroups-java-2.7.0.GA/doc/design/ReliableViewInstallation.txt libjgroups-java-2.12.2.Final/doc/design/ReliableViewInstallation.txt
--- libjgroups-java-2.7.0.GA/doc/design/ReliableViewInstallation.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/ReliableViewInstallation.txt 2011-10-18 11:22:35.000000000 +0000
@@ -3,7 +3,6 @@
==========================
Author: Bela Ban
-Version: $Id: ReliableViewInstallation.txt,v 1.1 2006/01/27 14:46:12 belaban Exp $
The default stack sees view as just messages; a view multicast is retransmitted until the sender is excluded because
it left or crashed. However, this behavior can lead to problems described below. The problems occur when a view
diff -Nru libjgroups-java-2.7.0.GA/doc/design/ReplCache.txt libjgroups-java-2.12.2.Final/doc/design/ReplCache.txt
--- libjgroups-java-2.7.0.GA/doc/design/ReplCache.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/ReplCache.txt 2011-10-18 11:22:35.000000000 +0000
@@ -4,7 +4,6 @@
================
Author: Bela Ban
-Id: $Id: ReplCache.txt,v 1.6 2008/12/23 16:11:02 belaban Exp $
Idea
@@ -15,86 +14,96 @@
ReplCache is a hashmap which distributes its keys and values across the cluster, based on consistent hashing.
+The difference to PartitionedHashMap is that ReplCache allows a user to define *per data item* whether it should be
+replicated (for high availability) or not and if yes, how many times.
+
There are 3 methods: put(), get() and remove().
-When adding a new key/value pair, put() takes the 'replication factor' as argument, alongside the key and value and
+When adding a new key/value pair, put() takes the 'replication count' as argument, along with the key, value and
a timeout.
-A replication factor of 0 means no replication.
+A replication count of 1 means the data is stored only on 1 node in the cluster, and there is no replication.
+The data will be placed on a node in the cluster that corresponds to the consistent hashcode of the data's key.
-A replication factor of -1 means that the element is replicated to all cluster nodes.
+A replication count of -1 means that the data item is replicated to all cluster nodes.
-A replication factor of K means replicate the element K times, e.g. PUT(KEY, VAL, 2, timeout) means that an element
+A replication count of K means the element is stored K times, e.g. PUT(KEY, VAL, 2, timeout) means that an element
will be created on 2 nodes. When the view changes, the cluster makes sure that the above KEY, VAL is always present
-in 2 nodes. Note that K has to be less than or equal to N (= number of nodes). When K > N, then ReplCache treats
+on 2 nodes. Note that K has to be less than or equal to N (= number of nodes). When K > N, then ReplCache treats
K as -1 (replicate to all nodes).
+K == 0 is invalid and will be ignored; the data will not be stored in the cluster.
-TBD: a replication factor which defines a percentage, e.g. 0.3 means replicate to 30% of all nodes.
-
+TBD: a replication count which defines a percentage, e.g. 0.3 means replicate to 30% of all nodes.
-The advantage of defining replication factors per element is that we can define what reliability we want for
+The advantage of defining replication counts per element is that we can define what reliability we want for
individual data items. For example, an element that can easily be retrieved from disk or database probably does
-fine with a factor of 0 (= no replication). Here, we use the cache just as a speedup to prevent DB access.
-An important item that is costly to recreate, or cannot be recreated at all, should probably have a factor of -1.
+fine with a count of 1 (= no replication). Here, we use the cache just as a speedup to prevent DB access.
+An important item that is costly to recreate, or cannot be recreated at all, should probably have a count of -1.
-The point of being able to define replication factors per data item is that we can save memory this way. If we
-compare this to RAID 0+1, then - because we're replicating every single data item - we can effectively only use
-half of the memory (disk space) allocated to the RAID system. With per data replication factors, we can increase the
-net memory that can be used (unless of course all elements are added with a factor of -1 !).
+The point of being able to define replication counts per data item is that we can save memory. If we
+compare this to RAID 1, then - because we're replicating every single data item - we can effectively only use
+half of the memory (disk space) allocated to the RAID system. With per data replication counts, we can increase the
+net memory that can be used (unless of course all elements are added with a count of -1 !).
Put() always results in a multicast across the cluster. Each node determines by itself whether it will add the KEY|VAL
or not. This is done by computing a set of consistent hashes from KEY, mapping them to a set of servers and determining
whether the node's address is in that set. If so, a node will add the KEY,VAL to its local cache, else not.
-Get() first checks the level 1 cache (L1 cache, not mentioned so far). If the data is found, it will be returned,
-else we multicast a GET request (bounded with a timeout). Every node returns its key/value from the local cache. Before
-returning from get(), we add the result to our L1 cache. (The L1 cache will independently evict timed out items, or
-evict items when it needs more space. Items with a timeout of -1 are never placed into the L1 cache).
+Get() first checks the level 1 cache (L1 cache, not mentioned so far), and the regular cache (L2 cache).
+If the data is found, it will be returned, else we multicast a GET request (bounded with a timeout).
+Every node returns its key/value from the local cache. Before returning from get(), we add the result to our L1 cache.
+(The L1 cache will independently evict timed-out items, or evict items when it needs more space.
+Items with a timeout of -1 are never placed into the L1 cache).
Remove() simply multicasts the KEY across the cluster. Every node removes KEY from its local cache, and the L1 cache
if enabled.
-Design points
--------------
-There are a few design considerations:
+Design decisions
+----------------
+There are a few considerations and assumptions that influenced the design:
-- Keys and values are small. We do *not* provide technology which breaks large data items into multiple chunks
+- Keys and values must be small. We do *not* provide technology which breaks large data items into multiple chunks
and distributes or replicates these chunks individually
-- IP multicasting is the transport. If we used TCP, communication would get costly (N-1 issue)
+- IP multicasting should be used in the transport. If we used TCP, communication would get costly (N-1 issue)
+
+- K cannot be reduced for the same key, e.g. if K == 3 and then K == 2 for the same key, we'll have some leftover
+ data with K == 3. If this is necessary, remove the key first before calling put() again.
API
---
put(KEY, VAL, K, TIMEOUT):
+--------------------------
Places KEY,VAL into the hashmaps of selected cluster nodes. Existing data will be overwritten. KEY and VAL have to
be serializable.
-K can be -1 (replicate everywhere), 0 (create only on 1 node) or > 0 <= N (replicate to K nodes).
-
-TIMEOUT (ms): -1 (no caching), 0 (cache until removed) or > 0 (cache for TIMEOUT ms)
-
-On reception of put():
-
-- The selected target nodes add the KEY,VAL to their local cache if the conistent hash matches their local_addr
-- *Everyone* removes KEY from their L1 cache. (Optimization: only the non-selected nodes do this, the selected nodes
- also add KEY,VAL to their L1 caches)
-
+K is the replication count and can be:
+ -1: replicate everywhere
+ 1: create only on 1 node
+ > 1 <= N: store on K nodes
+
+TIMEOUT (ms):
+ -1: no caching
+ 0: cache until removed
+ > 0: cache for TIMEOUT milliseconds
+
The put() method creates a message with KEY, VAL, K and TIMEOUT and multicasts it. Each node which receives the message
does the following:
- If K == -1: add it to the local cache and return
-- If K == 0: compute the server based on the consistent hashcode for KEY and see whether local_addr == server. If
+- If K == 1: compute the server based on the consistent hashcode for KEY and see whether local_addr == server. If
so, add the KEY, VAL to the local cache and return. Else, drop the message.
- If K > 0: compute K consistent hashes from KEY. If local_addr is part of the set of server addresses, add KEY,VAL
to the local cache. Else, drop the message.
VAL get(KEY):
+-------------
- Look up KEY in the L1 cache. If found,and not expired, return it
- Multicast a GET request.
@@ -102,27 +111,71 @@
- Else return null
void remove(KEY):
+-----------------
- Multicast a REMOVE(KEY) message
- On reception, every node removes KEY from its local cache
-View changes:
-
+View change:
+------------
-For a new or left node P, every node N:
-- For each local KEY:
- - If the K factor is -1: replicate KEY,VAL to P
- - If the K factor is 0: compute consistent hash and pick server S
- - If S == P, the server which hosted KEY before P joined moves KEY,VAL to P (PUT message), and
- removes KEY from its local hashmap
- - Else: do nothing (no rebalancing needed)
- - If the factor is > 0:
- - Compute K consistent hashes and determine the K servers which are supposed to be hosting KEY
- - For each server S:
- - Do the same as above (factor == 0)
+- The handling of view changes needs to be done in a separate thread. Suggestion: do this in a timer task, and
+ start the task 100ms after the view change callback. This is to ensure that every cluster node installed the view.
+- Old view is V, new view is V-NEW
+- For a new node P
+ - For each key KEY
+ - If K == -1: copy KEY to P (only the coord does this)
+ - If K == 1: compute new hash (based on V-NEW), if not same as local node -> move KEY to P
+ - If K > 1: re-balance
+
+- For each left node Q
+ - For each key KEY:
+ - If K == -1: no-op
+ - If K == 1: compute new hash (based on V-NEW), if not same as local node -> move KEY to P
+ - If K > 1: re-balance
+
+Re-balance (K > 1):
+-------------------
+
+- Old view is V, new view is V-NEW
+
+- move() installs a KEY regardless of whether it would be accepted in the current view
+
+- For each key KEY:
+ - If K == -1:
+ - For each newly joined node P:
+ - The coord sends KEY to P (move())
+
+ - If K == 1:
+ - Compute 1 hashcode (based on V-NEW) and determine the new node N
+ - If N != local node --> move KEY to N
+
+ - If K > 1:
+ - Compute hashes for V (NODES)
+ - Compute hashes for V-NEW (NEW-NODES)
+ - If NODES == NEW-NODES --> return
+ - Else
+ - Multicast KEY (make sure everyone has new view installed, to compute correct acceptance)
+ - If local node is not in NEW-NODES --> remove KEY from local node
+
+
+ - Compute nodes for V (NODES)
+ - Compute nodes for V-NEW (NEW-NODES)
+ - If NODES == NEW-NODES --> return
+ - Else
+ - Multicast KEY (every node will check the hash against itself and store if needed)
+ - If the local node is not in NEW-NODES --> remove KEY
+
+
+Stopping the cache:
+-------------------
+- For each key KEY:
+ - If K is -1: no-op (every node already has KEY)
+ - If K == 1: compute new hash (based on the view excluding the current node) and copy KEY to the new node
+ - If K > 1: no-op (somebody else has KEY, view change will copy to more nodes if needed)
diff -Nru libjgroups-java-2.7.0.GA/doc/design/SCOPE.txt libjgroups-java-2.12.2.Final/doc/design/SCOPE.txt
--- libjgroups-java-2.7.0.GA/doc/design/SCOPE.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/SCOPE.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,41 @@
+
+
+Implementation of the SCOPE protocol
+====================================
+
+Author: Bela Ban
+
+Scopes allow for concurrent delivery of messages sent by the same sender, without having to resort to OOB.
+
+The implementation is done by a protocol called SCOPE, which has to be somewhere above NAKACK and UNICAST.
+
+Scopes do apply to both multicast and unicast messages.
+
+A message is tagged as scoped by calling Message.setScope(short). This will add a SCOPE.ScopeHeader to the message. A
+scope is always a short, so we can have ca 32'000 scopes.
+
+The scope can be set *per message*. It should be more or less unique, but doesn't need to be.
+
+All messages with the same scope are delivered in the order in which they were received by the SCOPE protocol. Because
+SCOPE resides above NAKACK and UNICAST, all multicast and unicast messages are guaranteed to be received by SCOPE
+(a) in order and (b) once and only once.
+
+Messages without a scope header are passed up the stack.
+
+When a message is received by SCOPE, it is examined for a scope header. If none is present, the message is passed up.
+
+When a scope header is present, we grab the scope and fetch the associated queue (MessageQueue). If no queue
+exists yet, one will be created.
+
+The message is then added to the end of the queue.
+
+If no thread is currently processing the queue, one will be created (from a thread pool) and assigned to processing
+the queue. The thread (QueueThread) will then continually remove messages from the head of the queue and pass them
+up the stack.
+
+When no messages are available, the thread is terminated and is placed back to the thread pool.
+
+The thread pool is configurable (min and max threads, plus idle time).
+
+Unused scopes are periodically removed by the ExiryTask, which is run every expiration_interval milliseconds and
+removes scopes which have been idle for more than expiration_time milliseconds.
diff -Nru libjgroups-java-2.7.0.GA/doc/design/SEQUENCER.txt libjgroups-java-2.12.2.Final/doc/design/SEQUENCER.txt
--- libjgroups-java-2.7.0.GA/doc/design/SEQUENCER.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/SEQUENCER.txt 2011-10-18 11:22:35.000000000 +0000
@@ -5,7 +5,6 @@
Author: Bela Ban
Date: Dec 29 2005
-Version: $Id: SEQUENCER.txt,v 1.2 2008/10/06 16:05:53 belaban Exp $
Motivation
@@ -22,6 +21,15 @@
its own message and multicasts it to the group. The SEQUENCER protocol (somewhere above NAKACK) unwraps the message
so that the original sender is seen.
+It is the coordinator who decides on the ordering of messages from different senders. When receiving FORWARD
+messages from A, B and C, the coordinator establishes an ordered sequence, ordered by the seqno assigned by the
+coordinator when sending the message. This sequence is delivered in order at all receivers, therefore establishing
+total ordering.
+
+Note that there can be cases where a sender P sends message M1 and M2, but M2 is received first by the coordinator,
+then M1. In this case, M2 would be *before* M1 in the global sequence established by the coordinator. If this is not
+desired, then use a group RPC which gets acked by every node before a new message is sent.
+
Example: group is {A,B,C}. B wants to multicast a message M to the group. It does so by sending M to A. A then
adds a header which records the original sender (B) and replaces M's sender address with its own (A).
When a member receives M, everybody thinks the message is from A, and NAKACK will possibly retransmit from A
diff -Nru libjgroups-java-2.7.0.GA/doc/design/SimpleFlowControl.txt libjgroups-java-2.12.2.Final/doc/design/SimpleFlowControl.txt
--- libjgroups-java-2.7.0.GA/doc/design/SimpleFlowControl.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/SimpleFlowControl.txt 2011-10-18 11:22:35.000000000 +0000
@@ -1,5 +1,4 @@
-// Version: $Id: SimpleFlowControl.txt,v 1.2 2007/01/05 15:51:58 belaban Exp $
// Author: Bela Ban
diff -Nru libjgroups-java-2.7.0.GA/doc/design/STABLE.txt libjgroups-java-2.12.2.Final/doc/design/STABLE.txt
--- libjgroups-java-2.7.0.GA/doc/design/STABLE.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/STABLE.txt 2011-10-18 11:22:35.000000000 +0000
@@ -4,7 +4,6 @@
Author: Bela Ban
Date: May 29 2007
-Version: $Id: STABLE.txt,v 1.2 2007/05/31 09:56:58 belaban Exp $
Goal: to purge messages delivered by all members
diff -Nru libjgroups-java-2.7.0.GA/doc/design/StreamingStateTransfer.txt libjgroups-java-2.12.2.Final/doc/design/StreamingStateTransfer.txt
--- libjgroups-java-2.7.0.GA/doc/design/StreamingStateTransfer.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/StreamingStateTransfer.txt 2011-10-18 11:22:35.000000000 +0000
@@ -4,7 +4,6 @@
Author: Vladimir Blagojevic
Date: July 2006
-Version: $Id: StreamingStateTransfer.txt,v 1.4 2006/07/31 16:12:20 vlada Exp $
Overview
diff -Nru libjgroups-java-2.7.0.GA/doc/design/TestNG.txt libjgroups-java-2.12.2.Final/doc/design/TestNG.txt
--- libjgroups-java-2.7.0.GA/doc/design/TestNG.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/TestNG.txt 2011-10-18 11:22:35.000000000 +0000
@@ -4,7 +4,6 @@
==============================
Author Bela Ban
-Version: $Id: TestNG.txt,v 1.17 2008/04/18 09:13:12 belaban Exp $
Goals
-----
diff -Nru libjgroups-java-2.7.0.GA/doc/design/TransportNextGen libjgroups-java-2.12.2.Final/doc/design/TransportNextGen
--- libjgroups-java-2.7.0.GA/doc/design/TransportNextGen 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/TransportNextGen 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,29 @@
+
+
+Transport Next Generation
+-------------------------
+
+Author: Bela Ban
+
+The next version of the transport (org.jgroups.protocols.TP) should be NIO based: TP has an NIO selector, and subclasses
+such as TCP or UDP only register NIO channels with TP. For example, UDP would create 2 NIO channels, a unicast and a
+multicast channel and register them with TP. TCP would do an accept() in a loop and, whenever a new peer connects,
+register the client's NIO socket channel with TP's selector.
+
+TP would therefore be a multiplexer which handles a number of connections, be they TCP or UDP connections. Therefore,
+the connection table functionality of TCP would be largely removed, because this is now handled by TP itself.
+
+This requires JDK 7, because NetworkChannel.open() does not yet exist in prior JDKs. To be more precise, it does exist,
+but only for datagram sockets (DatagramChannel.open()), not for multicast sockets (no MulticastChannel.open()).
+
+Transport NetGen should be combined with the copyless stack (https://jira.jboss.org/jira/browse/JGRP-809). On the
+receive side, this is done by passing the selection key to a thread from the thread pool. If the key has an attachment,
+it is the ByteBuffer previously created by a (possibly different) thread to receive the message. The receiver thread
+will then simply call read() (or receive()) on the input NIO channel and - when all bytes have been received (defined
+by the initial length field of a message) - unmarshall the buffer and pass the resulting message up the stack.
+When there is no attachment, the receiver thread creates one (according to the length field which prefixes each message)
+and reads the bytes available from the NIO channel into it. If the number of bytes read is equals to the expected length,
+the thread proceeds to unmarshalling and passing the message up. Otherwise, it attaches the ByteBuffer to the selection
+key and returns. Later, a (potentially) different thread will complete reading the full message and then finish the job.
+
+
diff -Nru libjgroups-java-2.7.0.GA/doc/design/UNICAST2.txt libjgroups-java-2.12.2.Final/doc/design/UNICAST2.txt
--- libjgroups-java-2.7.0.GA/doc/design/UNICAST2.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/UNICAST2.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,181 @@
+
+UNICAST2 design
+===============
+(see UNICAST.txt for the old design)
+
+Author: Bela Ban
+
+Motivation
+----------
+
+UNICAST has issues when one end of the connnection unilaterally closes the connection and discards the state in
+the connection table.
+
+Example: we have a conn between A and B. There's a partition such that A sees {A,B} but B sees only {B}.
+B will clear its connection table for A on reception of the view, whereas A will keep it.
+
+Now the partition heals and A and B can communicate again.
+
+Assuming A's next seqno to B is #25 (and #7 for receiving messages from B),
+B will store the message because it expects #1 from A (new connection). As a matter of fact, B will store *and not
+deliver* all subsequent messages from A !
+
+The reverse direction is also bad: B will send #1 to A, but A expects #7, so A will discard the message. The first 6
+messages from B are discarded at A !
+
+
+Goals
+-----
+
+#1 Handle the above scenarios
+
+#2 Handle the scenario where a member communicates with a non-member (get rid of enabled_mbrs and prev_mbrs)
+
+#3 Handle the scenario where a member talks to a non existing (or previous) member. Get rid of
+ ENABLE_UNICASTS_TO and age out connections to non existing members after some time (JGRP-942)
+
+#4 Should be usable without group communication ('Unicast JGroups')
+
+
+Design
+------
+
+As example we have a unicast connection between A and B. A is the sender and B the receiver:
+
+ A <-------------------------------------------------> B
+
+ B:entry.seqno=#25 A:entry.seqno=#7
+ recv_win=#7 recv_win=#25
+ send-conn-id=322649 send-conn-id=101200
+ recv-conn-id=101200 recv-conn-id=322649
+
+A has an entry in the connection table for B, and B has an entry for A. Each connection has a connection ID (conn-id).
+Each entry also has a seqno which is the highest seqno sent to the peer so far, and a recv_win which has the highest
+seqno received from the peer so far. For example, A's next message to B will be #25, and the next seqno expected
+from B is #7.
+
+
+
+A sends a message to B:
+-----------------------
+- If the entry for B is null, or the seqno=0:
+ - Create an entry, set the seqno to 1 and set send-conn-id to the current time (needs to be unique, could also use UUIDs)
+ - Send the message with the next seqno and the current conn-id and first=true
+- Else
+ - Send the message with the next seqno and the current conn-id
+
+B receives a message from A:
+----------------------------
+- If first == true
+ - If entry or entry.recv_win for B == null
+ - Create a new entry.recv_win with msg.seqno
+ - Set entry.recv-conn-id to conn-id
+ - Else:
+ - If conn-id != entry.recv-conn-id:
+ - Create a new entry.recv_win with msg.seqno
+ - Set entry.recv-conn-id to conn-id
+ - Else
+ - NOP (prevents duplicate connection establishments)
+- Else
+ - If entry.recv_win == null || conn-id != recv-conn-id: no-op
+ - Drop message
+ - Send SEND_FIRST_SEQNO to A
+
+
+A receives GET_FIRST_SEQNO from B:
+----------------------------------
+- If conn-id != send-conn-id: drop message
+- A grabs the first message in its sent_win
+- A adds the entry.send-conn-id to the UnicastHeader (if not yet present), sets first=true and sends the message to B
+
+
+
+Scenarios
+---------
+
+The scenarios are tested in UNICAST_ConnectionTests
+
+#1 A creates new connection to B:
+- The entry for B is null, a new entry is created and added to the connection table
+- Entry.send-conn-id is set and sent with the message
+- Entry.seqno now is 1
+
+
+#2 B receives new connection:
+- B creates a new entry and entry.recv_win (with msg.seqno) for A
+- B sets entry.recv-conn-id to msg.conn-id
+- B adds the message to entry.recv_win
+
+
+#3 A and B close connection (e.g. based on a view change (partition)):
+- Both A and B reset (cancelling pending retransmissions) and remove the entry for their peer from the connection table
+
+
+#4 A closes the connection unilaterally (B keeps it open), then reopens it and sends a message:
+- A removes the entry for B from its connection table, cancelling all pending retransmissions
+- (Assuming that B's entry.recv_win for A is at #25)
+- A creates a new entry for B in its connection table
+- Entry.send-conn-id is set and sent with the message
+- Entry.seqno now is 1
+- B receives the message with a new conn-id
+- B does have an entry for A, but entry.recv-conn-id doesn't match msg.conn-id
+- B creates a new entry.recv_win, sets it to msg.seqno
+- B sets entry.recv-conn-id to msg.conn-id
+
+
+#5 B closes its connection unilaterally, then A sends a message to B:
+- B doesn't find an entry for A in its connection table
+- B discards the message and sends a SEND-FIRST-SEQNO to A
+- A receives the SEND-FIRST-SEQNO message. It grabs the message with the lowest seqno
+ in its entry.send_win, adds a UnicastHeader with entry.send-conn-id and sends the
+ message to B
+- B receive the message and creates a new entry and entry.recv_win (with msg.seqno)
+- B sets entry.recv-conn-id to msg.conn-id
+
+#6 Same as #4, but after re-establishing the connection to B, A loses the first message
+(first part of #4)
+- A creates a new sender window for B
+- A sends #1(conn-id=322649) #2(conn-id=0) #3(conn-id=0), but loses #1
+- B receives #2 first. It thinks this is part of a regular connection, so it doesn't trash its receiver window
+- B expects a seqno higher than #2 (from the prev conversation with A), and discards #2, but *acks* it nevertheless
+- A removes #2 from its sender window
+- B now finally receives #1, and creates a new receiver window for A at #1
+- A retransmits #3
+- B stores #3 but doesn't deliver it because it hasn't received #2 yet
+- However, B will *never* receive #2 from A because that seqno has been removed from A's sender window !
+
+
+#7 Merge where A and B are in different partitions:
+- Both A and B removes the entries for each other in their respective connection tables
+- When the partition heals, both A and B will create new entries (see scenario #2)
+
+
+#8 Merge where A and B are in overlapping partitions A: {A}, B: {A,B}:
+- (This case is currently handled by shunning, not merging)
+- A sends a message to B
+- A removed its entry for B, but B kept its entry for A
+- A new creates a new connection to B (scenario #1) and sends the message
+- B receives the message, but entry.recv-conn-id doesn't match msg.conn-id, so B
+ removes entry.recv_win, sets entry.recv-conn-id to msg.conn-id and creates a new
+ entry.recv_win with msg.seqno (same as second half of scenario #4)
+
+
+#9 Merge where A and B are in overlapping partitions A: {A,B}, B: {B}:
+- A sends a message to B (msg.seqno=25)
+- B doesn't have an entry for A
+- B discards the message and sends a SEND-FIRST-SEQNO to A
+- A receives the SEND-FIRST-SEQNO message. It grabs the message with the lowest seqno
+ in its entry.send_win, adds a UnicastHeader with entry.send-conn-id and sends the
+ message to B
+- B receive the message and creates a new entry and entry.recv_win (with msg.seqno)
+- B sets entry.recv-conn-id to msg.conn-id
+
+
+Issues
+------
+- How do we handle retransmissions of the first message (first=true) ? We *cannot* create a new entry.recv_win, or
+ else we trash already received msgs ! Use a UUID (as connection-ID) instead of first=true ? Maybe the system time
+ is sufficient ? After all, the ID only has to be unique between A and B !
+ ==> Solved by using connection IDs (see above)
+
+
diff -Nru libjgroups-java-2.7.0.GA/doc/design/UNICAST.txt libjgroups-java-2.12.2.Final/doc/design/UNICAST.txt
--- libjgroups-java-2.7.0.GA/doc/design/UNICAST.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/UNICAST.txt 2011-10-18 11:22:35.000000000 +0000
@@ -4,7 +4,6 @@
Author: Bela Ban
Date: Aug 10 2006
-Version: $Id: UNICAST.txt,v 1.3 2006/08/11 07:55:17 belaban Exp $
Sending a unicast message to P
diff -Nru libjgroups-java-2.7.0.GA/doc/design/UNIFORM.txt libjgroups-java-2.12.2.Final/doc/design/UNIFORM.txt
--- libjgroups-java-2.7.0.GA/doc/design/UNIFORM.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/UNIFORM.txt 2011-10-18 11:22:35.000000000 +0000
@@ -3,7 +3,6 @@
========================
Author: Bela Ban
-Version: $Id: UNIFORM.txt,v 1.2 2006/04/25 03:00:31 belaban Exp $
Definition
diff -Nru libjgroups-java-2.7.0.GA/doc/design/varia1.txt libjgroups-java-2.12.2.Final/doc/design/varia1.txt
--- libjgroups-java-2.7.0.GA/doc/design/varia1.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/varia1.txt 2011-10-18 11:22:35.000000000 +0000
@@ -1,4 +1,3 @@
-$Id: varia1.txt,v 1.1 2006/05/22 06:34:43 belaban Exp $
diff -Nru libjgroups-java-2.7.0.GA/doc/design/varia2.txt libjgroups-java-2.12.2.Final/doc/design/varia2.txt
--- libjgroups-java-2.7.0.GA/doc/design/varia2.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/varia2.txt 2011-10-18 11:22:35.000000000 +0000
@@ -1,4 +1,3 @@
-$Id: varia2.txt,v 1.1 2006/05/22 06:34:43 belaban Exp $
Design Issues
=============
@@ -21,7 +20,7 @@
seqnos from all current members (including itself) seen so far. It
also includes the new member, with a seqno of 0 (starting
seqno). Let's assume the coordinator has a seqno of 35. Now, the new
-view is mcast before the call (HandleJoin) returns to the client
+view is mcast before the call (handleJoin()) returns to the client
(containing the digest). The client therefore gets a wrong seqno for
the coordinator. The 2 scenarios are described below:
diff -Nru libjgroups-java-2.7.0.GA/doc/design/ViewHandling.txt libjgroups-java-2.12.2.Final/doc/design/ViewHandling.txt
--- libjgroups-java-2.7.0.GA/doc/design/ViewHandling.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/design/ViewHandling.txt 2011-10-18 11:22:35.000000000 +0000
@@ -4,7 +4,6 @@
=================
Author: Bela Ban
-Version: $Id: ViewHandling.txt,v 1.1 2006/01/27 14:46:12 belaban Exp $
Problem:
Merge, join and leave requests need to handled in the order in which they arrive. Currently,
diff -Nru libjgroups-java-2.7.0.GA/doc/history.txt libjgroups-java-2.12.2.Final/doc/history.txt
--- libjgroups-java-2.7.0.GA/doc/history.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/history.txt 2011-10-18 11:22:35.000000000 +0000
@@ -3,7 +3,6 @@
History List
============
-Revision: $Id: history.txt,v 1.192 2007/04/04 05:23:34 belaban Exp $
[For current version, see file Version.java (or invoke 'java org.jgroups.Version')]
diff -Nru libjgroups-java-2.7.0.GA/doc/JmxSupport.txt libjgroups-java-2.12.2.Final/doc/JmxSupport.txt
--- libjgroups-java-2.7.0.GA/doc/JmxSupport.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/JmxSupport.txt 2011-10-18 11:22:35.000000000 +0000
@@ -1,6 +1,5 @@
// Author: Bela Ban
-// $Id: JmxSupport.txt,v 1.3 2006/10/09 13:36:18 belaban Exp $
diff -Nru libjgroups-java-2.7.0.GA/doc/manual/.cvsignore libjgroups-java-2.12.2.Final/doc/manual/.cvsignore
--- libjgroups-java-2.7.0.GA/doc/manual/.cvsignore 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/manual/.cvsignore 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1 @@
+build
diff -Nru libjgroups-java-2.7.0.GA/doc/manual/en/images/RELAY.fig libjgroups-java-2.12.2.Final/doc/manual/en/images/RELAY.fig
--- libjgroups-java-2.7.0.GA/doc/manual/en/images/RELAY.fig 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/manual/en/images/RELAY.fig 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,74 @@
+#FIG 3.2 Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter
+100.00
+Single
+-2
+1200 2
+6 3375 4800 6375 9075
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3375 4800 6375 4800 6375 9075 3375 9075 3375 4800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3375 5400 6375 5400
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3375 6000 6375 6000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3375 6675 6375 6675
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3375 7350 6375 7350
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3375 8025 6375 8025
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3375 8550 6375 8550
+4 0 0 50 -1 16 16 0.0000 4 195 885 4425 5175 RELAY\001
+-6
+6 1575 825 4575 4200
+6 3750 1950 4350 2550
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 4050 2250 270 270 4050 2250 4200 2475
+4 0 0 50 -1 16 16 0.0000 4 195 180 3975 2400 A\001
+-6
+6 2100 1500 2700 2100
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 2400 1800 270 270 2400 1800 2550 2025
+4 0 0 50 -1 16 16 0.0000 4 195 195 2325 1875 C\001
+-6
+6 2475 2850 3075 3450
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 2775 3150 270 270 2775 3150 2925 3375
+4 0 0 50 -1 16 16 0.0000 4 195 180 2700 3225 B\001
+-6
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 3069 2364 1479 1479 3069 2364 4344 3114
+4 0 0 50 -1 16 16 0.0000 4 240 450 2850 4125 udp\001
+-6
+6 10125 2700 10725 3300
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 10425 3000 270 270 10425 3000 10575 3225
+4 0 0 50 -1 16 16 0.0000 4 195 165 10350 3075 F\001
+-6
+6 10200 1200 10800 1800
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 10500 1500 270 270 10500 1500 10650 1725
+4 0 0 50 -1 16 16 0.0000 4 195 180 10425 1650 E\001
+-6
+6 8700 1950 9300 2550
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 9000 2250 270 270 9000 2250 9150 2475
+4 0 0 50 -1 16 16 0.0000 4 195 195 8925 2325 D\001
+-6
+1 3 0 1 0 7 50 -1 -1 0.000 1 0.0000 9969 2289 1479 1479 9969 2289 11244 3039
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 2175 9450 8400 9450
+2 1 0 2 0 7 50 -1 -1 0.000 0 0 7 1 0 2
+ 1 1 4.00 60.00 120.00
+ 5475 9450 5475 4050
+2 1 0 2 0 7 50 -1 -1 0.000 0 0 7 1 0 2
+ 1 1 4.00 60.00 120.00
+ 5475 5175 7425 5175
+2 4 0 3 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 9525 2925 3600 2925 3600 1950 9525 1950 9525 2925
+4 0 0 50 -1 18 18 0.0000 4 225 2445 1800 600 Data Center NYC\001
+4 0 0 50 -1 18 18 0.0000 4 225 2415 8775 525 Data Center SFO\001
+4 0 0 50 -1 16 16 0.0000 4 195 990 7350 9300 Network\001
+4 0 0 50 -1 16 16 0.0000 4 255 3465 6525 5025 Relaying to other data center\001
+4 0 0 50 -1 16 16 0.0000 4 240 1320 4875 3900 Application\001
+4 0 0 50 -1 16 16 0.0000 4 210 360 6300 2325 tcp\001
+4 0 0 50 -1 16 16 0.0000 4 240 450 9750 4050 udp\001
+4 0 0 50 -1 2 18 0.0000 4 195 225 3975 2850 X\001
+4 0 0 50 -1 2 18 0.0000 4 195 225 8925 2850 Y\001
Binary files /tmp/AYciA0_poF/libjgroups-java-2.7.0.GA/doc/manual/en/images/RELAY.png and /tmp/XQ0f23GK1l/libjgroups-java-2.12.2.Final/doc/manual/en/images/RELAY.png differ
diff -Nru libjgroups-java-2.7.0.GA/doc/manual/en/images/StompArchitecture.fig libjgroups-java-2.12.2.Final/doc/manual/en/images/StompArchitecture.fig
--- libjgroups-java-2.7.0.GA/doc/manual/en/images/StompArchitecture.fig 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/manual/en/images/StompArchitecture.fig 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,146 @@
+#FIG 3.2 Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter
+100.00
+Single
+-2
+1200 2
+6 1650 6900 4275 8175
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 3375 7275 3375 6900 2550 6900 2550 7275 3375 7275
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 2475 7275 2475 6900 1650 6900 1650 7275 2475 7275
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 2475 7725 2475 7350 1650 7350 1650 7725 2475 7725
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 3375 7725 3375 7350 2550 7350 2550 7725 3375 7725
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 4275 7275 4275 6900 3450 6900 3450 7275 4275 7275
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 4275 7725 4275 7350 3450 7350 3450 7725 4275 7725
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 2475 8175 2475 7800 1650 7800 1650 8175 2475 8175
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 3375 8175 3375 7800 2550 7800 2550 8175 3375 8175
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 4275 8175 4275 7800 3450 7800 3450 8175 4275 8175
+-6
+6 5025 6900 7650 8175
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 6750 7275 6750 6900 5925 6900 5925 7275 6750 7275
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 5850 7275 5850 6900 5025 6900 5025 7275 5850 7275
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 5850 7725 5850 7350 5025 7350 5025 7725 5850 7725
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 6750 7725 6750 7350 5925 7350 5925 7725 6750 7725
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 7650 7275 7650 6900 6825 6900 6825 7275 7650 7275
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 7650 7725 7650 7350 6825 7350 6825 7725 7650 7725
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 5850 8175 5850 7800 5025 7800 5025 8175 5850 8175
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 6750 8175 6750 7800 5925 7800 5925 8175 6750 8175
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 7650 8175 7650 7800 6825 7800 6825 8175 7650 8175
+-6
+6 1800 600 4425 1875
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 3525 975 3525 600 2700 600 2700 975 3525 975
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 2625 975 2625 600 1800 600 1800 975 2625 975
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 2625 1425 2625 1050 1800 1050 1800 1425 2625 1425
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 3525 1425 3525 1050 2700 1050 2700 1425 3525 1425
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 4425 975 4425 600 3600 600 3600 975 4425 975
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 4425 1425 4425 1050 3600 1050 3600 1425 4425 1425
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 2625 1875 2625 1500 1800 1500 1800 1875 2625 1875
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 3525 1875 3525 1500 2700 1500 2700 1875 3525 1875
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 4425 1875 4425 1500 3600 1500 3600 1875 4425 1875
+-6
+6 5475 600 8100 1875
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 7200 975 7200 600 6375 600 6375 975 7200 975
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 6300 975 6300 600 5475 600 5475 975 6300 975
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 6300 1425 6300 1050 5475 1050 5475 1425 6300 1425
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 7200 1425 7200 1050 6375 1050 6375 1425 7200 1425
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 8100 975 8100 600 7275 600 7275 975 8100 975
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 8100 1425 8100 1050 7275 1050 7275 1425 8100 1425
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 6300 1875 6300 1500 5475 1500 5475 1875 6300 1875
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 7200 1875 7200 1500 6375 1500 6375 1875 7200 1875
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 8100 1875 8100 1500 7275 1500 7275 1875 8100 1875
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 2400 4575 3825 4575 3825 5325 2400 5325 2400 4575
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 2400 3375 3825 3375 3825 4125 2400 4125 2400 3375
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 5025 3375 6450 3375 6450 4125 5025 4125 5025 3375
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 5025 4575 6450 4575 6450 5325 5025 5325 5025 4575
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 3.00 60.00 120.00
+ 2250 6750 2250 5625
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 3.00 60.00 120.00
+ 3000 6750 3000 5625
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 3.00 60.00 120.00
+ 3600 6750 3600 5625
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 3.00 60.00 120.00
+ 5400 6825 5400 5700
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 3.00 60.00 120.00
+ 6075 6825 6075 5700
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 3.00 60.00 120.00
+ 6975 6825 6450 5700
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 3.00 60.00 120.00
+ 3150 2025 3150 3150
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 3.00 60.00 120.00
+ 2325 2025 2775 3150
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 3.00 60.00 120.00
+ 3975 2025 3600 3150
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 3.00 60.00 120.00
+ 5850 2025 5850 3150
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 3.00 60.00 120.00
+ 7725 2025 6450 3150
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 3.00 60.00 120.00
+ 6825 2025 6075 3150
+3 3 0 1 0 7 50 -1 -1 0.000 0 0 0 11
+ 1800 3075 3150 2400 4725 2550 6600 2400 7575 3600 7500 5250
+ 6375 6225 4050 6225 2325 6000 1575 4575 1800 3075
+ -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000
+ -1.000 -1.000 -1.000
+4 0 0 50 -1 16 16 0.0000 4 195 825 2775 3825 NodeA\001
+4 0 0 50 -1 16 16 0.0000 4 195 825 5400 3825 NodeB\001
+4 0 0 50 -1 16 16 0.0000 4 195 840 5400 5025 NodeD\001
+4 0 0 50 -1 16 16 0.0000 4 195 840 2775 5025 NodeC\001
+4 0 0 50 -1 16 16 0.0000 4 195 825 8325 1350 Clients\001
+4 0 0 50 -1 16 16 0.0000 4 195 825 750 1350 Clients\001
+4 0 0 50 -1 16 16 0.0000 4 195 825 600 7650 Clients\001
+4 0 0 50 -1 16 16 0.0000 4 195 825 8250 7650 Clients\001
Binary files /tmp/AYciA0_poF/libjgroups-java-2.7.0.GA/doc/manual/en/images/StompArchitecture.png and /tmp/XQ0f23GK1l/libjgroups-java-2.12.2.Final/doc/manual/en/images/StompArchitecture.png differ
diff -Nru libjgroups-java-2.7.0.GA/doc/manual/en/images/StompProtocol.fig libjgroups-java-2.12.2.Final/doc/manual/en/images/StompProtocol.fig
--- libjgroups-java-2.7.0.GA/doc/manual/en/images/StompProtocol.fig 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/manual/en/images/StompProtocol.fig 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,34 @@
+#FIG 3.2 Produced by xfig version 3.2.5
+Landscape
+Center
+Inches
+Letter
+100.00
+Single
+-2
+1200 2
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4950 2025 7575 2025 7575 2850 4950 2850 4950 2025
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4950 2925 7575 2925 7575 3750 4950 3750 4950 2925
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4950 3825 7575 3825 7575 4650 4950 4650 4950 3825
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4950 4725 7575 4725 7575 5550 4950 5550 4950 4725
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4950 5625 7575 5625 7575 6450 4950 6450 4950 5625
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4950 6525 7575 6525 7575 7350 4950 7350 4950 6525
+2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
+ 8325 7800 8325 1650 4425 1650 4425 7800 8325 7800
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
+ 1 1 3.00 60.00 120.00
+ 2400 2400 4800 2400
+4 0 0 50 -1 16 18 0.0000 4 285 1290 5625 7050 Transport\001
+4 0 0 50 -1 16 18 0.0000 4 225 1065 5775 2550 STOMP\001
+4 0 0 50 -1 16 18 0.0000 4 225 1230 5625 4425 NAKACK\001
+4 0 0 50 -1 16 18 0.0000 4 225 840 5700 3525 FRAG\001
+4 0 0 50 -1 16 18 0.0000 4 225 750 5625 6150 PING\001
+4 0 0 50 -1 16 18 0.0000 4 285 1095 5625 5250 FD_ALL\001
+4 0 0 50 -1 16 18 0.0000 4 225 600 3375 2325 TCP\001
+4 0 0 50 -1 16 18 0.0000 4 225 1995 300 2475 STOMP clients\001
Binary files /tmp/AYciA0_poF/libjgroups-java-2.7.0.GA/doc/manual/en/images/StompProtocol.png and /tmp/XQ0f23GK1l/libjgroups-java-2.12.2.Final/doc/manual/en/images/StompProtocol.png differ
diff -Nru libjgroups-java-2.7.0.GA/doc/manual/en/images/Tunneling.fig libjgroups-java-2.12.2.Final/doc/manual/en/images/Tunneling.fig
--- libjgroups-java-2.7.0.GA/doc/manual/en/images/Tunneling.fig 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/manual/en/images/Tunneling.fig 2011-10-18 11:22:35.000000000 +0000
@@ -11,12 +11,6 @@
3000 225 3000 3675
2 1 0 3 0 7 100 0 41 0.000 0 0 -1 0 0 2
6675 225 6675 3675
-2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
- 1 1 1.00 60.00 120.00
- 2250 2325 3975 2175
-2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 0 2
- 1 1 1.00 60.00 120.00
- 7575 2325 5250 2175
2 2 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
1050 1125 2250 1125 2250 3000 1050 3000 1050 1125
2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 2
@@ -34,28 +28,39 @@
2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 2
7575 1650 8775 1650
2 2 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
- 3975 2025 5250 2025 5250 2700 3975 2700 3975 2025
-2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 1 2
+ 3975 2850 5250 2850 5250 3525 3975 3525 3975 2850
+2 2 0 1 0 7 100 0 -1 0.000 0 0 -1 0 0 5
+ 3975 1050 5250 1050 5250 1725 3975 1725 3975 1050
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+ 1 1 1.00 60.00 120.00
+ 1 1 1.00 60.00 120.00
+ 2250 2775 3975 3225
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
+ 1 1 1.00 60.00 120.00
+ 1 1 1.00 60.00 120.00
+ 2250 2625 3975 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
1 1 1.00 60.00 120.00
1 1 1.00 60.00 120.00
- 2250 2697 3975 2547
-2 1 0 1 0 7 100 0 -1 0.000 0 0 -1 1 1 2
+ 7575 2775 5250 3225
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 1 1 2
1 1 1.00 60.00 120.00
1 1 1.00 60.00 120.00
- 7573 2731 5248 2581
+ 7575 2625 5250 1350
4 0 0 50 0 16 11 0.0000 4 120 495 1350 675 Host A\001
4 0 0 50 0 16 11 0.0000 4 120 495 4200 675 Host B\001
4 0 0 50 0 16 11 0.0000 4 120 510 7800 675 Host C\001
-4 0 0 50 0 16 11 0.0000 4 120 300 3150 2175 TCP\001
-4 0 0 50 0 16 11 0.0000 4 120 360 1425 1500 GMS\001
-4 0 0 50 0 16 11 0.0000 4 120 210 1500 1950 FD\001
-4 0 0 50 0 16 11 0.0000 4 120 390 1425 2400 PING\001
-4 0 0 50 0 16 11 0.0000 4 120 630 1275 2850 TUNNEL\001
-4 0 0 50 0 16 11 0.0000 4 120 630 7800 2850 TUNNEL\001
-4 0 0 50 0 16 11 0.0000 4 120 390 7950 2400 PING\001
-4 0 0 50 0 16 11 0.0000 4 120 210 8025 1950 FD\001
-4 0 0 50 0 16 11 0.0000 4 120 360 7950 1500 GMS\001
-4 0 0 50 0 16 11 0.0000 4 150 945 4125 2400 GossipRouter\001
-4 0 0 50 0 16 11 0.0000 4 120 300 3150 2775 TCP\001
-4 0 0 50 0 16 11 0.0000 4 120 300 6075 2175 TCP\001
-4 0 0 50 0 16 11 0.0000 4 120 300 6075 2775 TCP\001
+4 0 0 50 0 16 11 0.0000 4 120 375 1425 1500 GMS\001
+4 0 0 50 0 16 11 0.0000 4 120 225 1500 1950 FD\001
+4 0 0 50 0 16 11 0.0000 4 120 405 1425 2400 PING\001
+4 0 0 50 0 16 11 0.0000 4 120 660 1275 2850 TUNNEL\001
+4 0 0 50 0 16 11 0.0000 4 120 660 7800 2850 TUNNEL\001
+4 0 0 50 0 16 11 0.0000 4 120 405 7950 2400 PING\001
+4 0 0 50 0 16 11 0.0000 4 120 225 8025 1950 FD\001
+4 0 0 50 0 16 11 0.0000 4 120 375 7950 1500 GMS\001
+4 0 0 50 0 16 11 0.0000 4 150 1020 4125 3225 GossipRouter\001
+4 0 0 50 0 16 11 0.0000 4 150 1020 4125 1500 GossipRouter\001
+4 0 0 50 0 16 11 0.0000 4 120 330 3150 1800 TCP\001
+4 0 0 50 0 16 11 0.0000 4 120 330 6150 1800 TCP\001
+4 0 0 50 0 16 11 0.0000 4 120 330 6150 2850 TCP\001
+4 0 0 50 0 16 11 0.0000 4 120 330 3225 2850 TCP\001
Binary files /tmp/AYciA0_poF/libjgroups-java-2.7.0.GA/doc/manual/en/images/Tunneling.png and /tmp/XQ0f23GK1l/libjgroups-java-2.12.2.Final/doc/manual/en/images/Tunneling.png differ
diff -Nru libjgroups-java-2.7.0.GA/doc/manual/en/master.xml libjgroups-java-2.12.2.Final/doc/manual/en/master.xml
--- libjgroups-java-2.7.0.GA/doc/manual/en/master.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/manual/en/master.xml 2011-10-18 11:22:35.000000000 +0000
@@ -3,8 +3,8 @@
"../../../../docbook-support/support/docbook-dtd/docbookx.dtd" [
-
-
+
+
@@ -14,8 +14,7 @@
Reliable Multicasting with the JGroups Toolkit
- $Date: 2008/01/23 14:36:56 $
- $Revision: 1.10 $
+ Jan 2011Bela
@@ -31,51 +30,41 @@
- 1998-2008
+ 1998-2006Bela Ban
- 2006-2008
+ 2006-2011Red Hat Inc
- This document is copyrighted. Copies are allowed for
- personal use. Redistribution only with written permission of the author(s).
+ This document is licensed under the
+
+ Creative Commons Attribution-ShareAlike (CC-BY-SA) 3.0
+
+ Foreword
- This is the Programmer's and User's Guide for
- JGroups. It provides information about the following areas:
+ This is the JGroups manual. It provides information about:
- Installation and configuration.
+ Installation and configuration
- Using JGroups.
+ Using JGroups (the API)
- Architecture and implementation of JGroups. Focus on the
- protocol stack and protocols.
+ Configuration of the JGroups protocols
- Most of the Installation and User's Guide has been copied
- from what is freely available on the
- JGroups web site
- .
- However, the focus of this document is to introduce programmers
- who want to learn more about JGroups to the architecture and
- implementation of JGroups. I will for example go into the
- details of the protocol stack, how a message traverses the stack,
- and how protocols can process it. I will also explain the various
- design decisions I had to make when designing JGroups, which
- hopefully leads to a better understanding of why things are the
- way they are.
+
+ The focus is on how to use JGroups, not on how JGroups is implemented.
Here are a couple of points I want to abide by throughout
@@ -88,7 +77,7 @@
I like simplicity. Keep It Simple and Stupid. This is
- one of the biggest goals I have both in writing this book
+ one of the biggest goals I have both in writing this manual
and in writing JGroups. It is easy to explain simple
concepts in complex terms, but it is hard to explain a
complex system in simple terms. I'll try to do the
@@ -101,13 +90,13 @@
So, how did it all start?I spent 1998-1999 at the Computer Science Department at
- Cornell University for a post-doc, in Ken Birman's group. Ken is
+ Cornell University as a post-doc, in Ken Birman's group. Ken is
credited with inventing the group communication paradigm,
especially the Virtual Synchrony model. At the time they were
working on their third generation group communication prototype,
called Ensemble. Ensemble followed Horus (written in C by Robbert
VanRenesse), which followed ISIS (written by Ken Birman, also in
- C). Ensemble was written in OCaml, developed at INRIA, which is a
+ C). Ensemble was written in OCaml, developed at INRIA, and is a
functional language and related to ML. I never liked the OCaml
language, which in my opinion has a hideous syntax. Therefore I
never got warm with Ensemble either.
@@ -115,8 +104,7 @@
However, Ensemble had a Java interface (implemented by a
student in a semester project) which allowed me to program in Java
and use Ensemble underneath. The Java part would require that an
- Ensemble process was running somewhere on the same machine, or
- within the same network, and would connect to it via a
+ Ensemble process was running somewhere on the same machine, and would connect to it via a
bidirectional pipe. The student had developed a simple protocol
for talking to the Ensemble engine, and extended the engine as
well to talk back to Java.
@@ -157,7 +145,7 @@
In the fall of 2002, Sacha Labourey contacted me, letting me know that JGroups was being used by JBoss for
their clustering implementation. I joined JBoss in 2003 and have been working on JGroups and JBossCache. My
- goal is to make JGroups the most widely used clustering software in the Java space...
+ goal is to make JGroups the most widely used clustering software in Java ...
Bela Ban, San Jose, Aug 2002, Kreuzlingen Switzerland 2006
@@ -175,7 +163,7 @@
many fruitful discussions of all aspects of group communication in
particular and distributed systems in general.
- I want to dedicate this book to Jeannette and Michelle.
+ I want to dedicate this manual to Jeannette and Michelle.
diff -Nru libjgroups-java-2.7.0.GA/doc/manual/en/modules/advanced.xml libjgroups-java-2.12.2.Final/doc/manual/en/modules/advanced.xml
--- libjgroups-java-2.7.0.GA/doc/manual/en/modules/advanced.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/manual/en/modules/advanced.xml 2011-10-18 11:22:35.000000000 +0000
@@ -39,285 +39,9 @@
two different channels.
-
- Using the Multiplexer to run multiple building blocks over the same
- channel
-
- In JBoss we have multiple JGroups channels, one for each application
- (e.g. JBossCache, ClusterPartition etc).
-
- The goal of the Multiplexer is to combine all stacks with the
- same configuration into one, and have multiple
- services on top of that same channel.
-
- To do this, we have to introduce multiplexing and demultiplexing
- functionality, ie. each service will have to have a unique service ID (a
- string), and when sending a message, the message has to be tagged with
- that ID. When receiving a message, it will be dispatched to the right
- destination service based on the ID attached to the message. We require
- special handling for VIEW and SUSPECT messages: those need to be
- dispatched to *all* services. State transfer also needs to be handled
- specially, here we probably have to use thread locals, or change the API
- (TBD).
-
- When deployed into JBoss, the Multiplexer will be exposed as an
- MBean, and all services that depend on it will be deployed with dependency
- injection on the Multiplexer. Of course, the old configuration will still
- be supported.
-
- The config of the Multiplexer is done via a config file, which lists
- a number of stacks, each keyed by a name, e.g. "udp", "tcp", "tcp-nio"
- etc. See ./conf/stacks.xml for an example. An app is configured with the
- name of a stack, e.g. "udp", and a reference to the Multiplexer MBean. It
- will get a proxy channel through which all of its communication will take
- place. The proxy channel (MuxChannel) will mux/demux messages to the real
- JGroups channel.
-
- The advantage of the Multiplexer is that we can reduce N channels
- into M where M < N. This means fewer threads, therefore fewer context
- switches, less memory consumption and easier configuration and better
- support.
- The Multiplexer API
-
- The Multiplexer is actually a JChannelFactory, which is configured
- with a reference to an XML configuration file, and has a few additional
- methods to get a Channel. The channel returned is actually an instance
- of MuxChannel, which transparently forwards all invocations to the
- underlying JChannel, and performs multiplexing and demultiplexing.
- Multiple MuxChannels can share the same underlying JChannel, and each
- message sent by a service over the MuxChannel will add the services's ID
- to the message (as a header). That ID is then used to demultiplex the
- message to the correct MuxChannel when received.
-
- The methods of the JChannelFactory are:
-
-
- public Channel createMultiplexerChannel(String stack_name, String id) throws Exception;
- public Channel createMultiplexerChannel(String stack_name, String id, boolean register_for_state_transfer, String substate_id) throws Exception;
-
-
- The stack_name parameter refers to a channel configuration defined
- in a separate file (see below).
-
- The id parameter is the service ID and has to be unique for all
- services sitting on the same channel. If an ID is used more than once,
- when trying to call createMultiplexerChannel(), an exception will be
- thrown.
-
- the register_for_state_transfer and substate_id parameters are
- discussed below (in ).
-
- The stack_name parameter is a reference to a stack, for example
- defined in stacks.xml. A shortened version of stacks.xml is shown
- below:
-
-
- <protocol_stacks>
- <stack name="fc-fast-minimalthreads" description="Flow control, no up or down threads">
- <config>
- <UDP mcast_port="45566"
- enable_bundling="true"/>
- ...
- <pbcast.STATE_TRANSFER down_thread="false" up_thread="false"/>
- </config>
- </stack>
-
- <stack name="sequencer" description="Totally ordered multicast using a sequencer">
- <config>
- // config
- </config>
- </stack>
-
- <stack name="tcp" description="Using TCP as transport">
- <config>
- <TCP start_port="7800" loopback="true" send_buf_size="100000" recv_buf_size="200000"/>
- <TCPPING timeout="3000" initial_hosts="localhost[7800]" port_range="3" num_initial_members="3"/>
- <FD timeout="2000" max_tries="4"/>
- <VERIFY_SUSPECT timeout="1500" down_thread="false" up_thread="false"/>
- <pbcast.NAKACK gc_lag="100" retransmit_timeout="600,1200,2400,4800"/>
- <pbcast.STABLE stability_delay="1000" desired_avg_gossip="20000" down_thread="false" max_bytes="0" up_thread="false"/>
- <VIEW_SYNC avg_send_interval="60000" down_thread="false" up_thread="false" />
- <pbcast.GMS print_local_addr="true" join_timeout="5000" shun="true"/>
- </config>
- </stack>
-
- <stack name="discovery" description="Simple UDP-only stack for discovery">
- <config>
- <UDP mcast_port="7609"
- mcast_addr="228.15.15.15"
- ip_ttl="32"/>
- </config>
- </stack>
- </protocol_stacks>
-
-
- This file defines 4 configurations: fc-fast-minimalthreads,
- sequencer, tcp and discovery. The first service to call
- JChannelFactory.createMultiplexerChannel() with a stack_name of "tcp"
- will create the JChannel with the "tcp" configuration, all subsequent
- method calls for the same stack_name ("tcp") will
- simply get a MuxChannel which has a reference to the same underlying
- JChannel. When a service closes a MuxChannel, the underlying JChannel
- will only be closed when there are no more MuxChannels referring to
- it.
-
- For more information on Multiplexing refer to
- JGroups/doc/design/Multiplexer.txt
-
-
- Batching state transfers
-
- Note that this feature is currently not
- used in JBoss, because JBoss doesn't call all create() methods of all
- dependent beans first, and then all start() methods. The call sequence
- is indeterministic unless all dependent beans are defined in the same
- XML file, which is unrealistic. We're looking into using a barrier
- service to provide the guarantee that all create() methods are called
- before all start() methods, possibly in JBoss 5.
-
- When multiple services are sharing a JChannel, and each of the
- services requires state transfer at a different time, then we need
- FLUSH (see ./doc/design/PartialStateTransfer.txt for a description of
- the problem). FLUSH is also called the stop-the-world model, and
- essentially stops everyone in a group from sending messages until the
- state has been transferred, and then everyone can resume again.
- The 2.3 release of JGroups will
-
- not
-
- have the FLUSH protocol integrated, so state transfer for the Multiplexer might be incorrect. 2.4 will have FLUSH, so that situation will be corrected. The main reason for putting Multiplexing into 2.3 is that people can start programming against the API, and then use it when FLUSH is available.
-
-
- When multiple services share one JChannel, then we have to run
- the FLUSH protocol for every service which requires state, so if we
- have services A, B, C, D and E running on top of a JChannel J, and B,C
- and E require state, then the FLUSH protocol has to be run 3 times,
- which slows down startup (e.g.) of JBoss.
-
- To remedy this, we can batch state
- transfers, so that we suspend everyone from sending messages, then
- fetch the states for B, C and E at once, and then resume everyone.
- Thus, the FLUSH protocol has to be run only once.
-
- To do this, a service has to register with the JChannelFactory
- when creating the MuxChannel, and know that getState() will be a no-op
- until the last registered application has called getState(). This
- works as follows:
-
- B, C and D register for state transfer
-
-
-
- B calls MuxChannel.getState(). Nothing happens.
-
-
-
- D calls MuxChannel.getState(). Nothing happens.
-
-
-
- E calls MuxChannel.getState(). Now everyone who registered has called getState() and therefore we transfer the state for B, C and E (using partial state transfer).
-
-
-
- At this point B, C and D's setState() will be called, so that they can set the state.
-
-
-
- The code below (a snipper from MultiplexerTest) shows how
- services can register for state transfers. In an MBean (JBoss)
- environment, the registration could be done in the create() callback,
- and the actual getState() call in start().
-
-
- public void testStateTransferWithRegistration() throws Exception {
- final String STACK_NAME="fc-fast-minimalthreads";
- Channel ch1, ch2;
- ch1=factory.createMultiplexerChannel(STACK_NAME, "c1", true, null); // register for (entire) state transfer
- ch1.connect("bla"); // will create a new JChannel
-
- ch2=factory.createMultiplexerChannel(STACK_NAME, "c2", true, null); // register for (entire) state transfer
- ch2.connect("bla"); // will share the JChannel created above (same STACK_NAME)
-
- boolean rc=ch1.getState(null, 5000); // this will *not* trigger the state transfer protocol
- rc=ch2.getState(null, 5000); // only *this* will trigger the state transfer
- }
-
-
- The example above shows that 2 services ("c1" and "c2") share a
- common JChannel because they use the same stack_name (STACK_NAME). It
- also shows that only the second getState() invocation will actually
- transfer the 2 states (for "c1" and "c2").
-
-
-
-
- Service views
-
- When we have multiple service running on the same channel, then
- some services might get redeployed or stopped independently from the other
- services. So we might have a situation where we have services S1, S2 and
- S3 running on host H1, but on host H2, only services S2 and S3 are
- running.
-
- The cluster view is {H1, H2}, but the
- service views are:
-
-
-
- S1: {H1}
-
-
-
- S2: {H1, H2}
-
-
-
- S3: {H1, H2}
-
-
-
- This can also be seen as ordered by hosts:
-
-
-
- H1: {S1, S2, S3}
-
-
-
- H2: {S2, S3}
-
-
-
- So here we host H1 running services S1, S2 and S3, whereas H2 is
- only running S2 and S3. S1 might be in the process of being redeployed
- on H2, or is simply not running.
-
- A service view is essentially a list of nodes of a cluster on
- which a given service S is currently running. Service views are always
- subsets of cluster views. Here's a reason we need service views:
- consider the example above. Let's say service S1 on H1 wants to make a
- cluster-wide method invocation on all instances of S1 running on any
- host. Now, S1 is only running on H1, therefore we have to make the
- invocation only on S1. However, if we took the cluster view rather than
- the service view, the invocation would be across H1 and H2, and we'd be
- waiting for a response from the (non-existent) service S1 on H2 forever
- !
-
- So, by default, calling MuxChannel.getView() will return the
- service view rather than the cluster view. The cluster view can be
- retrieved calling MuxChannel.getClusterView().
-
- There are example unit tests in MultiplexerTest and
- MultiplexerViewTest. The latter tests service views versus cluster
- views.
-
-
-
-
- Sharing a transport between multiple channels in a JVM
+ The shared transport: sharing a transport between multiple channels in a JVM
To save resources (threads, sockets and CPU cycles), transports of channels residing within the same
@@ -645,14 +369,14 @@
The following example shows how to disable the use of IP
multicasting and use a GossipRouter instead. Only the bottom two
protocols are shown, the rest of the stack is the same as in the
- previous example:
-
+ previous example:
- <UDP ip_mcast="false" mcast_addr="224.0.0.35" mcast_port="45566" ip_ttl="32"
- mcast_send_buf_size="150000" mcast_recv_buf_size="80000"/>
- <PING gossip_host="localhost" gossip_port="5555" gossip_refresh="15000"
- timeout="2000" num_initial_members="3"/>
-
+ <UDP ip_mcast="false" mcast_addr="224.0.0.35" mcast_port="45566" ip_ttl="32"
+ mcast_send_buf_size="150000" mcast_recv_buf_size="80000"/>
+ <PING gossip_host="localhost" gossip_port="5555" gossip_refresh="15000"
+ timeout="2000" num_initial_members="3"/>
+
+ The property ip_mcast is set to
false in UDP and the gossip
@@ -684,8 +408,7 @@
WANs.The properties for a typical stack based on TCP might look like
- this (edited/protocols removed for brevity):
-
+ this (edited/protocols removed for brevity):
<TCP start_port="7800" />
<TCPPING timeout="3000"
@@ -702,7 +425,8 @@
<pbcast.GMS print_local_addr="true" join_timeout="3000"
shun="true"
view_bundling="true"/>
-
+
+
@@ -788,6 +512,10 @@
. The only difference is that TCPGOSSIP allows for
multiple GossipRouters instead of only one.
+
+
+ JDBC_PING: using a shared database via JDBC or DataSource.
+ The next two section illustrate the use of TCP with both TCPPING
@@ -797,13 +525,13 @@
Using TCP and TCPPINGA protocol stack using TCP and TCPPING looks like this (other
- protocols omitted):
-
+ protocols omitted):
- <TCP start_port="7800" /> +
- <TCPPING initial_hosts="HostA[7800],HostB[7800]" port_range="5"
- timeout="3000" num_initial_members="3" />
-
+ <TCP start_port="7800" /> +
+ <TCPPING initial_hosts="HostA[7800],HostB[7800]" port_range="5"
+ timeout="3000" num_initial_members="3" />
+
+ The concept behind TCPPING is that no external daemon such as
GossipRouter is needed. Instead some selected group members assume the
@@ -838,13 +566,13 @@
gossip_port and
gossip_refresh set. However, in TCPGOSSIP these
properties are called differently as shown below (only the bottom two
- protocols are shown):
-
-
- <TCP />
- <TCPGOSSIP initial_hosts="localhost[5555],localhost[5556]" gossip_refresh_rate="10000"
- num_initial_members="3" />
-
+ protocols are shown):
+
+ <TCP />
+ <TCPGOSSIP initial_hosts="localhost[5555],localhost[5556]" gossip_refresh_rate="10000"
+ num_initial_members="3" />
+
+
The initial_hosts properties combines
both the host and port of a GossipRouter, and it is possible to
@@ -890,20 +618,24 @@
so other members (possibly also behind firewalls) can access it.The solution works as follows. A channel inside a firewall has
- to use protocol TUNNEL instead of UDP as bottommost layer in the
- stack, plus either PING or TCPGOSSIP, as shown below (only the bottom
- two protocols shown):
-
-
- <TUNNEL router_host="localhost" router_port="12001" />
- <TCPGOSSIP initial_hosts="localhost[12001]" gossip_refresh_rate="10000"
- num_initial_members="3" />
-
+ to use protocol TUNNEL instead of UDP or TCP as bottommost layer. Recommended
+ discovery protocol is PING, starting with 2.8 release, you do not have to specify
+ any gossip routers in PING.
+
+ <TUNNEL gossip_router_hosts="127.0.0.1[12001]" />
+ <PING />
+
+
TCPGOSSIP uses the GossipRouter (outside
the firewall) at port 12001 to register its address
(periodically) and to retrieve the initial membership for its
- group.
+ group. It is not recommended to use TCPGOSSIP for discovery if TUNNEL is
+ already used. TCPGOSSIP might be used in rare scenarios when registration and
+ initial member discovery has to be done through gossip
+ router indepedent of transport protocol being used. Starting with 2.8 release
+ TCPGOSSIP accepts one or multiple router hosts as a comma delimited list
+ of host[port] elements specified in a property initial_hosts.
TUNNEL establishes a TCP connection to the
GossipRouter process (also outside the firewall) that
@@ -920,7 +652,10 @@
Note that TUNNEL has to be given the
hostname and port of the GossipRouter process. This example assumes a GossipRouter
is running on the local host at port 12001. Both
- TUNNEL and TCPGOSSIP (or PING) access the same GossipRouter.
+ TUNNEL and TCPGOSSIP (or PING) access the same GossipRouter.
+ Starting with 2.8 release TUNNEL transport layer accepts one or multiple router
+ hosts as a comma delimited list of host[port] elements specified in a
+ property gossip_router_hosts.Any time a message has to be sent, TUNNEL forwards the message
to GossipRouter, which distributes it to its destination: if the message's
@@ -933,6 +668,28 @@
To do so, GossipRouter has to maintain a table between groups,
member addresses and TCP connections.
.
+
+
+ Starting with 2.8 release, gossip router is no longer a single
+ point of failure. In a set-up with multiple gossip routers, routers do
+ not communicate among themselves, and single point of failure is avoided
+ by having each channel simply connect to multiple available routers. In
+ case one or more routers go down, cluster members are still able to
+ exchange message through remaining available router instances, if there
+ are any.
+
+ For each send invocation, a channel goes through a list of available
+ connections to routers and attempts to send a message on each connection
+ until it succeeds. If a message could not be sent on any of the
+ connections – an exception is raised. Default policy for connection
+ selection is random. However, we also provide an plug-in interface for
+ other policies as well.
+
+ Gossip router configuration is static and is not updated for the
+ lifetime of the channel. A list of available routers has to be provided
+ in channel configuration file.
+
+
To tunnel a firewall using JGroups, the following steps have to
be taken:
@@ -944,11 +701,11 @@
- Start the GossipRouter:
-
-
- start org.jgroups.stack.GossipRouter -port 12001
-
+ Start the GossipRouter:
+
+ start org.jgroups.stack.GossipRouter -port 12001
+
+
@@ -1001,24 +758,15 @@
connection to B. Also, applications behind a firewall would be able to
talk to each other, joining a group.
- However, there are several drawbacks: first, the central
- GossipRouter process constitute a single point of failure
- (if host B crashes)
- Although multiple GossipRouters could be started
- , second, having to maintain a TCP connection for the
+ However, there are several drawbacks: first, having to maintain a TCP connection for the
duration of the connection might use up resources in the host system
- (e.g. in the GossipRouter), leading to scalability problems, third, this
+ (e.g. in the GossipRouter), leading to scalability problems, second, this
scheme is inappropriate when only a few channels are located behind
firewalls, and the vast majority can indeed use IP multicast to
communicate, and finally, it is not always possible to enable outgoing
traffic on 2 ports in a firewall, e.g. when a user does not 'own' the
firewall.
-
-
- There will be a major overhaul of GossipRouter/TUNNEL in 2.6, where we'll streamline the connection
- table and possibly introduce new functionality such as connecting to multiple GossipRouters,
- connecting to both IP multicasting and TCP based clients etc.
-
+
@@ -1241,6 +989,71 @@
+
+ Scopes: concurrent message delivery for messages from the same sender
+
+ In the previous paragraph, we showed how the concurrent stack delivers messages from different senders
+ concurrently. But all (non-OOB) messages from the same sender P are delivered in the order in which
+ P sent them. However, this is not good enough for certain types of applications.
+
+
+ Consider the case of an application which replicates HTTP sessions. If we have sessions X, Y and Z, then
+ updates to these sessions are delivered in the order in which there were performed, e.g. X1, X2, X3,
+ Y1, Z1, Z2, Z3, Y2, Y3, X4. This means that update Y1 has to wait until updates X1-3 have been delivered.
+ If these updates take some time, e.g. spent in lock acquisition or deserialization, then all subsequent
+ messages are delayed by the sum of the times taken by the messages ahead of them in the delivery order.
+
+
+ However, in most cases, updates to different web sessions should be completely unrelated, so they could
+ be delivered concurrently. For instance, a modification to session X should not have any effect on
+ session Y, therefore updates to X, Y and Z can be delivered concurrently.
+
+
+ One solution to this is out-of-band (OOB) messages (see next paragraph). However, OOB messages do not
+ guarantee ordering, so updates X1-3 could be delivered as X1, X3, X2. If this is not wanted, but
+ messages pertaining to a given web session should all be delivered concurrently between sessions, but
+ ordered within a given session, then we can resort to scoped messages.
+
+
+ Scoped messages apply only to regular (non-OOB) messages, and are delivered
+ concurrently between scopes, but ordered within a given scope. For example, if we used the sessions above
+ (e.g. the jsessionid) as scopes, then the delivery could be as follows ('->' means sequential, '||' means concurrent):
+
+ X1 -> X2 -> X3 -> X4 || Y1 -> Y2 -> Y3 || Z1 -> Z2 -> Z3
+
+ This means that all updates to X are delivered in parallel to updates to Y and updates to Z. However, within
+ a given scope, updates are delivered in the order in which they were performed, so X1 is delivered before
+ X2, which is deliverd before X3 and so on.
+
+
+ Taking the above example, using scoped messages, update Y1 does not have to wait for
+ updates X1-3 to complete, but is processed immediately.
+
+
+ To set the scope of a message, use method Message.setScope(short).
+
+
+ Scopes are implemented in a separate protocol called . This protocol
+ has to be placed somewhere above ordering protocols like UNICAST or NAKACK (or SEQUENCER for that matter).
+
+
+
+ Uniqueness of scopes
+
+ Note that scopes should be as unique as possible. Compare this to hashing: the fewer collisions
+ there are, the better the concurrency will be. So, if for example, two web sessions pick the same
+ scope, then updates to those sessions will be delivered in the order in which they were sent, and
+ not concurrently. While this doesn't cause erraneous behavior, it defies the purpose of SCOPE.
+
+
+ Also note that, if multicast and unicast messages have the same scope, they will be delivered
+ in sequence. So if A multicasts messages to the group with scope 25, and A also unicasts messages
+ to B with scope 25, then A's multicasts and unicasts will be delivered in order at B ! Again,
+ this is correct, but since multicasts and unicasts are unrelated, might slow down things !
+
+
+
+
Out-of-band messages
@@ -1360,6 +1173,11 @@
MiscShunning
+
+
+ Note that in 2.8, shunning has been removed, so the sections below only apply to versions up to 2.7.
+
+
Let's say we have 4 members in a group: {A,B,C,D}. When a member (say D) is expelled from the group, e.g.
because it didn't respond to are-you-alive messages, and later comes back, then it is shunned. Shunning
causes a member to leave the group and re-join, if this is enabled on the Channel. To enable automatic
@@ -1385,9 +1203,62 @@
will shun everybody else (a real shun fest :-)). This is clearly not desirable, so in this case shunning
should be turned off:
- <FD timeout="2000" max_tries="3" shun="false"/> ... <pbcast.GMS join_timeout="3000" shun="false"/>
+ <FD timeout="2000" max_tries="3" shun="false"/>
+ ...
+ <pbcast.GMS join_timeout="3000" shun="false"/>
+
+ Using a custom socket factory
+
+ JGroups creates all of its sockets through a SocketFactory, which is located in the transport (TP) or
+ TP.ProtocolAdapter (in a shared transport). The factory has methods to create sockets (Socket,
+ ServerSocket, DatagramSocket and MulticastSocket)
+
+
+ Currently, SocketFactory does not support creation of NIO sockets / channels.
+
+ ,
+ closen sockets and list all open sockets. Every socket creation method has a service name, which could
+ be for example "jgroups.fd_sock.srv_sock". The service name is used to look up a port (e.g. in a config
+ file) and create the correct socket.
+
+
+ To provide one's own socket factory, the following has to be done: if we have a non-shared transport,
+ the code below creates a SocketFactory implementation and sets it in the transport:
+
+
+ JChannel ch;
+ MySocketFactory factory; // e.g. extends DefaultSocketFactory
+ ch=new JChannel("config.xml");
+ ch.setSocketFactory(new MySocketFactory());
+ ch.connect("demo");
+
+
+
+ If a shared transport is used, then we have to set 2 socket factories: 1 in the shared transport and
+ one in the TP.ProtocolAdapter:
+
+
+ JChannel c1=new JChannel("config.xml"), c2=new JChannel("config.xml");
+
+ TP transport=c1.getProtocolStack().getTransport();
+ transport.setSocketFactory(new MySocketFactory("transport"));
+
+ c1.setSocketFactory(new MySocketFactory("first-cluster"));
+ c2.setSocketFactory(new MySocketFactory("second-cluster"));
+
+ c1.connect("first-cluster");
+ c2.connect("second-cluster");
+
+
+
+ First, we grab one of the channels to fetch the transport and set a SocketFactory in it. Then we
+ set one SocketFactory per channel that resides on the shared transport. When JChannel.connect() is
+ called, the SocketFactory will be set in TP.ProtocolAdapter.
+
+
+
@@ -1502,7 +1373,8 @@
private static void handleView(JChannel ch, View new_view) {
if(new_view instanceof MergeView) {
ViewHandler handler=new ViewHandler(ch, (MergeView)new_view);
- handler.start(); // requires separate thread as we don't want to block JGroups
+ // requires separate thread as we don't want to block JGroups
+ handler.start();
}
}
@@ -1520,8 +1392,8 @@
View tmp_view=subgroups.firstElement(); // picks the first
Address local_addr=ch.getLocalAddress();
if(!tmp_view.getMembers().contains(local_addr)) {
- System.out.println("I (" + local_addr + ") am not member of the new primary partition (" + tmp_view +
- "), will re-acquire the state");
+ System.out.println("Not member of the new primary partition ("
+ + tmp_view + "), will re-acquire the state");
try {
ch.getState(null, 30000);
}
@@ -1529,8 +1401,8 @@
}
}
else {
- System.out.println("I (" + local_addr + ") am member of the new primary partition (" + tmp_view +
- "), will do nothing");
+ System.out.println("Not member of the new primary partition ("
+ + tmp_view + "), will do nothing");
}
}
}
@@ -1584,7 +1456,7 @@
On view change V:
- If V has >= N members:
- - If not read-write: get state from coordinator and switch to read-write
+ - If not read-write: get state from coord and switch to read-write
- Else: switch to read-only
@@ -1650,4 +1522,319 @@
+
+
+
+ Large clusters
+
+ This section is a collection of best practices and tips and tricks for running large clusters on JGroups.
+ By large clusters, we mean several hundred nodes in a cluster.
+
+
+
+ Reducing chattiness
+
+ When we have a chatty protocol, scaling to a large number of nodes might be a problem: too many messages
+ are sent and - because they are generated in addition to the regular traffic - this can have a
+ negative impact on the cluster. A possible impact is that more of the regular messages are dropped, and
+ have to be retransmitted, which impacts performance. Or heartbeats are dropped, leading to false
+ suspicions. So while the negative effects of chatty protocols may not be seen in small clusters, they
+ will be seen in large clusters !
+
+
+
+ Discovery
+
+ A discovery protocol (e.g. PING, TCPPING, MPING etc) is run at startup, to discover the initial
+ membership, and periodically by the merge protocol, to detect partitioned subclusters.
+
+
+ When we send a multicast discovery request to a large cluster, every node in the cluster might
+ possibly reply with a discovery response sent back to the sender. So, in a cluster of 300 nodes,
+ the discovery requester might be up to 299 discovery responses ! Even worse, because num_ping_requests
+ in Discovery is by default set to 2, so we're sending 2 discovery requests, we might receive up to
+ num_ping_requests * (N-1) discovery responses, even though we might be able to find out the
+ coordinator after a few responses already !
+
+
+ To reduce the large number of responses, we can set a max_rank property: the value defines which
+ members are going to send a discovery response. The rank is the index of a member in a cluster: in
+ {A,B,C,D,E}, A's index is 1, B's index is 2 and so on. A max_rank of 3 would trigger discovery
+ responses from only A, B and C, but not from D or E.
+
+
+ We highly recommend setting max_rank in large clusters.
+
+
+ This functionality was implemented in
+ https://jira.jboss.org/browse/JGRP-1181.
+
+
+
+ Failure detection protocols
+
+ Failure detection protocols determine when a member is unresponsive, and subsequently
+ suspect it. Usually (FD, FD_ALL), messages (heartbeats) are used to determine
+ the health of a member, but we can also use TCP connections (FD_SOCK) to connect to a member P, and
+ suspect P when the connection is closed.
+
+
+ Heartbeating requires messages to be sent around, and we need to be careful to limit the number of
+ messages sent by a failure detection protocol (1) to detect crashed members and (2) when a member
+ has been suspected. The following sections discuss how to configure FD_ALL and FD_SOCK, the most
+ commonly used failure detection protocols, for use in large clusters.
+
+
+
+ FD_SOCK
+
+
+
+ FD_ALL
+
+
+
+
+
+
+
+ Bridging between remote clusters
+
+ In 2.12, the RELAY protocol was added to JGroups (for the properties see RELAY).
+ It allows for bridging of remote clusters. For example, if we have a cluster in New York (NYC) and another
+ one in San Francisco (SFO), then RELAY allows us to bridge NYC and SFO, so that multicast messages sent in
+ NYC will be forwarded to SFO and vice versa.
+
+
+ The NYC and SFO clusters could for example use IP multicasting (UDP as transport), and the bridge could use
+ TCP as transport. The SFO and NYC clusters don't even need to use the same cluster name.
+
+
+ shows how the two clusters are bridged.
+
+
+
+
+
+ The cluster on the left side with nodes A (the coordinator), B and C is called "NYC" and use IP
+ multicasting (UDP as transport). The cluster on the right side ("SFO") has nodes D (coordinator), E and F.
+
+
+ The bridge between the local clusters NYC and SFO is essentially another cluster with the coordinators
+ (A and D) of the local clusters as members. The bridge typically uses TCP as transport, but any of the
+ supported JGroups transports could be used (including UDP, if supported across a WAN, for instance).
+
+
+ Only a coordinator relays traffic between the local and remote cluster. When A crashes or leaves, then the
+ next-in-line (B) takes over and starts relaying.
+
+
+ Relaying is done via the RELAY protocol added to the top of the stack. The bridge is configured with
+ the bridge_props property, e.g. bridge_props="/home/bela/tcp.xml". This creates a JChannel inside RELAY.
+
+
+ Note that property "site" must be set in both subclusters. In the example above, we could set site="nyc"
+ for the NYC subcluster and site="sfo" for the SFO ubcluster.
+
+
+ The design is described in detail in JGroups/doc/design/RELAY.txt (part of the source distribution). In
+ a nutshell, multicast messages received in a local cluster are wrapped and forwarded to the remote cluster
+ by a relay (= the coordinator of a local cluster). When a remote cluster receives such a message, it is
+ unwrapped and put onto the local cluster.
+
+
+ JGroups uses subclasses of UUID (PayloadUUID) to ship the site name with an address. When we see an address
+ with site="nyc" on the SFO side, then RELAY will forward the message to the SFO subcluster, and vice versa.
+ When C multicasts a message in the NYC cluster, A will forward it to D, which will re-broadcast the message on
+ its local cluster, with the sender being D. This means that the sender of the local broadcast will appear
+ as D (so all retransmit requests got to D), but the original sender C is preserved in the header.
+ At the RELAY protocol, the sender will be replaced with the original sender (C) having site="nyc".
+ When node F wants to reply to the sender of the multicast, the destination
+ of the message will be C, which is intercepted by the RELAY protocol and forwarded to the current
+ relay (D). D then picks the correct destination (C) and sends the message to the remote cluster, where
+ A makes sure C (the original sender) receives it.
+
+
+ An important design goal of RELAY is to be able to have completely autonomous clusters, so NYC doesn't for
+ example have to block waiting for credits from SFO, or a node in the SFO cluster doesn't have to ask a node
+ in NYC for retransmission of a missing message.
+
+
+ Views
+
+ RELAY presents a global view to the application, e.g. a view received by
+ nodes could be {D,E,F,A,B,C}. This view is the same on all nodes, and a global view is generated by
+ taking the two local views, e.g. A|5 {A,B,C} and D|2 {D,E,F}, comparing the coordinators' addresses
+ (the UUIDs for A and D) and concatenating the views into a list. So if D's UUID is greater than
+ A's UUID, we first add D's members into the global view ({D,E,F}), and then A's members.
+
+
+ Therefore, we'll always see all of A's members, followed by all of D's members, or the other way round.
+
+
+ To see which nodes are local and which ones remote, we can iterate through the addresses (PayloadUUID)
+ and use the site (PayloadUUID.getPayload()) name to for example differentiate between "nyc" and "sfo".
+
+
+
+ Configuration
+
+ To setup a relay, we need essentially 3 XML configuration files: 2 to configure the local clusters and
+ 1 for the bridge.
+
+
+ To configure the first local cluster, we can copy udp.xml from the JGroups distribution and add RELAY on top
+ of it: <RELAY bridge_props="/home/bela/tcp.xml" />. Let's say we call this config relay.xml.
+
+
+ The second local cluster can be configured by copying relay.xml to relay2.xml. Then change the
+ mcast_addr and/or mcast_port, so we actually have 2 different cluster in case we run instances of
+ both clusters in the same network. Of course, if the nodes of one cluster are run in a different
+ network from the nodes of the other cluster, and they cannot talk to each other, then we can simply
+ use the same configuration.
+
+
+ The 'site' property needs to be configured in relay.xml and relay2.xml, and it has to be different. For
+ example, relay.xml could use site="nyc" and relay2.xml could use site="sfo".
+
+
+ The bridge is configured by taking the stock tcp.xml and making sure both local clusters can see each
+ other through TCP.
+
+
+
+
+
+
+ Daisychaining
+
+ Daisychaining refers to a way of disseminating messages sent to the entire cluster.
+
+
+ The idea behind it is that it is inefficient to broadcast a message in clusters where IP multicasting is
+ not available. For example, if we only have TCP available (as is the case in most clouds today), then we
+ have to send a broadcast (or group) message N-1 times. If we want to broadcast M to a cluster of 10,
+ we send the same message 9 times.
+
+
+ Example: if we have {A,B,C,D,E,F}, and A broadcasts M, then it sends it to B, then to C, then to D etc.
+ If we have a 1 GB switch, and M is 1GB, then sending a broadcast to 9 members takes 9 seconds, even if we
+ parallelize the sending of M. This is due to the fact that the link to the switch only sustains 1GB / sec.
+ (Note that I'm conveniently ignoring the fact that the switch will start dropping packets if it is
+ overloaded, causing TCP to retransmit, slowing things down)...
+
+
+ Let's introduce the concept of a round. A round is the time it takes to send or receive a message.
+ In the above example, a round takes 1 second if we send 1 GB messages.
+ In the existing N-1 approach, it takes X * (N-1) rounds to send X messages to a cluster of N nodes.
+ So to broadcast 10 messages a the cluster of 10, it takes 90 rounds.
+
+
+ Enter DAISYCHAIN.
+
+
+
+ The idea is that, instead of sending a message to N-1 members, we only send it to our neighbor, which
+ forwards it to its neighbor, and so on. For example, in {A,B,C,D,E}, D would broadcast a message by
+ forwarding it to E, E forwards it to A, A to B, B to C and C to D. We use a time-to-live field,
+ which gets decremented on every forward, and a message gets discarded when the time-to-live is 0.
+
+
+ The advantage is that, instead of taxing the link between a member and the switch to send N-1 messages,
+ we distribute the traffic more evenly across the links between the nodes and the switch.
+ Let's take a look at an example, where A broadcasts messages m1 and m2 in
+ cluster {A,B,C,D}, '-->' means sending:
+
+
+
+ Traditional N-1 approach
+
+
+ Round 1: A(m1) --> B
+ Round 2: A(m1) --> C
+ Round 3: A(m1) --> D
+ Round 4: A(m2) --> B
+ Round 5: A(m2) --> C
+ Round 6: A(m2) --> D
+
+
+ It takes 6 rounds to broadcast m1 and m2 to the cluster.
+
+
+
+
+ Daisychaining approach
+
+
+ Round 1: A(m1) --> B
+ Round 2: A(m2) --> B || B(m1) --> C
+ Round 3: B(m2) --> C || C(m1) --> D
+ Round 4: C(m2) --> D
+
+ In round 1, A send m1 to B.
+ In round 2, A sends m2 to B, but B also forwards m1 (received in round 1) to C.
+ In round 3, A is done. B forwards m2 to C and C forwards m1 to D (in parallel, denoted by '||').
+ In round 4, C forwards m2 to D.
+
+
+
+
+ Switch usage
+
+ Let's take a look at this in terms of switch usage: in the N-1 approach, A can only send 125MB/sec,
+ no matter how many members there are in the cluster, so it is constrained by the link capacity to the
+ switch. (Note that A can also receive 125MB/sec in parallel with today's full duplex links).
+
+
+ So the link between A and the switch gets hot.
+
+
+ In the daisychaining approach, link usage is more even: if we look for example at round 2, A sending
+ to B and B sending to C uses 2 different links, so there are no constraints regarding capacity of a
+ link. The same goes for B sending to C and C sending to D.
+
+
+ In terms of rounds, the daisy chaining approach uses X + (N-2) rounds, so for a cluster size of 10 and
+ broadcasting 10 messages, it requires only 18 rounds, compared to 90 for the N-1 approach !
+
+
+
+
+ Performance
+
+ To measure performance of DAISYCHAIN, a performance test (test.Perf) was run, with 4 nodes connected
+ to a 1 GB switch; and every node sending 1 million 8K messages, for a total of 32GB received by
+ every node. The config used was tcp.xml.
+
+
+ The N-1 approach yielded a throughput of 73 MB/node/sec, and the daisy chaining approach 107MB/node/sec !
+
+
+
+
+
+ Configuration
+
+ DAISYCHAIN can be placed directly on top of the transport, regardless of whether it is UDP or TCP, e.g.
+
+ <TCP .../>
+ <DAISYCHAIN .../>
+ <TCPPING .../>
+
+
+
+
+
+
+
+ Ergonomics
+
+ Ergonomics is similar to the dynamic setting of optimal values for the JVM, e.g. garbage collection,
+ memory sizes etc. In JGroups, ergonomics means that we try to dynamically determine and set optimal
+ values for protocol properties. Examples are thread pool size, flow control credits, heartbeat
+ frequency and so on.
+
+
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/manual/en/modules/api.xml libjgroups-java-2.12.2.Final/doc/manual/en/modules/api.xml
--- libjgroups-java-2.7.0.GA/doc/manual/en/modules/api.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/manual/en/modules/api.xml 2011-10-18 11:22:35.000000000 +0000
@@ -20,7 +20,7 @@
The org.jgroups.util.Util class contains a
collection of useful functionality which cannot be assigned to any
- particular other package.
+ particular package.
objectToByteBuffer(), objectFromByteBuffer()
@@ -30,28 +30,7 @@
externalizable). The byte array is then returned. This method is often
used to serialize objects into the byte buffer of a message. The second
method returns a reconstructed object from a buffer. Both methods throw
- an exception if the object cannot be serialized or unseriali
-
-
-
- printMessage()
-
- Prints the message given as argument in readable format. Returns a
- string.
-
-
-
- activeThreads()
-
- Returns a strings containing a pretty-printed list of currently
- running threads.
-
-
-
- printMembers()
-
- Given a list of member addresses, pretty-prints the members and
- returns a string.
+ an exception if the object cannot be serialized or unserialized.
@@ -62,32 +41,6 @@
therefore they are listed first.
- Transport
-
- Interface Transport looks as
- follows:
-
-
- public interface Transport {
- public void send(Message msg) throws Exception;
- public Object receive(long timeout) throws Exception;
- }
-
-
- It defines a very small subset of the functionality of a channel,
- essentially only the methods for sending and receiving messages. There
- are a number of classes that implement Transport
- , among others Channel . Many building blocks
- (see ) require nothing else than
- a bare-bone facility to send and receive messages; therefore the
- Transport interface was created. It increases the
- genericness and portability of building blocks: being so simple, the
- Transport interface can easily be ported to a
- different toolkit, without requiring any modifications to building
- blocks.
-
-
- MessageListenerContrary to the pull-style of channels, some building blocks (e.g.
@@ -96,15 +49,15 @@
the entity to be notified of message reception needs to provide a
callback to be invoked whenever a message has been received. The
MessageListener interface below provides a method
- to do so:
-
-
- public interface MessageListener {
- public void receive(Message msg);
- byte[] getState();
- void setState(byte[] state);
- }
-
+ to do so:
+
+ public interface MessageListener {
+ public void receive(Message msg);
+ byte[] getState();
+ void setState(byte[] state);
+ }
+
+
Method receive() will be called when a
message is received. The getState() and
@@ -116,47 +69,44 @@
ExtendedMessageListener
- JGroups release 2.3 introduces ExtendedMessageListener enabling
- partial state transfer (refer to
- ) while release 2.4 further expands ExtendedMessageListener with
- streaming state transfer callbacks:
+
+ JGroups release 2.3 introduced ExtendedMessageListener enabling
+ partial state transfer (refer to
+ ) while release 2.4 further expands ExtendedMessageListener with
+ streaming state transfer callbacks:
- public interface ExtendedMessageListener extends MessageListener {
- byte[] getState(String state_id);
- void setState(String state_id, byte[] state);
+ public interface ExtendedMessageListener extends MessageListener {
+ byte[] getState(String state_id);
+ void setState(String state_id, byte[] state);
- /*** since JGroups 2.4 *****/
- void getState(OutputStream ostream);
- void getState(String state_id, OutputStream ostream);
- void setState(InputStream istream);
- void setState(String state_id, InputStream istream);
- }
-
+ /*** since JGroups 2.4 *****/
+ void getState(OutputStream ostream);
+ void getState(String state_id, OutputStream ostream);
+ void setState(InputStream istream);
+ void setState(String state_id, InputStream istream);
+ }
+
+
- Method receive() will be called when a
- message is received. The getState() and
- setState() methods are used to fetch and set
- the group state (e.g. when joining). Refer to for a discussion of state transfer.MembershipListener
- The MembershipListener interface is similar
- to the MessageListener interface above: every
- time a new view, a suspicion message, or a block event is received, the
- corresponding method of the class implementing
- MembershipListener will be called.
+
+ The MembershipListener interface is similar to the MessageListener
+ interface above: every time a new view, a suspicion message, or a block event is received, the corresponding
+ method of the class implementing MembershipListener will be called.
-
- public interface MembershipListener {
- public void viewAccepted(View new_view);
- public void suspect(Object suspected_mbr);
- public void block();
- }
-
+
+ public interface MembershipListener {
+ public void viewAccepted(View new_view);
+ public void suspect(Object suspected_mbr);
+ public void block();
+ }
+
+ Oftentimes the only method containing any functionality will be
viewAccepted() which notifies the receiver that
@@ -178,33 +128,48 @@
- Therefore, block() can be used to send pending messages or complete some other work. However,
- sending of messages should be done on a different thread, e.g. the current thread blocks on a mutex,
- starts a different thread which notifies the mutex once the work has been done.
+ Therefore, block() can be used to send pending messages or complete some other work.
- Note that block() should take a small amount of time to complete, otherwise the entire FLUSH protocol
- is blocked.
+ Note that block() should be brief, or else the entire FLUSH protocol is blocked.
+
+ Sending messages in callbacks
+
+ Note that anything that could block should not be done in a callback.
+ This includes sending of messages;
+ if we have FLUSH on the stack, and send a message in a viewAccepted() callback, then the following
+ happens: the FLUSH protocol blocks all (multicast) messages before installing a view, then installs
+ the view, then unblocks. However, because installation of the view triggers the viewAccepted() callback,
+ sending of messages inside of viewAccepted() will block. This in turn blocks the viewAccepted() thread,
+ so the flush will never return !
+
+
+ If we need to send a message in a callback, the sending should be done on a separate thread, or a timer
+ task should be submitted to the timer.
+
+ ExtendedMembershipListener
- The ExtendedMembershipListener interface extends
- MembershipListener:
+
+ The ExtendedMembershipListener interface extends
+ MembershipListener:
public interface ExtendedMembershipListener extends MembershipListener {
public void unblock();
}
+
The unblock() method is called
- to notify the member that the flush protocol has completed and the member can resume
+ to notify the member that the FLUSH protocol has completed and the member can resume
sending messages. If the member did not stop sending messages on block(), FLUSH simply blocked them and
will resume, so no action is required from a member. Implementation of the unblock() callback is optional.
@@ -215,16 +180,17 @@
ChannelListener
-
-
- public interface ChannelListener {
- void channelConnected(Channel channel);
- void channelDisconnected(Channel channel);
- void channelClosed(Channel channel);
- void channelShunned();
- void channelReconnected(Address addr);
- }
-
+
+
+ public interface ChannelListener {
+ void channelConnected(Channel channel);
+ void channelDisconnected(Channel channel);
+ void channelClosed(Channel channel);
+ void channelShunned(); // deprecated in 2.8
+ void channelReconnected(Address addr); // deprecated in 2.8
+ }
+
+ A class implementing ChannelListener can
use the Channel.setChannelListener() method to
@@ -235,40 +201,51 @@
Receiver
-
+
- public interface Receiver extends MessageListener, MembershipListener {
- }
-
+ public interface Receiver extends MessageListener, MembershipListener {
+ }
+
+
- A Receiver can be used to receive all relevant messages and view
+ A Receiver can be used to receive messages and view
changes in push-style; rather than having to pull these events from a
channel, they will be dispatched to the receiver as soon as they have
been received. This saves one thread (application thread, pulling
messages from a channel, or the PullPushAdapter thread
+
+ Note that JChannel.receive() has been deprecated and will be removed in 3.0. The
+ preferred way of receiving messages is now via a Receiver callback (push style).
+ ExtendedReceiver
-
+
- public interface ExtendedReceiver extends ExtendedMessageListener, MembershipListener {
- }
-
+ public interface ExtendedReceiver extends ExtendedMessageListener, MembershipListener {
+ }
+
+
- This is a receiver who will be able to handle partial state
- transfer
+ This is a receiver who will be able to handle partial state transfer
+
+ ReceiverAdapter and ExtendedReceiverAdapter
+
+ These classes implement Receiver and ExtendedReceiver. When implementing a callback, one can simply
+ extend ReceiverAdapter and overwrite receive() in order to not having to implement all callbacks of
+ the interface.
+
+
+
- Merging of Extended interfaces with their super
- interfaces
+ Merging of Extended interfaces with their super interfaces
- The Extended- interfaces (ExtendedMessageListener,
- ExtendedReceiver) will be merged with their parents in the 3.0 release
- of JGroups. The reason is that this will create an API backwards
- incompatibility, which we didn't want to introduce in the 2.x
- series.
+ The Extended- interfaces (ExtendedMessageListener, ExtendedReceiver) will be merged with their parents in
+ the 3.0 release of JGroups. The reason is that this will create an API backwards
+ incompatibility, which we didn't want to introduce in the 2.x series.
@@ -279,18 +256,20 @@
member. The interface for such an address is Address, which requires
concrete implementations to provide methods for comparison and sorting of
addresses, and for determination whether the address is a multicast
- address. JGroups addresses have to implement the following
- interface:
+ address. JGroups addresses have to implement the following interface:
- public interface Address extends Externalizable, Comparable, Cloneable {
- boolean isMulticastAddress();
- int compareTo(Object o) throws ClassCastException;
- boolean equals(Object obj);
- int hashCode();
- String toString();
- }
-
+ public interface Address extends Externalizable, Comparable, Cloneable {
+ boolean isMulticastAddress();
+ int size();
+ }
+
+
+
+
+ Please never use implementations of Address directly; Address should always be used
+ as an opaque identifier of a cluster node !
+ Actual implementations of addresses are often generated by the
bottommost protocol layer (e.g. UDP or TCP). This allows for all possible
@@ -299,19 +278,23 @@
In JChannel, it is the IP address of the host on which the stack is
running and the port on which the stack is receiving incoming messages; it
is represented by the concrete class
- org.jgroups.stack.IpAddress . Instances of this
+ org.jgroups.stack.IpAddress. Instances of this
class are only used within the JChannel protocol
stack; users of a channel see addresses (of any kind) only as
- Addresses . Since an address uniquely identifies a channel, and
+ Addresses. Since an address uniquely identifies a channel, and
therefore a group member, it can be used to send messages to that group
member, e.g. in Messages (see next section).
+
+ In 2.8, the default implementation of Address was changed from IpAddress to
+ org.jgroups.util.UUID.
+ MessageData is sent between members in the form of messages (
- Message ). A message can be sent by a member to a
+ org.jgroups.Message ). A message can be sent by a member to a
single member , or to all
members of the group of which the channel is an endpoint. The
structure of a message is shown in .
@@ -396,14 +379,16 @@
or it can be null , which means that the message will
be sent to all members of the group. A typical multicast message, sending
string "Hello" to all members would look like
- this:
+ this:
-
- Message msg=new Message(null, null, "Hello".getBytes());
- channel.send(msg);
-
+
+ Message msg=new Message(null, null, "Hello");
+ channel.send(msg);
+
+
+
View
@@ -421,19 +406,19 @@
coordinator easily and without having to contact other members.
The code below shows how to send a (unicast) message to the first
- member of a view (error checking code omitted):
+ member of a view (error checking code omitted):
- View myview=channel.getView();
- Address first=myview.getMembers().first();
- Message msg=new Message(first, null, "Hello world");
- channel.send(msg);
-
+ View view=channel.getView();
+ Address first=view.getMembers().first();
+ Message msg=new Message(first, null, "Hello world");
+ channel.send(msg);
+
+
Whenever an application is notified that a new view has been
installed (e.g. by
- MembershipListener.viewAccepted() or
- Channel.receive() ), the view is already set in
+ Receiver.viewAccepted(), the view is already set in
the channel. For example, calling
Channel.getView() in a
viewAccepted() callback would return the same
@@ -446,7 +431,7 @@
The ViewId is used to uniquely number views. It consists of the
address of the view creator and a sequence number. ViewIds can be
compared for equality and put in a hashtable as they implement equals()
- and hashCode() methods.
+ and hashCode() methods.Note that the latter 2 methods only take the ID into account.
@@ -465,16 +450,9 @@
-
- Membership
-
- This class can be used for keeping rack of members instead of a
- Vector class. It adds several functions, such as duplicate elimination,
- merging with other Membership instances and sorting.
-
- Channel
+ JChannelIn order to join a group and send messages, a process has to create
a channel. A channel is like a socket. When a client connects to a
@@ -515,82 +493,46 @@
Creating a channel
- A channel can be created in two ways: an instance of a subclass of
- Channel is created directly using its public
- constructor (e.g. new JChannel() ), or a
- channel factory is created, which -- upon request -- creates instances
- of channels. We will only look at the first method of creating channel:
- by direct instantiation. Note that instantiation may differ between the
- various channel implementations. As example we will look at
- JChannel .
+
+ A channel can be created in two ways: an instance of a subclass of
+ Channel is created directly using its public
+ constructor (e.g. new JChannel() ), or a
+ channel factory is created, which -- upon request -- creates instances
+ of channels. We will only look at the first method of creating channel:
+ by direct instantiation.
+
- The public constructor of JChannel looks as
- follows:
+
+ The public constructor of JChannel looks as follows:
+
- public JChannel(Object properties) throws ChannelException {}
-
-
- It creates an instance of JChannel . The
- properties argument defines the composition of
- the protocol stack (number and type of layers, parameters for each
- layer, and their order). For JChannel, this has to be a String.
- An example of a channel creation is:
-
-
- String props="UDP(mcast_addr=228.1.2.3;mcast_port=45566;ip_ttl=32):" +
- "PING(timeout=3000;num_initial_members=6):" +
- "FD(timeout=5000):" +
- "VERIFY_SUSPECT(timeout=1500):" +
- "pbcast.STABLE(desired_avg_gossip=10000):" +
- "pbcast.NAKACK(gc_lag=10;retransmit_timeout=3000):" +
- "UNICAST(timeout=5000;min_wait_time=2000):" +
- "FRAG:" +
- "pbcast.GMS(initial_mbrs_timeout=4000;join_timeout=5000;" +
- "shun=false;print_local_addr=false)";
-
- JChannel channel;
- try {
- channel=new JChannel(props);
- }
- catch(Exception ex) {
- // channel creation failed
- }
-
+ public JChannel(String props) throws ChannelException {}
+
- The argument is a colon-delimited string of protocols, specified
- from bottom to top (left to right). The example properties argument will
- be used to create a protocol stack that uses IP Multicast (UDP) as
- bottom protocol, the PING protocol to locate the initial members, FD for
- failure detection, VERIFY_SUSPECT for double-checking of suspected
- members, STABLE for garbage collection of messages received by all
- members, NAKACK for lossless delivery of multicast messages, UNICAST for
- lossless delivery of unicast messages and GMS for group membership
- (handling of join or leave requests).
+ It creates an instance of JChannel . The
+ props argument points to an XML file containing the configuration
+ of the protocol stack to be used. This can be a String, but there are also other constructors which
+ take for example a DOM element or a URL (more on this later).
+
- If the properties argument is null, the default properties will be
+ If the props argument is null, the default properties will be
used. An exception will be thrown if the channel cannot be created.
Possible causes include protocols that were specified in the property
argument, but were not found, or wrong parameters to protocols.
-
- Using XML to define a protocol stack
- In version 2.0 of JGroups an XML-based scheme to define protocol
- stacks was introduced. Instead of specifying a string containing the
- protocol spec, an URL pointing to a valid protocol stack definition
- can be given. For example, the Draw demo can be launched as
- follows:
+ For example, the Draw demo can be launched as follows:
- java org.javagroups.demos.Draw -props file:/home/bela/vsync.xml
-
+ java org.javagroups.demos.Draw -props file:/home/bela/udp.xml
+
or
- java org.javagroups.demos.Draw -props http://www.jgroups.org/udp.xml
-
+ java org.javagroups.demos.Draw -props http://www.jgroups.org/udp.xml
+
In the latter case, an application downloads its protocol stack
@@ -629,7 +571,7 @@
<MERGE2 max_interval="30000"
min_interval="10000"/>
<FD_SOCK/>
- <FD timeout="10000" max_tries="5" shun="true"/>
+ <FD timeout="10000" max_tries="5" />
<VERIFY_SUSPECT timeout="1500" />
<BARRIER />
<pbcast.NAKACK
@@ -641,7 +583,6 @@
max_bytes="400000"/>
<VIEW_SYNC avg_send_interval="60000" />
<pbcast.GMS print_local_addr="true" join_timeout="3000"
- shun="false"
view_bundling="true"/>
<FC max_credits="20000000"
min_threshold="0.10"/>
@@ -665,8 +606,8 @@
Each element has to be the name of a Java class
that resides in the org.jgroups.stack.protocols
package. Note that only the base name has to be given, not the fully
- specified class name ( UDP instead of
- org.jgroups.stack.protocols.UDP ). If the
+ specified class name (UDP instead of
+ org.jgroups.stack.protocols.UDP). If the
protocol class is not found, JGroups assumes that the name given is a
fully qualified classname and will therefore try to instantiate that
class. If this does not work an exception is thrown. This allows for
@@ -685,7 +626,76 @@
Note that all members in a group have to have the same
protocol stack.
-
+
+
+ Programmatic creation
+
+ Usually, channels are created by passing the name of an XML configuration file to the JChannel() constructor.
+ On top of this declarative configuration, JGroups provides an API to create a channel programmatically.
+ The way to do this is to first create a JChannel, then an instance of ProtocolStack, then add all desired
+ protocols to the stack and finally calling init() on the stack to set it up. The rest, e.g. calling
+ JChannel.connect() is the same as with the declarative creation.
+
+
+ An example of how to programmatically create a channel is shown below (copied from ProgrammaticChat):
+
+ JChannel ch=new JChannel(false); // 1
+ ProtocolStack stack=new ProtocolStack(); // 2
+ ch.setProtocolStack(stack); // 3
+ stack.addProtocol(new UDP().setValue("bind_addr", InetAddress.getByName("192.168.1.5")))
+ .addProtocol(new PING())
+ .addProtocol(new MERGE2())
+ .addProtocol(new FD_SOCK())
+ .addProtocol(new FD_ALL().setValue("timeout", 12000).setValue("interval", 3000))
+ .addProtocol(new VERIFY_SUSPECT())
+ .addProtocol(new BARRIER())
+ .addProtocol(new NAKACK())
+ .addProtocol(new UNICAST2())
+ .addProtocol(new STABLE())
+ .addProtocol(new GMS())
+ .addProtocol(new UFC())
+ .addProtocol(new MFC())
+ .addProtocol(new FRAG2()); // 4
+ stack.init(); // 5
+
+ ch.setReceiver(new ReceiverAdapter() {
+ public void viewAccepted(View new_view) {
+ System.out.println("view: " + new_view);
+ }
+
+ public void receive(Message msg) {
+ System.out.println(msg.getObject() + " [" + msg.getSrc() + "]");
+ }
+ });
+
+ ch.connect("ChatCluster");
+
+ for(;;) {
+ String line=Util.readStringFromStdin(": ");
+ ch.send(null, null, line);
+ }
+
+
+
+ First a JChannel is created. The 'false' argument tells the channel not to create a ProtocolStack. This
+ is needed because we will create one ourselves later (2) and set it in the channel (3).
+
+
+ Next, all protocols are added to the stack. Note that the order is from bottom (transport protocol) to
+ top. So UDP as transport is added first, then PING and so on, until FRAG2, which is the top protocol.
+ Every protocol can be configured via setters, but there is also a generic setValue(String attr_name,
+ Object value), which can be used to configure protocols as well, as shown in the example.
+
+
+ Once the stack is configured, we call ProtocolStack.init() to link all protocols correctly and to call
+ init() in every protocol instance. After this, the channel is ready to be used and all subsequent
+ actions (e.g. connect()) can be executed. When the init() method returns, we have essentially the
+ equivalent of new JChannel(config_file).
+
+
+
+
+
@@ -695,12 +705,12 @@
Setting options
- A number of options can be set in a channel. To do so, the
- following method is used:
-
-
+
+ A number of options can be set in a channel. To do so, the following method is used:
+
public void setOpt(int option, Object value);
-
+
+ Arguments are the options number and a value. The following
options are currently recognized:
@@ -710,9 +720,7 @@
Channel.BLOCK
- The argument is a boolean object. If true, block messages
- will be received. If this option is set to true, views will also
- be set to true. Default is false.
+ The argument is a boolean object. If true, block messages will be received.
@@ -734,7 +742,8 @@
When set to true, a shunned channel will leave the group and
- then try to automatically re-join. Default is false
+ then try to automatically re-join. Default is false. Note that in 2.8, shunning has been removed, therefore
+ this option has been deprecated.
@@ -744,20 +753,107 @@
When set to true a shunned channel, after reconnection, will
attempt to fetch the state from the coordinator. This requires
- AUTO_RECONNECT to be true as well. Default is false.
+ AUTO_RECONNECT to be true as well. Default is false. Note that in 2.8, shunning has been removed, therefore
+ this option has been deprecated.
The equivalent method to get options is
- getOpt() :
+ getOpt():
- public Object getOpt(int option);
-
+ public Object getOpt(int option);
+
+
Given an option, the current value of the option is
returned.
+
+
+ Deprecating options in 3.0
+
+
+ Most of the options (except LOCAL) have been deprecated in 2.6.x and will be removed in 3.0.
+
+
+
+
+
+
+ Giving the channel a logical name
+
+ A channel can be given a logical name which is then used instead of the channel's address. A logical name
+ might show the function of a channel, e.g. "HostA-HTTP-Cluster", which is more legible than a UUID
+ 3c7e52ea-4087-1859-e0a9-77a0d2f69f29.
+
+
+ For example, when we have 3 channels, using logical names we might see a view "{A,B,C}", which is nicer than
+ "{56f3f99e-2fc0-8282-9eb0-866f542ae437, ee0be4af-0b45-8ed6-3f6e-92548bfa5cde, 9241a071-10ce-a931-f675-ff2e3240e1ad} !"
+
+
+ If no logical name is set, JGroups generates one, using the hostname and a random number, e.g. linux-3442.
+ If this is not desired and the UUIDs should be shown, use system property -Djgroups.print_uuids=true.
+
+
+ The logical name can be set using:
+
+ public void setName(String logical_name);
+
+
+
+ This should be done before connecting a channel. Note that the logical name stays with a channel until
+ the channel is destroyed, whereas a UUID is created on each connection.
+
+
+
+ When JGroups starts, it prints the logical name and the associated physical address(es):
+
+ -------------------------------------------------------------------
+ GMS: address=mac-53465, cluster=DrawGroupDemo, physical address=192.168.1.3:49932
+ -------------------------------------------------------------------
+ ** View=[mac-53465|0] [mac-53465]
+
+
+ The logical name is mac-53465 and the physical address is 192.168.1.3:49932. The UUID is not shown here.
+
+
+
+
+ Generating custom addresses
+
+ Since 2.12 address generation is pluggable. This means that an application can determine what kind of
+ addresses it uses. The default address type is UUID, and since some protocols use UUID, it is recommended
+ to provide custom classes as subclasses of UUID.
+
+
+ This can be used to for example pass additional data around with an address, for example information about
+ the location of the node to which the address is assigned. Note that methods equals(), hashCode() and
+ compare() of the UUID super class should not be changed.
+
+
+ To use custom addresses, the following things have to be done:
+
+ Write an implementation of org.jgroups.stack.AddressGenerator
+ For any class CustomAddress, it will need to get registered with the ClassConfigurator
+ in order to marshal it correctly:
+
+ class CustomAddress extends UUID {
+ static {
+ ClassConfigurator.add((short)8900, CustomAddress.class);
+ }
+ }
+
+ Note that the ID should be chosen such that it doesn't collide with any IDs defined in
+ jg-magic-map.xml.
+
+ Set the address generator in JChannel: setAddressGenerator(AddressGenerator). This
+ has to be done before the channel is connected
+
+
+
+ An example of a subclass is org.jgroups.util.PayloadUUID.
+
@@ -768,8 +864,8 @@
to be joined:
- public void connect(String clustername) throws ChannelClosed;
-
+ public void connect(String clustername) throws ChannelClosed;
+
The cluster name is a string, naming the cluster to be joined. All
channels that are connected to the same name form a cluster.
@@ -782,7 +878,7 @@
The method returns as soon as the group has been joined
successfully. If the channel is in the closed state (see ), an exception will be thrown. If there
- are no other members, i.e. no other client has connected to a group with
+ are no other members, i.e. no other member has connected to a group with
this name, then a new group is created and the member joined. The first
member of a group becomes its coordinator . A
coordinator is in charge of multicasting new views whenever the
@@ -807,7 +903,9 @@
- public void connect(string cluster_name, address target, string state_id, long timeout) throws channelexception;
+ public void connect(string cluster_name, address target,
+ string state_id, long timeout)
+ throws ChannelException;
@@ -823,7 +921,9 @@
Getting the local address and the group nameMethod getLocalAddress() returns the
- local address of the channel. In the case of
+ local address of the channel
+ Since 2.8 the method is getAddress()
+ . In the case of
JChannel , the local address is generated by the
bottom-most layer of the protocol stack when the stack is connected to.
That means that -- depending on the channel implementation -- the local
@@ -831,15 +931,15 @@
state.
- public Address getLocalAddress();
-
+ public Address getLocalAddress(); // use getAddress() with 2.8.0+
+
- Method getClusterlName() returns the name
+ Method getClusterName() returns the name
of the cluster in which the channel is a member:
- public String getClusterName();
-
+ public String getClusterName();
+
Again, the result is undefined if the channel is in the
unconnected or closed state.
@@ -852,8 +952,8 @@
channel:
- public View getView();
-
+ public View getView();
+
This method does not retrieve a new view
(message) from the channel, but only returns the current view of the
@@ -874,9 +974,10 @@
send() methods:
- public void send(Message msg) throws ChannelNotConnected, ChannelClosed;
- public void send(Address dst, Address src, Object obj) throws ChannelNotConnected, ChannelClosed;
-
+ public void send(Message msg) throws ChannelNotConnected, ChannelClosed;
+ public void send(Address dst, Address src, Object obj)
+ throws ChannelNotConnected, ChannelClosed;
+
The first send() method has only one
argument, which is the message to be sent. The message's destination
@@ -895,41 +996,41 @@
be thrown upon attempting to send a message.Here's an example of sending a (multicast) message to all members
- of a group:
+ of a group:
- Hashtable data; // any serializable data
- try {
- channel.send(null, null, data);
- }
- catch(Exception ex) {
- // handle errors
- }
-
+ Map data; // any serializable data
+ try {
+ channel.send(null, null, data);
+ }
+ catch(Exception ex) {
+ // handle errors
+ }
+
+ The null value as destination address means that the message will
be sent to all members in the group. The sender's address will be filled
- in by the bottom-most protocol. The payload is a hashtable, which will
+ in by the bottom-most protocol. The payload is a hashmap, which will
be serialized into the message's buffer and unserialized at the
receiver's end. Alternatively, any other means of generating a byte
buffer and setting the message's buffer to it (e.g. using
Message.setBuffer()) would also work.Here's an example of sending a (unicast) message to the first
- member (coordinator) of a group:
+ member (coordinator) of a group:
- Address receiver;
- Message msg;
- Hashtable data;
- try {
- receiver=channel.getView().getMembers().first();
- channel.send(receiver, null, data);
- }
- catch(Exception ex) {
- // handle errors
- }
-
+ Map data;
+ try {
+ Address receiver=channel.getView().getMembers().first();
+ channel.send(receiver, null, data);
+ }
+ catch(Exception ex) {
+ // handle errors
+ }
+
+ It creates a Message with a specific address for the receiver (the
first member of the group). Again, the sender's address can be left null
@@ -943,8 +1044,9 @@
messages, views, suspicions and blocks:
- public Object receive(long timeout) throws ChannelNotConnected, ChannelClosed, Timeout;
-
+ public Object receive(long timeout) throws ChannelNotConnected,
+ ChannelClosed, Timeout;
+
A channel receives messages asynchronously from the network and
stores them in a queue. When receive() is called, the next available
@@ -1083,20 +1185,17 @@
The caller has to check the type of the object returned. This can
be done using the instanceof operator, as
- follows:
-
+ follows:
- Object obj;
- Message msg;
- View v;
- obj=channel.receive(0); // wait forever
- if(obj instanceof Message)
- msg=(Message)obj;
- else if(obj instanceof View)
- v=(View)obj;
- else
- ; // don't handle suspicions or blocks
-
+ Object obj=channel.receive(0); // wait forever
+ if(obj instanceof Message)
+ Message msg=(Message)obj;
+ else if(obj instanceof View)
+ View v=(View)obj;
+ else
+ ; // don't handle suspicions or blocks
+
+ If for example views, suspicions and blocks are disabled, then the
caller is guaranteed to only receive return values of type
@@ -1108,19 +1207,18 @@
exception will be thrown.The example below shows how to retrieve the "Hello world" string
- from a message:
-
+ from a message:
- Message msg; // received above
- String s;
- try {
- s=(String)msg.getObject(); // error if object not Serializable
- // alternative: s=new String(msg.getBuffer());
- }
- catch(Exception ex) {
- // handle errors, e.g. casting error above)
- }
-
+ Message msg; // received above
+ try {
+ String s=(String)msg.getObject(); // error if obj not Serializable
+ // alternative: s=new String(msg.getBuffer());
+ }
+ catch(Exception ex) {
+ // handle errors, e.g. casting error above)
+ }
+
+
The Message.getObject() method retrieves the message's byte
buffer, converts it into a (serializable) object and returns the
@@ -1131,22 +1229,23 @@
Using a Receiver to receive messagesInstead of pulling messages from a channel in an application
- thread, a Receiver can be registered with a channel; all received
- messages, view changes and state transfer requests will invoke callbacks
- on the registered Receiver:
-
-
- JChannel ch=new JChannel();
- ch.setReceiver(new ExtendedReceiverAdapter() {
- public void receive(Message msg) {
- System.out.println("received message " + msg);
- }
- public void viewAccepted(View new_view) {
- System.out.println("received view " + new_view);
- }
- });
- ch.connect("bla");
-
+ thread, a Receiver can be registered with a channel. This is the preferred and recommended way of receiving
+ messages. In 3.0, the receive() method will be removed from JChannel.
+ All received messages, view changes and state transfer requests will invoke callbacks
+ on the registered Receiver:
+
+ JChannel ch=new JChannel();
+ ch.setReceiver(new ExtendedReceiverAdapter() {
+ public void receive(Message msg) {
+ System.out.println("received message " + msg);
+ }
+ public void viewAccepted(View new_view) {
+ System.out.println("received view " + new_view);
+ }
+ });
+ ch.connect("bla");
+
+ The ExtendedReceiverAdapter class
implements all callbacks of ExtendedReceiver with no-ops, in the example
@@ -1211,28 +1310,29 @@
transfer would not be correct.The following code fragment shows how a group member participates
- in state transfers:
-
+ in state transfers:
- channel=new JChannel();
- channel.connect("TestChannel");
- boolean rc=channel.getState(null, 5000);
-
- ...
-
- Object state, copy;
- Object ret=channel.receive(0);
- if(ret instanceof Message)
- ;
- else if(ret instanceof GetStateEvent) {
- copy=copyState(state); // make a copy so that other msgs don't change the state
- channel.returnState(Util.objectToByteBuffer(copy));
- }
- else if(ret instanceof SetStateEvent) {
- SetStateEvent e=(SetStateEvent)ret;
- state=e.getArg();
- }
-
+ channel=new JChannel();
+ channel.connect("TestChannel");
+ boolean rc=channel.getState(null, 5000);
+
+ ...
+
+ Object state, copy;
+ Object ret=channel.receive(0);
+ if(ret instanceof Message)
+ ;
+ else if(ret instanceof GetStateEvent) {
+ // make a copy so that other msgs don't change the state
+ copy=copyState(state);
+ channel.returnState(Util.objectToByteBuffer(copy));
+ }
+ else if(ret instanceof SetStateEvent) {
+ SetStateEvent e=(SetStateEvent)ret;
+ state=e.getArg();
+ }
+
+
A JChannel has to be created whose stack includes the
@@ -1265,32 +1365,33 @@
As an alternative to handling the GetStateEvent and SetStateEvent
events, and calling Channel.returnState(), a Receiver could be used. The
- example above would look like this:
-
+ example above would look like this:
- class MyReceiver extends ReceiverAdapter {
- final Map m=new HashMap();
- public byte[] getState() {
- synchronized(m) { // so nobody else can modify the map while we serialize it
- byte[] state=Util.objectToByteBuffer(m);
- return state;
- }
- }
-
- public void setState(byte[] state) {
- synchronized(m) {
- Map new_m=(Map)Util.objectFromByteBuffer(state);
- m.clear();
- m.addAll(new_m);
- }
- }
- }
-
- channel=new JChannel(); // use default properties (has to include pbcast.STATE_TRANSFER protocol)
- channel.setReceiver(new MyReceiver());
- channel.connect("TestChannel");
- boolean rc=channel.getState(null, 5000);
-
+ class MyReceiver extends ReceiverAdapter {
+ final Map m=new HashMap();
+ public byte[] getState() {
+ // so nobody else can modify the map while we serialize it
+ synchronized(m) {
+ byte[] state=Util.objectToByteBuffer(m);
+ return state;
+ }
+ }
+
+ public void setState(byte[] state) {
+ synchronized(m) {
+ Map new_m=(Map)Util.objectFromByteBuffer(state);
+ m.clear();
+ m.addAll(new_m);
+ }
+ }
+ }
+ // use default props (has to include STATE_TRANSFER)
+ channel=new JChannel();
+ channel.setReceiver(new MyReceiver());
+ channel.connect("TestChannel");
+ boolean rc=channel.getState(null, 5000);
+
+ In a group consisting of A,B and C, with D joining the group and
calling Channel.getState(), the following sequence of callbacks happens:
@@ -1326,56 +1427,58 @@
the pull model, GetStateEvent and SetStateEvent have an additional
member, state_id, and in the push model, there are 2 additional
getState() and setState() callbacks. The example below shows partial
- state transfer for the push model:
-
+ state transfer for the push model:
- class MyReceiver extends ExtendedReceiverAdapter {
- final Map m=new HashMap();
+ class MyReceiver extends ExtendedReceiverAdapter {
+ final Map m=new HashMap();
- public byte[] getState() {
- return getState(null);
- }
-
- public byte[] getState(String substate_id) {
- synchronized(m) { // so nobody else can modify the map while we serialize it
- byte[] state=null;
- if(substate_id == null) {
- state=Util.objectToByteBuffer(m);
- }
- else {
- Object value=m.get(substate_id);
- if(value != null) {
- return Util.objectToByteBuffer(value);
- }
- }
- return state;
- }
- }
-
- public void setState(byte[] state) {
- setState(null, state);
- }
-
- public void setState(String substate_id, byte[] state) {
- synchronized(m) {
- if(substate_id != null) {
- Object value=Util.objectFromByteBuffer(state);
- m.put(substate_id, value);
- }
- else {
- Map new_m=(Map)Util.objectFromByteBuffer(state);
- m.clear();
- m.addAll(new_m);
- }
- }
- }
- }
-
- channel=new JChannel(); // use default properties (has to include pbcast.STATE_TRANSFER protocol)
- channel.setReceiver(new MyReceiver());
- channel.connect("TestChannel");
- boolean rc=channel.getState(null, "MyID", 5000);
-
+ public byte[] getState() {
+ return getState(null);
+ }
+
+ public byte[] getState(String substate_id) {
+ // so nobody can modify the map while we serialize it
+ synchronized(m) {
+ byte[] state=null;
+ if(substate_id == null) {
+ state=Util.objectToByteBuffer(m);
+ }
+ else {
+ Object value=m.get(substate_id);
+ if(value != null) {
+ return Util.objectToByteBuffer(value);
+ }
+ }
+ return state;
+ }
+ }
+
+ public void setState(byte[] state) {
+ setState(null, state);
+ }
+
+ public void setState(String substate_id, byte[] state) {
+ synchronized(m) {
+ if(substate_id != null) {
+ Object value=Util.objectFromByteBuffer(state);
+ m.put(substate_id, value);
+ }
+ else {
+ Map new_m=(Map)Util.objectFromByteBuffer(state);
+ m.clear();
+ m.addAll(new_m);
+ }
+ }
+ }
+ }
+
+ // use default props (has to include pbcast.STATE_TRANSFER)
+ channel=new JChannel();
+ channel.setReceiver(new MyReceiver());
+ channel.connect("TestChannel");
+ boolean rc=channel.getState(null, "MyID", 5000);
+
+
The example shows that the Channel.getState() method specifies the
ID of the substate, in this case "MyID". The
@@ -1410,19 +1513,19 @@
receiving/reading state through a provided InputStream reference. In
order to use streaming state transfer in a push mode, existing
ExtendedMessageListener has been expanded to include additional four
- methods:
-
+ methods:
-public interface ExtendedMessageListener {
+ public interface ExtendedMessageListener {
- /*non-streaming callback methods ommitted for clarity*/
+ /*non-streaming callback methods ommitted for clarity*/
- void getState(OutputStream ostream);
- void getState(String state_id, OutputStream ostream);
- void setState(InputStream istream);
- void setState(String state_id, InputStream istream);
-
-}
+ void getState(OutputStream ostream);
+ void getState(String state_id, OutputStream ostream);
+ void setState(InputStream istream);
+ void setState(String state_id, InputStream istream);
+ }
+
+
For a pull mode (when application uses channel.receive() to fetch
events) two new event classes will be introduced:
@@ -1443,29 +1546,30 @@
The following code snippet demonstrates how to pull events from a
channel, processing StreamingGetStateEvent and sending hypothetical
state through a provided OutputStream reference. Handling of
- StreamingSetStateEvent is analogous to this example:
-
- ...
- Object obj=channel.receive(0);
- if(obj instanceof StreamingGetStateEvent) {
- StreamingGetStateEvent evt=(StreamingGetStateEvent)obj;
- OutputStream oos = null;
- try {
- oos = new ObjectOutputStream(evt.getArg());
- oos.writeObject(state);
- oos.flush();
- }
- catch (Exception e) {}
- finally {
- try {
- oos.close();
- }
- catch (IOException e) {
- System.err.println(e);
- }
- }
- }
- ...
+ StreamingSetStateEvent is analogous to this example:
+
+ ...
+ Object obj=channel.receive(0);
+ if(obj instanceof StreamingGetStateEvent) {
+ StreamingGetStateEvent evt=(StreamingGetStateEvent)obj;
+ OutputStream oos = null;
+ try {
+ oos=new ObjectOutputStream(evt.getArg());
+ oos.writeObject(state);
+ oos.flush();
+ }
+ catch (Exception e) {}
+ finally {
+ try {
+ oos.close();
+ }
+ catch (IOException e) {
+ System.err.println(e);
+ }
+ }
+ }
+
+
JGroups has a great flexibility with state transfer methodology by
allowing application developers to implement both byte based and
@@ -1481,11 +1585,11 @@
Disconnecting from a channelDisconnecting from a channel is done using the following
- method:
-
-
- public void disconnect();
-
+ method:
+
+ public void disconnect();
+
+ It will have no effect if the channel is already in the
disconnected or closed state. If connected, it will remove itself from
@@ -1503,11 +1607,11 @@
To destroy a channel instance (destroy the associated protocol
stack, and release all resources), method
- close() is used:
-
-
- public void close();
-
+ close() is used:
+
+ public void close();
+
+ It moves the channel to the closed state, in which no further
operations are allowed (most throw an exception when invoked on a closed
diff -Nru libjgroups-java-2.7.0.GA/doc/manual/en/modules/blocks.xml libjgroups-java-2.12.2.Final/doc/manual/en/modules/blocks.xml
--- libjgroups-java-2.7.0.GA/doc/manual/en/modules/blocks.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/manual/en/modules/blocks.xml 2011-10-18 11:22:35.000000000 +0000
@@ -3,9 +3,11 @@
Building blocks are layered on top of channels. Most of them
do not even need a channel, all they need is a class that implements
interface Transport (channels do). This
- enables them to work on any type of group transport that obeys this
+ enables them to work on any type of group transport that implements this
interface. Building blocks can be used instead of channels whenever
- a higher-level interface is required. Whereas channels are simple
+ a higher-level interface is required.
+
+ Whereas channels are simple
socket-like constructs, building blocks may offer a far more
sophisticated interface. In some cases, building blocks offer access
to the underlying channel, so that -- if the building block at hand
@@ -19,7 +21,9 @@
PullPushAdapter
- Note that this building block has been deprecated and should not be used anymore !
+ Note that this building block has been deprecated and should not be used anymore !
+ Use a Receiver instead.
+ This class is a converter (or adapter, as used in
- public class RspList {
+ public class RspList implements Map<Address,Rsp> {
public boolean isReceived(Address sender);
public int numSuspectedMembers();
public Vector getResults();
@@ -280,7 +284,6 @@
public boolean isSuspected(Address sender);
public Object get(Address sender);
public int size();
- public Object elementAt(int i) throws ArrayIndexOutOfBoundsException;
}
@@ -382,14 +385,12 @@
shown):
- public RspList callRemoteMethods(Vector dests, String method_name,
- int mode, long timeout);
- public RspList callRemoteMethods(Vector dests, String method_name,
- Object arg1, int mode, long timeout);
- public Object callRemoteMethod(Address dest, String method_name,
- int mode, long timeout);
- public Object callRemoteMethod(Address dest, String method_name,
- Object arg1, int mode, long timeout);
+ public RspList callRemoteMethods(Vector dests, String method_name, int mode, long timeout);
+ public RspList callRemoteMethods(Vector dests, String method_name, Object arg1, int mode,
+ long timeout);
+ public Object callRemoteMethod(Address dest, String method_name, int mode, long timeout);
+ public Object callRemoteMethod(Address dest, String method_name, Object arg1, int mode,
+ long timeout);
The family of callRemoteMethods()
@@ -485,6 +486,73 @@
by providing a higher abstraction level between the application
and the primitive channels.
+ RequestOptions
+
+ RequestOptions is a collection of options that can be passed into a call, e.g. the mode (GET_ALL, GET_NONE),
+ timeout, flags etc. It is an alternative to passing multiple arguments to a method.
+
+
+
+ All calls with individual parameters have been deprecated in 2.9 and the new calls with RequestOptions
+ are:
+
+ public RspList callRemoteMethods(Collection<Address> dests, String method_name,
+ Object[] args,Class[] types, RequestOptions options);
+ public RspList callRemoteMethods(Collection<Address> dests, MethodCall method_call,
+ RequestOptions options);
+ public Object callRemoteMethod(Address dest, String method_name, Object[] args,
+ Class[] types, RequestOptions options);
+ public Object callRemoteMethod(Address dest, MethodCall call, RequestOptions options);
+
+
+
+
+ An example of how to use RequestOptions is:
+
+ RpcDispatcher disp;
+ RequestOptions opts=new RequestOptions(Request.GET_ALL)
+ .setFlags(Message.NO_FC | Message.DONT_BUNDLE);
+ Object val=disp.callRemoteMethod(target, method_call, opts);
+
+
+
+
+ Asynchronous calls with futures
+
+
+ When invoking a synchronous call, the calling thread is blocked until the response (or responses) has
+ been received.
+
+
+
+ A Future allows a caller to return immediately and grab the result(s) later. In
+ 2.9, two new methods, which return futures, have been added to RpcDispatcher:
+
+ public NotifyingFuture<RspList> callRemoteMethodsWithFuture(Collection<Address> dests,
+ MethodCall method_call, RequestOptions options);
+ public <T> NotifyingFuture<T> callRemoteMethodWithFuture(Address dest, MethodCall call,
+ RequestOptions options);
+
+
+
+
+ A NotifyingFuture extends java.util.concurrent.Future, with its regular methods such as isDone(),
+ get() and cancel(). NotifyingFuture adds setListener<FutureListener> to get notified when
+ the result is available. This is shown in the following code:
+
+ NotifyingFuture<RspList> future=dispatcher.callRemoteMethodsWithFuture(...);
+ future.setListener(new FutureListener() {
+ void futureDone(Future<T> future) {
+ System.out.println("result is " + future.get());
+ }
+ }
+ );
+
+
+
+
+
+
@@ -616,7 +684,184 @@
-
+
+
+ Distributed locking
+
+ In 2.12, a new distributed locking service was added, replacing DistributedLockManager. The new service is
+ implemented as a protocol and is used via org.jgroups.blocks.locking.LockService.
+
+
+ LockService talks to the locking protocol via events. The main abstraction of a distributed lock is an
+ implementation of java.util.concurrent.locks.Lock. All lock methods are supported, however, conditions
+ are not yet supported. (Based on feedback, they might be added later).
+
+
+ Below is an example of how LockService is typically used:
+
+ // locking.xml needs to have a locking protocol
+ JChannel ch=new JChannel("/home/bela/locking.xml");
+ LockService lock_service=new LockService(ch);
+ ch.connect("lock-cluster");
+ Lock lock=lock_service.getLock("mylock");
+ lock.lock();
+ try {
+ // do something with the locked resource
+ }
+ finally {
+ lock.unlock();
+ }
+
+
+
+ In the example, we create a channel, then a LockService, then connect the channel. Then we grab a lock
+ named "mylock", which we lock and subsequently unlock.
+
+
+ Note that the owner of a lock is always a given thread in a cluster, so the owner is the JGroups address and
+ the thread ID. This means that different threads inside the same JVM trying to access the same named lock
+ will compete for it. If thread-22 grabs the lock first, then thread-5 will block until thread-23
+ releases the lock.
+
+
+ JGroups includes a demo (org.jgroups.demos.LockServiceDemo), which can be used to interactively experiment
+ with distributed locks. LockServiceDemo -h dumps all command line options.
+
+
+ Currently (Jan 2011), there are 2 protocols which provide locking:
+ PEER_LOCK and CENTRAL_LOCK. The locking
+ protocol has to be placed at or towards the top of the stack (close to the channel).
+
+
+ Locking and merges
+
+ The following scenario is susceptible to merging: we have a cluster view of {A,B,C,D} and then the cluster
+ splits into {A,B} and {C,D}. Assume that B and D now acquire a lock "mylock".
+ This is what happens (with the locking protocol being CENTRAL_LOCK):
+
+ There are 2 coordinators: A for {A,B} and C for {C,D}
+ B successfully acquires "mylock" from A
+ D successfully acquires "mylock" from C
+ The partitions merge back into {A,B,C,D}. Now, only A is the coordinator, but C ceases
+ to be a coordinator
+ Problem: D still holds a lock which should actually be invalid !
+
+ There is no easy way (via the Lock API) to 'remove' the lock from D. We could for example simply release
+ D's lock on "mylock", but then there's no way telling D that the lock it holds is actually stale !
+
+
+ Therefore the recommended solution here is for nodes to listen to MergeView changes if they expect
+ merging to occur, and re-acquire all of their locks after a merge, e.g.:
+
+ Lock l1, l2, l3;
+ LockService lock_service;
+ ...
+ public void viewAccepted(View view) {
+ if(view instanceof MergeView) {
+ new Thread() {
+ public void run() {
+ lock_service.unlockAll();
+ // stop all access to resources protected by l1, l2 or l3
+ // every thread needs to re-acquire the locks it holds
+ }
+ }.start
+ }
+ }
+
+
+
+
+
+ Distributed ExecutionService
+
+ In 2.12, a distributed execution service was added. The new service is implemented as a protocol and is used
+ via org.jgroups.blocks.executor.ExecutionService.
+
+
+ ExecutionService talks to the executing protocol via events. The main abstraction is an implementation of
+ java.util.concurrent.locks.ExecutorService. All methods are supported. The restrictions are however that
+ the Callable or Runnable must be Serializable, Externalizable or Streamable. Also the result produced
+ from the future needs to be Serializable, Externalizable or Streamable. If the Callable or Runnable are not
+ then an IllegalArgumentException is immediately thrown. If a result is not then a NotSerializableException
+ with the name of the class will be returned to the Future as an exception cause.
+
+
+ Below is an example of how ExecutionService is typically used:
+
+ // locking.xml needs to have a locking protocol
+ JChannel ch=new JChannel("/home/bela/executing.xml");
+ ExecutionService exec_service =new ExecutionService(ch);
+ ch.connect("exec-cluster");
+ Future<Value> future = exec_service.submit(new MyCallable());
+ try {
+ Value value = future.get();
+ // Do something with value
+ }
+ catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ catch (ExecutionException e) {
+ e.getCause().printStackTrace();
+ }
+
+
+
+ In the example, we create a channel, then an ExecutionService, then connect the channel. Then we submit
+ our callable giving us a Future. Then we wait for the future to finish returning our value and do something
+ with it. If any exception occurs we print the stack trace of that exception.
+
+
+ JGroups includes a demo (org.jgroups.demos.ExecutionServiceDemo), which can be used to interactively
+ experiment with a distributed sort algorithm and performance. This is for demonstration purposes and
+ performance should not be assumed to be better than local.
+ ExecutionServiceDemo -h dumps all command line options.
+
+
+ Currently (March 2011), there is 1 protocol which provide executions:
+ CENTRAL_EXECUTOR. The executing protocol has to be placed at or
+ towards the top of the stack (close to the channel).
+
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/doc/manual/en/modules/installation.xml libjgroups-java-2.12.2.Final/doc/manual/en/modules/installation.xml
--- libjgroups-java-2.7.0.GA/doc/manual/en/modules/installation.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/manual/en/modules/installation.xml 2011-10-18 11:22:35.000000000 +0000
@@ -1,7 +1,7 @@
Installation and Configuration
- The installation refers to version 2.5 of JGroups. Refer to the installation
+ The installation refers to version 2.8 of JGroups. Refer to the installation
instructions that are shipped with JGroups for details.Note that these instructions are also available in the
@@ -22,10 +22,10 @@
- JGroups 2.5 requires JDK 5 or higher.
+ JGroups 2.5 requires JDK 1.5 or higher. Version 2.9 requires JDK 1.6 or higher.
- There is no JNI code present so it should run on all platforms.
+ There is no JNI code present so JGroups should run on all platforms.If you want to generate HTML-based test reports from the
@@ -53,16 +53,12 @@
INSTALL.html: this file
- commons-logging.jar
-
-
- log4j.jar. This JAR is optional, for example if JDK logging is used, we don't need it.
+ log4j.jar. This JAR is optional, for example if JDK logging is used, we don't need it. Note that
+ commons-logging is not a requirement any more since version 2.8.
- Place the JAR files somewhere in your CLASSPATH, and you're ready to start using
- JGroups. If you want to use the JGroups JMS protocol (org.jgroups.protocols.JMS),
- then you will also need to place jms.jar somewhere in your CLASSPATH.
+ Place the JAR files somewhere in your CLASSPATH, and you're ready to start using JGroups.
@@ -93,17 +89,7 @@
Ant
- JARs: used to build JGroups. If you already have
- Ant installed, you won't need these files
-
-
-
- jms.jar: JMS library. Needed only if you intend to
- run the org.jgroups.protocols.JMS protocol
-
-
- junit.jar: to run the
- JUnit test cases
+ JARs: used to build JGroups. If you already have Ant installed, you won't need these files
@@ -113,9 +99,6 @@
- commons-logging.jar
-
- log4j.jar
@@ -157,8 +140,7 @@
To generate the JARs:
- $> ./build.sh
- jar
+ $> ./build.sh jar
@@ -169,13 +151,13 @@
jgroups-core.jar
- - the core JGroups libraries
+ - the core JGroups library without unit tests and demos
jgroups-all.jar
- - the complete JGroups libraries including demos and unit tests
+ - the complete JGroups library including demos and unit tests
@@ -260,11 +242,10 @@
class is found:
- bela@dell /cygdrive/c/JGroups/dist
- $ java -jar jgroups-all.jar
+ [mac] /Users/bela/JGroups$ java org.jgroups.Version
- Version: 2.6.0 pre-alpha
- CVS: $Id: installation.xml,v 1.5 2007/07/24 16:30:46 belaban Exp $
+ Version: 2.8.0.GA
+ CVS: $Id: installation.xml,v 1.10 2010/04/30 14:27:39 vlada Exp $
@@ -298,6 +279,10 @@
a different transport if multicast doesn't work (it should always
work on the same machine). Please consult the documentation to see how to do this.
+
+ State transfer (see the section in the API later) can also be tested by passing the -state flag to Draw.
+
+
@@ -385,7 +370,7 @@
the receiver as follows:
- java org.jgroups.tests.McastReceiverTest1_4 -mcast_addr 228.8.8.8 -use_all_interfaces
+ java org.jgroups.tests.McastReceiverTest1_4 -mcast_addr 228.8.8.8 -use_all_interfaces
The multicast receiver uses the 1.4 functionality to list
@@ -397,7 +382,7 @@
- java org.jgroups.tests.McastSenderTest1_4 -mcast_addr 228.8.8.8 -use_all_interfaces
+ java org.jgroups.tests.McastSenderTest1_4 -mcast_addr 228.8.8.8 -use_all_interfaces
The sender will also determine the available network
@@ -407,13 +392,14 @@
bind to when previously no packets were received. E.g. when you
see the following output in the receiver:
-
- bash-2.03$ java org.jgroups.tests.McastReceiverTest1_4 -mcast_addr 228.8.8.8 -bind_addr 192.168.168.4
- Socket=0.0.0.0/0.0.0.0:5555, bind interface=/192.168.168.4
- dd [sender=192.168.168.4:5555]
- dd [sender=192.168.168.1:5555]
- dd [sender=192.168.168.2:5555]
-
+
+ bash-2.03$ java org.jgroups.tests.McastReceiverTest1_4 -mcast_addr 228.8.8.8
+ -bind_addr 192.168.1.4
+ Socket=0.0.0.0/0.0.0.0:5555, bind interface=/192.168.168.4
+ dd [sender=192.168.168.4:5555]
+ dd [sender=192.168.168.1:5555]
+ dd [sender=192.168.168.2:5555]
+ you know that you can bind to any of the 192.168.168.{1,2,4}
interfaces to receive your multicast packets. In this case you
@@ -439,7 +425,7 @@
- java -Djava.net.preferIPv4Stack=true org.jgroups.demos.Draw -props file:/home/bela/udp.xml
+ java -Djava.net.preferIPv4Stack=true org.jgroups.demos.Draw -props /home/bela/udp.xml
JDK 1.4.1 uses IPv6 by default, although is has a dual stack, that is, it also supports IPv4.
@@ -490,5 +476,23 @@
-
+ Supported classes
+ JGroups project has been around since 2001. Over this time, some of the JGroups classes
+ have been used in experimental phases and have never been matured enough to be used in today's production
+ releases. However, they were not removed since some people used them in their products.
+
+ The following tables list unsupported and experimental classes. These classes are not actively maintained, and
+ we will not work to resolve potential issues you might find. Their final faith is not yet determined; they
+ might even be removed altogether in the next major release. Weight your risks if you decide to use them anyway.
+
+ Experimental
+ ${Experimental}
+
+
+
+ Unsupported
+ ${Unsupported}
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/doc/manual/en/modules/overview.xml libjgroups-java-2.12.2.Final/doc/manual/en/modules/overview.xml
--- libjgroups-java-2.7.0.GA/doc/manual/en/modules/overview.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/manual/en/modules/overview.xml 2011-10-18 11:22:35.000000000 +0000
@@ -2,8 +2,8 @@
Group communication uses the terms group and member. Members are part
- of a group. In the more common terminology, a member is a node and a groups is a
- cluster. We use these words interchangeably.
+ of a group. In the more common terminology, a member is a node and a group is a
+ cluster. We use these terms interchangeably.
A node is a process, residing on some host. A cluster can have one or more nodes belonging to it. There
@@ -25,51 +25,36 @@
The architecture of JGroups is shown in .
-
-
-
- It consists of 3 parts: (1) the Channel API used by
+ It consists of 3 parts: (1) the Channel used by
application programmers to build reliable group communication
applications, (2) the building blocks, which are layered on top of
the channel and provide a higher abstraction level and (3) the
protocol stack, which implements the properties specified for a
given channel.
- This document describes how to install and
- use JGroups, ie. the Channel API and the
- building blocks. The targeted audience is application programmers
- who want to use JGroups to build reliable distributed programs
- that need group communication. Programmers who want to
- implement their own protocols to be used with
- JGroups should consult the Programmer's Guide for more details
- about the architecture and implementation of JGroups.
-
- A channel is connected to a protocol stack. Whenever the
- application sends a message, the channel passes it on to the
- protocol stack, which passes it to the topmost protocol. The
- protocol processes the message and the passes it on to the protocol
- below it. Thus the message is handed from protocol to protocol until
- the bottom protocol puts it on the network. The same happens in the
- reverse direction: the bottom (transport) protocol listens for
- messages on the network. When a message is received it will be
- handed up the protocol stack until it reaches the channel. The
- channel stores the message in a queue until the application consumes
- it.
+
+ This document describes how to install and use JGroups, ie. the Channel API and the
+ building blocks. The targeted audience is application programmers who want to use JGroups to
+ build reliable distributed programs that need group communication.
+
+
+
+ A channel is connected to a protocol stack. Whenever the
+ application sends a message, the channel passes it on to the
+ protocol stack, which passes it to the topmost protocol. The
+ protocol processes the message and the passes it on to the protocol
+ below it. Thus the message is handed from protocol to protocol until
+ the bottom (transport) protocol puts it on the network. The same happens in the
+ reverse direction: the transport protocol listens for
+ messages on the network. When a message is received it will be
+ handed up the protocol stack until it reaches the channel. The
+ channel stores the message in a queue until the application consumes it.
+ When an application connects to the channel, the protocol
stack will be started, and when it disconnects the stack will be
@@ -101,7 +86,7 @@
view. A process can select an address from
this list and send a unicast message to it (also to itself), or it
may send a multicast message to all members of the current
- view. Whenever a process joins or leaves a group, or when a
+ view (also including itself). Whenever a process joins or leaves a group, or when a
crashed process has been detected, a new view
is sent to all remaining group members. When a member process is
suspected of having crashed, a suspicion
@@ -117,12 +102,20 @@
received.
+
+ Note that the push approach to receiving messages and views is preferred. This involves setting a Receiver
+ in the channel and getting callbacks invoked by JGroups whenever a message or view is received.
+ The current pull approach (JChannel.receive() method) has been deprecated in 2.8 and will be removed in 3.0.
+
+
+
+
There is currently only one implementation of Channel: JChannel.
The properties of a channel are typically defined in an XML file, but JGroups also allows for configuration
- through simple strings, URIs, DOM trees or even programming.
+ through simple strings, URIs, DOM trees or even programmatically.
The Channel API and its related classes is described in
@@ -177,7 +170,7 @@
The protocol stack
containins a number of protocol layers in a bidirectional
list. All messages sent and received over the channel have to pass
- through the protocol stack. Every layer may modify, reorder, pass
+ through all protocols. Every layer may modify, reorder, pass
or drop a message, or add a header to a message. A fragmentation
layer might break up a message into several smaller messages,
adding a header with an id to each fragment, and re-assemble the
@@ -186,8 +179,7 @@
The composition of the protocol stack, i.e. its layers, is
determined by the creator of the channel: an XML file
defines the layers to be used (and the parameters for each
- layer). This string might be interpreted differently by each
- channel implementation; in JChannel it is used to create the
+ layer). The configuration is used to create the
stack, depending on the protocol names given in the
property.
diff -Nru libjgroups-java-2.7.0.GA/doc/manual/en/modules/protocols.xml libjgroups-java-2.12.2.Final/doc/manual/en/modules/protocols.xml
--- libjgroups-java-2.7.0.GA/doc/manual/en/modules/protocols.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/manual/en/modules/protocols.xml 2011-10-18 11:22:35.000000000 +0000
@@ -63,6 +63,10 @@
Initial membership discovery
+ The task of the discovery is to find an initial membership, which is used to determine the current
+ coordinator. Once a coordinator is found, the joiner sends a JOIN request to the coord.
+
+
PING
@@ -70,6 +74,33 @@
+
+
+ FILE_PING
+ This uses a shared directory into which all members write their addresses. New joiners read all addresses
+ from this directory (which needs to be shared, e.g. via NFS or SMB) and ping each of the elements of
+ the resulting set of members. When a member leaves, it deletes its corresponding file.
+
+ FILE_PING can be used instead of GossipRouter in cases where no external process is desired.
+
+
+ ${PING}
+
+
+
+
+ JDBC_PING
+ This uses a shared Database into which all members write their addresses. New joiners read all addresses
+ from this Database and ping each of the elements of the resulting set of members. When a member leaves,
+ it deletes its corresponding record.
+
+ JDBC_PING is an alternative to S3_PING by using Amazon RDS instead of S3.
+
+
+ ${JDBC_PING}
+
+
+
TCPPING
@@ -92,6 +123,32 @@
${MPING}
+
+
+ BPING
+
+ BPING uses UDP broadcasts to discover other nodes. The default broadcast address (dest) is
+ 255.255.255.255, and should be replaced with a subnet specific broadcast, e.g. 192.168.1.255.
+
+
+ ${BPING}
+
+
+
+
+ S3_PING
+ This uses an Amazon S3 bucket into which all members write their addresses. New joiners read all addresses
+ from this bucket and ping each of the elements of the resulting set of members. When a member leaves, it
+ deletes its corresponding file.
+
+ S3_PING is primarily meant to be used on Amazon EC2 where multicast traffic is not allowed and
+ no external process (GossipRouter) is desired. When Amazon RDS is preferred over S3, or if a shared
+ database is used, an alternative is to use JDBC_PING.
+
+
+ ${S3_PING}
+
+
@@ -155,7 +212,7 @@
Example: <FD_ALL interval="3000" timeout="10000"/>
- In the exampe above, we send a heartbeat every 3 seconds and suspect members if we haven't received a
+ In the example above, we send a heartbeat every 3 seconds and suspect members if we haven't received a
heartbeat (or traffic) for more than 10 seconds. Note that since we check the timestamps every
'interval'
milliseconds, we will suspect a member after roughly 4 * 3s == 12 seconds. If we set the timeout to
@@ -331,7 +388,18 @@
${UNICAST}
-
+
+
+
+ UNICAST2
+
+ UNICAST2 provides lossless, ordered, communication between 2 members. Contrary to UNICAST, it
+ uses negative acks (similar to NAKACK) rather than positive acks. This reduces the communication
+ overhead required for sending an ack for every message.
+
+
+ ${UNICAST2}
+
@@ -340,20 +408,33 @@
FRAG and FRAG2
-
-
+
${FRAG}
- Ordering (FIFO covered by NAKACK)
-
+ Ordering
- Total Order (SEQUENCER)
+ SEQUENCER
-
+
+ SEQUENCER provider total order for multicast (=group) messages by forwarding messages to the current
+ coordinator, which then sends the messages to the cluster on behalf of the original sender. Because it
+ is always the same sender (whose messages are delivered in FIFO order), a global (or total) order
+ is established.
+
+
+ Sending members add every forwarded message M to a buffer and remove M when they receive it. Should
+ the current coordinator crash, all buffered messages are forwarded to the new coordinator.
+
+
+ Note that retransmissions go to the original sender, not
+ to the coordinator.
+
+
+ ${SEQUENCER}
@@ -534,6 +615,15 @@
state transfer transfers the state in chunks of N bytes where N is
user configurable.
+
+ Prior to 2.6.9 and 2.8 releases streaming state transfer relied
+ exclusively on its own tcp sockets to transfer state between members.
+ The downside of tcp socket approach is that it is not firewall friendly. If
+ use_default_transport property of pbcast.STREAMING_STATE_TRANSFER is
+ set to true streaming state transfer will use normal messages to transfer
+ state. This approach besides being completely transparent to application is also
+ firewall friendly. However, as expected, tcp sockets have better performance.
+
@@ -771,11 +861,35 @@
until it has processed all messages worth max_credits bytes, the senders will block. This in turn allows STABLE to
progress and eventually garbage collect most messages from all senders. Therefore, SFC and STABLE complement each other,
with SFC blocking senders so that STABLE can catch up.
+
+
+ SFC is currently experimental, we recommend to use MFC and UFC (see below) instead.
${SFC}
+
+
+ MFC and UFC
+
+ In 2.10, FC was separated into MFC (Multicast Flow Control) and Unicast Flow Control (UFC). The reason
+ was that multicast flow control should not be impeded by unicast flow control, and vice versa. Also,
+ performance for the separate implementations could be increased, plus they can be individually omitted.
+ For example, if no unicast flow control is needed, UFC can be left out of the stack configuration.
+
+
+
+ MFC
+ ${MFC}
+
+
+
+ UFC
+ ${UFC}
+
+
+
@@ -817,7 +931,7 @@
COMPRESS
-
+ ${COMPRESS}
@@ -881,6 +995,231 @@
${FLUSH}
+
+
+ SCOPE
+
+ As discussed in Scopes, the SCOPE protocol is used to deliver updates
+ to different scopes concurrently. It has to be placed somewhere above UNICAST and NAKACK.
+
+
+
+ SCOPE has a separate thread pool. The reason why the default thread pool from the transport wasn't used
+ is that the default thread pool has a different purpose. For example, it can use a queue to which all
+ incoming messages are added, which would defy the purpose of concurrent delivery in SCOPE. As a matter
+ of fact, using a queue would most likely delay messages get sent up into SCOPE !
+
+
+ Also, the default pool's rejection policy might not be "run", so the SCOPE implementation would have
+ to catch rejection exceptions and engage in a retry protocol, which is complex and wastes resources.
+
+
+
+ The configuration of the thread pool is shown below. If you expect concurrent
+ messages to N different scopes, then the max pool size would ideally be set
+ to N. However, in most cases, this is not necessary as (a) the messages might not be to different
+ scopes or (b) not all N scopes might get messages at the same time. So even if the max pool size is a
+ bit smaller, the cost of this is slight delays, in the sense that a message for scope Y might wait until
+ the thread processing message for scope X is available.
+
+
+
+ To remove unused scopes, an expiry policy is provided: expiration_time is the number of milliseconds
+ after which an idle scope is removed. An idle scope is a scope which hasn't seen any messages for
+ expiration_time milliseconds. The expiration_interval value defines the number of milliseconds at
+ which the expiry task runs. Setting both values to 0 disables expiration; it would then have to be
+ done manually (see for details).
+
+
+ ${SCOPE}
+
+
+
+ RELAY
+
+ RELAY bridges traffic between seperate clusters, see for details.
+
+ ${RELAY}
+
+
+
+ STOMP
+
+ STOMP is a JGroups protocol which implements the STOMP
+ protocol. Currently (as of Nov 2010), transactions and acks are not implemented.
+
+
+ The location of a STOMP protocol in a stack is shown in .
+
+
+
+
+
+
+ The STOMP protocol should be near the top of the stack.
+
+
+ A STOMP instance listens on a TCP socket for client connections. The port and bind address of the
+ server socket can be defined via properties.
+
+
+ A client can send SUBSCRIBE commands for various destinations. When a SEND for a given destination is
+ received, STOMP adds a header to the message and broadcasts it to all cluster nodes. Every node then in
+ turn forwards the message to all of its connected clients which have subscribed to the same destination.
+ When a destination is not given, STOMP simply forwards the message to all connected
+ clients.
+
+
+ Traffic can be generated by clients and by servers. In the latter case, we could for example have code
+ executing in the address space of a JGroups (server) node. In the former case, clients use the SEND
+ command to send messages to a JGroups server and receive messages via the MESSAGE command. If there is
+ code on the server which generates messages, it is important that both client and server code agree
+ on a marshalling format, e.g. JSON, so that they understand each other's messages.
+
+
+ Clients can be written in any language, as long as they understand the STOMP protocol. Note that the
+ JGroups STOMP protocol implementation sends additional information (e.g. INFO) to clients; non-JGroups
+ STOMP clients should simply ignore them.
+
+
+ JGroups comes with a STOMP client (org.jgroups.client.StompConnection) and a demo (StompDraw). Both
+ need to be started with the address and port of a JGroups cluster node. Once they have been started,
+ the JGroups STOMP protocol will notify clients of cluster changes, which is needed so client can
+ failover to another JGroups server node when a node is shut down. E.g. when a client connects to C, after
+ connection, it'll get a list of endpoints (e.g. A,B,C,D). When C is terminated, or crashes, the client
+ automatically reconnects to any of the remaining nodes, e.g. A, B, or D. When this happens, a client
+ is also re-subscribed to the destinations it registered for.
+
+
+ The JGroups STOMP protocol can be used when we have clients, which are either not in the same network
+ segment as the JGroups server nodes, or which don't want to become full-blown JGroups server nodes.
+ shows a typical setup.
+
+
+
+
+
+
+
+ There are 4 nodes in a cluster. Say the cluster is in a LAN, and communication is via IP multicasting
+ (UDP as transport). We now have clients which do not want to be part of the cluster themselves, e.g.
+ because they're in a different geographic location (and we don't want to switch the main cluster to TCP),
+ or because clients are frequently started and stopped, and therefore the cost of startup and joining
+ wouldn't be amortized over the lifetime of a client. Another reason could be that clients are written
+ in a different language, or perhaps, we don't want a large cluster, which could be the case if we
+ for example have 10 JGroups server nodes and 1000 clients connected to them.
+
+
+ In the example, we see 9 clients connected to every JGroups cluster node. If a client connected to
+ node A sends a message to destination /topics/chat, then the message is multicast from node A to all other
+ nodes (B, C and D). Every node then forwards the message to those clients which have previously subscribed
+ to /topics/chat.
+
+
+ When node A crashes (or leaves) the JGroups STOMP clients (org.jgroups.client.StompConnection) simply pick
+ another server node and connect to it.
+
+
+
+
+
+ The properties for STOMP are shown below:
+
+ ${STOMP}
+
+
+
+
+ DAISYCHAIN
+
+ The DAISYCHAIN protocol is discussed in .
+
+
+ ${DAISYCHAIN}
+
+
+
+
+ RATE_LIMITER
+
+ RATE_LIMITER can be used to set a limit on the data sent per time unit. When sending data, only
+ max_bytes can be sent per time_period milliseconds. E.g. if max_bytes="50M" and time_period="1000", then
+ a sender can only send 50MBytes / sec max.
+
+
+ ${RATE_LIMITER}
+
+
+
+ Locking protocols
+
+ There are currently 2 locking protocols: org.jgroups.protocols.CENTRAL_LOCK and
+ org.jgroups.protocols.PEER_LOCK.
+
+
+ CENTRAL_LOCK
+
+ CENTRAL_LOCK has the current coordinator of a cluster grants locks, so every node has to communicate
+ with the coordinator to acquire or release a lock. Lock requests by different nodes for the same lock
+ are processed in the order in which they are received.
+
+
+ A coordinator maintains a lock table. To prevent losing the knowledge of who holds which locks, the
+ coordinator can push lock information to a number of backups defined by num_backups. If num_backups
+ is 0, no replication of lock information happens. If num_backups is greater than 0, then the coordinator
+ pushes information about acquired and released locks to all backup nodes. Topology changes might
+ create new backup nodes, and lock information is pushed to those on becoming a new backup node.
+
+
+ The advantage of CENTRAL_LOCK is that all lock requests are granted in the same order across
+ the cluster, which is not the case with PEER_LOCK.
+
+
+ ${CENTRAL_LOCK}
+
+
+
+ PEER_LOCK
+
+ PEER_LOCK acquires a lock by contacting all cluster nodes, and lock acquisition is only successful
+ if all non-faulty cluster nodes (peers) grant it.
+
+
+ Unless a total order configuration is used (e.g. org.jgroups.protocols.SEQUENCER based), lock
+ requests for the same resource from different senders may be received in different order, so
+ deadlocks can occur. Example:
+
+ Nodes A and B
+ A and B call lock(X) at the same time
+ A receives L(X,A) followed by L(X,B): locks X(A), queues L(X,B)
+ B receives L(X,B) followed by L(X,A): locks X(B), queues L(X,A)
+
+
+
+ To acquire a lock, we need lock grants from both A and B, but this will never happen here.
+ To fix this, either add SEQUENCER to the configuration, so that all lock requests are received in
+ the same global order at both A and B, or use
+ java.util.concurrent.locks.Lock.tryLock(long,javaTimeUnit) with retries if a lock cannot be acquired.
+
+
+ ${PEER_LOCK}
+
+
+
+
+ CENTRAL_EXECUTOR
+
+ CENTRAL_EXECUTOR is an implementation of Executing which is needed by the ExecutionService.
+
+ ${CENTRAL_EXECUTOR}
+
+
diff -Nru libjgroups-java-2.7.0.GA/doc/manual/en/modules/writing.xml libjgroups-java-2.12.2.Final/doc/manual/en/modules/writing.xml
--- libjgroups-java-2.7.0.GA/doc/manual/en/modules/writing.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/manual/en/modules/writing.xml 2011-10-18 11:22:35.000000000 +0000
@@ -66,7 +66,7 @@
int cnt=1;
for(int i=0; i < 5; i++) {
Message msg=new Message();
- msg.putHeader("x", new MyHeader(cnt++));
+ msg.putHeader((short)1900, new MyHeader(cnt++));
ch.send(msg);
}
ch.close();
@@ -83,12 +83,6 @@
this.counter=counter;
}
- private static final long serialVersionUID=7726837062616954053L;
-
- public void writeExternal(ObjectOutput out) throws IOException {}
-
- public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {}
-
public String toString() {
return "counter=" + counter;
}
diff -Nru libjgroups-java-2.7.0.GA/doc/MarshalingFormat.txt libjgroups-java-2.12.2.Final/doc/MarshalingFormat.txt
--- libjgroups-java-2.7.0.GA/doc/MarshalingFormat.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/MarshalingFormat.txt 1970-01-01 00:00:00.000000000 +0000
@@ -1,61 +0,0 @@
-
-// Author: Bela Ban
-// $Id: MarshalingFormat.txt,v 1.10 2008/10/21 07:40:26 belaban Exp $
-
-
-Binary format for marshalled messages
-=====================================
-
-An org.jgroups.Message is marshalled to a byte stream as follows.
-
-- version ID: short (2 bytes). Version.encode() encodes the major, minor and patch version into the short.
-- flags (byte):
- - single message or list of messages (LIST)
- If single message --> SingleMessage, else MessageList
- - multicast (MULTICAST) or unicast message (for optimizations)
-
-SingleMessage:
-- leading: byte. Has bits set for null src and dest addresses, buf and headers
-- flags: byte
-- src address: Address
-- [length of buf]: int
-- [buf]: byte[] array
-- [Headers]: list of headers --> Headers
-
-
-MessageList:
-- length: int. Number of messages in the list
-- src address: Address
-- 1-m Messages: --> SingleMessage, but with no src and dest addresses
-
-
-
-Headers:
-- length: int. Number of headers
-- For each Header:
- - Key: UTF-8 string
- - Header
-
-
-Header:
-- magic_number (short)
-- if magic number == -1 (not present):
- - no-op
-- else
- - UTF-8 string (class name)
-- size in bytes (short)
-- contents (header-specific)
-
-
-UTF-8 strings:
-- All strings start with a short that is the length of the string (DataOutputStream.writeUTF(String))
-
-
-Notes:
-
-- In most cases, we don't need to send the dest address, because the sender knows whether the message
- was received on the unicast or multicast socket, and can thus set the dest address in an incoming
- message to its own local address, or multicast address
-
-- This is currently as used by UDP. Once we move to Transport (e.g. including TCP), this needs to be
- revisited. Currently (2.2.8), TCP uses externalization, *not* Streamable.
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/NullDestAddresses.txt libjgroups-java-2.12.2.Final/doc/NullDestAddresses.txt
--- libjgroups-java-2.7.0.GA/doc/NullDestAddresses.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/NullDestAddresses.txt 1970-01-01 00:00:00.000000000 +0000
@@ -1,21 +0,0 @@
-
-Nulling of destination addresses for optimized marshalling
-==========================================================
-
-Version: $Id: NullDestAddresses.txt,v 1.2 2005/08/26 11:06:37 belaban Exp $
-Author: Bela Ban
-Date: Aug 26 2005
-
-When we marshall a message (org.jgroups.Message), we can transmit a null value for the destination, because
-the receiver can determine the destination:
-- for UDP: if received on the multicast receive socket, the destination is the multicast address (same as null)
- if received on the unicast receive socket, the destination is the local_addr (ourself)
-- for TCP: we use the MULTICAST byet sent with the message when unmarshalling the message:
- - if true, we leave the deatination null (= multicast destination)
- - if not set, we set the destination to the address passed to use from the ConnectionTable
-
-This requires that when marshalling a message, we send a multicast byte with each Message (or once for bundled msgs)
-based on the destination address !
-
-Note that we *cannot* modify the destination address in the message itself, otherwise retransmissions might fail !
-
diff -Nru libjgroups-java-2.7.0.GA/doc/NullingSrcAddresses.txt libjgroups-java-2.12.2.Final/doc/NullingSrcAddresses.txt
--- libjgroups-java-2.7.0.GA/doc/NullingSrcAddresses.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/NullingSrcAddresses.txt 1970-01-01 00:00:00.000000000 +0000
@@ -1,20 +0,0 @@
-
-Loopback adaptor issues on Windows
-----------------------------------
-
-JIRA: http://jira.jboss.com/jira/browse/JGRP-79
-Version: $Id: NullingSrcAddresses.txt,v 1.1 2005/05/19 07:57:46 belaban Exp $
-
-On Windows, when a loopback adaptor is created, we can associate multiple (virtual) IP
-addresses with it, e.g. 10.0.0.1 and 10.0.0.2.
-
-However, when we have a member M1 bound to 10.0.0.1, and another member M2 bound to 10.0.0.2, and
-bind_to_all_interfaces is set to true, then it was observed that - regardless of the bind address -
-the sender's address in a DatagramPacket received was always 10.0.0.1 (the first address assigned) !
-
-Therefore, members would never find each other.
-
-The reason this shows up now (in 2.2.8) is that as an optimization, we *don't* send the src address
-in the Message anymore, so we can save a few bytes, but we null the src address, and set it to the sender's
-address when we *receive* the packet.
-This can be disabled by setting null_src_addresses to false (default is true)
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/perfgraph.plt libjgroups-java-2.12.2.Final/doc/perfgraph.plt
--- libjgroups-java-2.7.0.GA/doc/perfgraph.plt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/perfgraph.plt 1970-01-01 00:00:00.000000000 +0000
@@ -1,26 +0,0 @@
-#This is a gnuplot file used for plotting performance test result graphs
-
-set term png
-set out "picname.png"
-set data style boxes
-set style fill solid border -1
-set logscale xy
-set yrange [1:100000]
-set xrange [1:1000000]
-set style fill solid 1.0
-set boxwidth 0.10
-set title "Throughput in msg/sec(cluster of 8 machines,udp.xml,JGroups 2.3)"
-set xlabel "Message size"
-set ylabel "Number of messages per sec"
-set xtics ("100B" 100,"1K" 1000, "10K" 10000, "100K" 100000)
-plot "perfdata.dat" using ($1):($2) lt rgb "#6495ED" t "1 sender",\
-"perfdata.dat" using ($1*1.27):($3) lt rgb "#BA55D3" t "4 senders",\
-"perfdata.dat" using ($1*1.63):($4) lt rgb "#FFF8DC" t "8 senders"
-
-
-#where perfdata.dat looks something like this
-
-#100 29754 30873 27161
-#1000 15886 11354 15918
-#10000 2013 314 624
-#100000 183 77 54
diff -Nru libjgroups-java-2.7.0.GA/doc/PerformanceNotes.txt libjgroups-java-2.12.2.Final/doc/PerformanceNotes.txt
--- libjgroups-java-2.7.0.GA/doc/PerformanceNotes.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/PerformanceNotes.txt 2011-10-18 11:22:35.000000000 +0000
@@ -2,7 +2,6 @@
Check list for performance tuning (mainly gige)
===============================================
-Version: $Id: PerformanceNotes.txt,v 1.1 2006/08/15 08:23:33 belaban Exp $
Author: Bela Ban, Eric
For the transmit queue:
diff -Nru libjgroups-java-2.7.0.GA/doc/persistence.html libjgroups-java-2.12.2.Final/doc/persistence.html
--- libjgroups-java-2.7.0.GA/doc/persistence.html 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/persistence.html 1970-01-01 00:00:00.000000000 +0000
@@ -1,217 +0,0 @@
-
-
-
- Persistence for Hashtables
-
-
-
-
-
-
-
-
-
-
-
Persistence
-
-
Using Persistence
-
-
The package is meant for users who need to maintain the state of their
-Serializable name-value pair sets for better fault tolerance. Using this package
-will improve usability but will affect performance depending on the usage
-of the persist API.
-
The current package will support only 2 known implementations, the
-DB storage way (which is vendor independant) and an ad-hoc (or some open
-source) implementation.
-
The Persistence package assumes that the user will provide appropriate
-properties to initialize and use the storage mechanism.
-
-
Code Example
-Code examples make it easy to comprehend the package.
-
Classname for driver that needs to be loaded for DB storage.
-
oracle.jdbc.driver.OracleDriver
-
-
-
jdbc.Conn
-
Connection string required for user to connect to Db instance
-
jdbc:oracle:oci8:@instance
-
-
-
jdbc.User
-
User name required to connect to provided DB instance
-
user
-
-
-
jdbc.Pass
-
Password wrt to User provided
-
pass
-
-
-
-
-
-
-
-
-
-
-
Using org.jgroups.blocks.DistributedHashtable with PersistenceManager
-
// Example of how to setup and use DistributedHashtable
-
-
-
Create persist.properties (classpath or home dir)
-
-
Start one instance with -persist
-
Start another instance with -persist
-
Add a couple of values
-
Delete both instances
-
Start first instance again: previous values should be available
-
-
-
-
-
-
-
-
-
-
-
diff -Nru libjgroups-java-2.7.0.GA/doc/PrimaryPartition.txt libjgroups-java-2.12.2.Final/doc/PrimaryPartition.txt
--- libjgroups-java-2.7.0.GA/doc/PrimaryPartition.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/PrimaryPartition.txt 1970-01-01 00:00:00.000000000 +0000
@@ -1,43 +0,0 @@
-
-Design of the PRIMARY_PARTITION protocol
-========================================
-
-Author: Bela Ban
-Version: $Id: PrimaryPartition.txt,v 1.1 2005/07/21 20:33:01 belaban Exp $
-
-
-Dawid Kurzyniec wrote:
-
-> Bela Ban wrote:
->
->> I think adding a protocol on top of (or below ?) GMS will work. However, there is the question of how you actually determine the primary and secondary partitions ?
->> For example, if we have a switch crash, and all 5 members in the group become singleton groups, then the switch is turned back on, which one
->> is the primary partition ? There is no majority. Of course, you simply need to take a deterministic decision, e.g. in this case do a lexical sort and take
->> the first (A). Is this what you are thinking of doing ? So B, C, D and E would get an EXIT event, would have to leave and possibly re-join ? This
->> would be simple to implement.
->
->
-> Yes, this is pretty much what we have in mind. We intend in a conflicting case to find the greatest address of all members from candidate groups, then pick as a surviving group the one where this greatest guy belongs to (or should we take the smallest one? It would be nice to bias towards the group containing the current coordinator; does the coordinator has the smallest or the largest address in its group?)
-
-
-It is a lexical sort, e.g. Address extends Comparable, so we sort and take the first member of the resulting merged group as the coordinator
-
-> In fact we figured we don't even need a protocol - handling this in MembershipListener should do the job, I guess?... (We are lazy and we want to deal with JGroups at the highest level possible).
-
-
-I think it should be a protocols, PRIMARY_PARTITION, and can be implemented as follows:
-
- * Place it somewhere below GMS, but above MERGE2, It probably needs lossless delivery, so it should be ablove UNICAST and NAKACK as well
- * Handle the MERGE event on the up() method:
- o Get the subgroups, e.g. {A,B}, {C}, {D,E} and {F}
- o Consult a *merge policy*, which determines (given the list of subgroups), the primary partition
- o If we are the coordinator of the primary partition:
- + Send an exit message to all other coordinators (hmm, you probably can't do that as you are not a member of the subgroups, so probably we have to handle VIEW(MergeView) rather than the MERGE event
- + The other coordinators forward the EXIT event to everyone else in their group, so all members leave (and possibly rejoin) the group
- o Else
- + Send the EXIT event to everyone in my group
- + Everyone shuts down and possibly rejoins later
-
-The MergePolicy implementation needs to be configurable, so devs can specify their own implementation. We would supply a default impl if not specified.
-Looks relatively straightforward. The only thing I don't really like is that we have to merge *first* before we send the EXIT message to members of the *previous* subgroups.
-However, this is probably necessary as we cannot send messages to members *not* in our group
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/ProtocolReentrancy libjgroups-java-2.12.2.Final/doc/ProtocolReentrancy
--- libjgroups-java-2.7.0.GA/doc/ProtocolReentrancy 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/ProtocolReentrancy 1970-01-01 00:00:00.000000000 +0000
@@ -1,16 +0,0 @@
-
-Author: Bela Ban
-Version: $id$
-
-A typical protocol in JGroups can be assured that only up() and down() methods can be called concurrently,
-however up() and up() methods, and down() and down() methods cannot be called concurrently. This is due
-to JGroups using an up and down queue, and 1 thread per queue continually dequeues messages and invokes up() or down().
-However, with the introduction of down_thread=false and up_thread=false, we don't use queues anymore. If, in this case,
-we have multiple threads calling Channel.send() concurrently, then the above guarantee cannot be provided anymore.
-As a result, down() in any given protocol *can* now be called concurrently, by different threads, and so each protocol
-has to be made thread safe (reentrant).
-
-The focus here has to be on the down() side; multiple threads can call send() simultaneously.
-However, the up() methods are probably not much of a problem because they are called by a single
-thread (the receiver thread). We *cannot* use a thread pool for receiving messages, as this would
-violate the ordering previously established.
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/README libjgroups-java-2.12.2.Final/doc/README
--- libjgroups-java-2.7.0.GA/doc/README 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/README 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,19 @@
+
+JGroups ships as a single JAR file: jgroups-x.y.z.jar. Simply add it to your classpath and start coding !
+
+The JGroups version can be printed with java -jar jgroups-x.y.z.jar.
+
+There's a simple draw demo, start 2 or more instances: java -cp jgroups-x.y.z.jar org.jgroups.demos.Draw, and see if
+the members find each other.
+
+The sources for the core classes are in jgroups-sources.jar.
+
+If you want the complete sources, including unit tests, go to http://www.github.com/belaban/jgroups.
+
+JGroups is hosted at www.jgroups.org.
+
+For questions use either the dev or users mailing list.
+
+Enjoy,
+
+Bela Ban
diff -Nru libjgroups-java-2.7.0.GA/doc/RELEASE_INSTRUCTIONS libjgroups-java-2.12.2.Final/doc/RELEASE_INSTRUCTIONS
--- libjgroups-java-2.7.0.GA/doc/RELEASE_INSTRUCTIONS 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/RELEASE_INSTRUCTIONS 2011-10-18 11:22:35.000000000 +0000
@@ -1,11 +1,10 @@
-// $Id: RELEASE_INSTRUCTIONS,v 1.21 2008/09/17 15:16:51 belaban Exp $
Things to do before packaging a release
---------------------------------------
Pre-release:
- Do a cvs update -dP and commit all pending changes
-- Run all unit tests (all-tests-cc target)
+- Run all unit tests: ./build clean all-tests reports
- Run the manual tests in doc/tests/ManualTests.txt
- Run the performance tests to see whether performance is about the same
(see wiki http://wiki.jboss.org/wiki/Wiki.jsp?page=PerfTests)
@@ -13,12 +12,12 @@
Release:
- Update the ReleaseNotes-xxx.txt for the given release
-- Set version in: Version.java, manifest.mf, build.xml and jgroups-pom.xml
+- Set version in: Version.java, manifest.mf, build.xml and pom.xml
* Note that the version needs to conform to the version standards, e.g. 2.6.2.GA or 2.6.4.CR2, 2.5.4.Beta1
- Create a CVS tag: JGroups_x_y_z
- Add tag information to wiki: http://wiki.jboss.org/wiki/Wiki.jsp?page=Branches
-- Create a distribution: ./build.sh dist
- - the distribution files are dist/JGroups-x.y.z-rel.bin.zip, dist/JGroups-x.y.z-rel.src.zip
+- Create a distribution: ./build.sh jar
+ - the distribution files are dist/jgroups-x.y.z.jar, dist/jgroups-sources.jar
- Upload distribution files to web site:
- Go to http://sourceforge.net/projects/javagroups/
- Log in and pick http://sourceforge.net/project/admin/editpackages.php?group_id=6081
@@ -30,25 +29,13 @@
- see JGroups/bin/upload_manual.sh
- Create javadoc: ./build.sh javadoc and upload to web site
- use process similar to pdf and html (script is bin/upload_javadocs.sh)
-- Add new release binary jar *and* source jar to maven2 repository (http://repository.jboss.org/maven2)
- a. Check out the jgroups directory of the maven repository into a working directory $JG_REPO
- > svn co https://svn.jboss.org/repos/repository.jboss.org/maven2/jgroups/jgroups $JG_REPO
- b. Update the working copy with the new release binary jar file
- > mvn deploy:deploy-file -Dfile=$JG_RELEASE/dist/jgroups-all.jar -Durl=file://$JG_REPO -DpomFile=$JG_RELEASE/jgroups-pom.xml
- This command will do the following:
- - use the pom you passed to determine groupId/artifactId/version
- - create a directory in the svn working copy you checked out with the groupId/artifactID/version number
- - copy the jar into the directory and name it by version number
- - copy the pom passed into the directory
- - create checksums for the jar and the pom
- - update the maven meta-data files in the parent directory
- c. Update the working copy with the new release sources jar file
- > mvn deploy:deploy-file -Dfile=$JG_RELEASE/dist/jgroups-sources.jar -Durl=file://$JG_REPO \
- -DpomFile=$JG_RELEASE/jgroups-pom.xml -Dclassifier=sources
- Performs the same actions as in step b., except that the classifier parameter causes the file to retain
- the sources suffix in the repository.
- d. Add the new directories and files to version control and commit the changes to the maven2 repo.
- (see wiki http://wiki.jboss.org/wiki/Wiki.jsp?page=MavenReleaseRepository)
+- Add new release binary jar *and* source jar to Nexus maven repository (http://repository.jboss.org/nexus)
+ a. Run ./bin/release_to_nexus.sh (you need access permissions to Nexus)
+ b. Go to Nexus: https://repository.jboss.org/nexus
+ c. Log in (jboss.org login)
+ d. Click on Staging repositories in the left hand pane
+ e. Right click on the uploaded artifacts (JAR and src JAR) and either drop or promote them. In case of promotion,
+ the artifacts will be promoted to the jboss-releases repository and removed from the staging repo
- Announcement to the jg-dev and jg-users mailing lists
-include release notes and changelog
diff -Nru libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.12.txt libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.12.txt
--- libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.12.txt 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.12.txt 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,95 @@
+
+
+Release Notes JGroups 2.12.1
+============================
+
+
+Author: Bela Ban
+
+JGroups 2.12.1 is API-backwards compatible with previous versions (down to 2.2.7).
+
+Below is a summary (with links to the detailed description) of the major new features, optimizations and bug fixes.
+
+
+
+
+New features
+============
+
+Sample config for large clusters
+--------------------------------
+[https://issues.jboss.org/browse/JGRP-1307]
+
+
+Config udp-largecluster.xml was added, serves as blueprint for large clusters. This is work-in-progress.
+
+
+
+
+Optimizations
+=============
+
+
+ExecutionService
+----------------
+[https://issues.jboss.org/browse/JGRP-1308]
+[https://issues.jboss.org/browse/JGRP-1310]
+
+Removed serialization overhead when assigning task to self
+
+
+
+
+
+Bug fixes
+=========
+
+
+ENCRYPT: use alg provider for cipher creation
+----------------------------------------------------
+[https://issues.jboss.org/browse/JGRP-1311]
+
+During distribution of the encryption key from the master to each cluster member,
+use the configured asym_provider and sym_provider when getting Ciphers.
+
+
+
+TCP SocketFactory ignored
+-------------------------
+[https://issues.jboss.org/browse/JGRP-1312]
+
+Despite setting a custom SocketFactory, it was ignored.
+
+
+Configuration sanity check: order of protocols was not enforced
+---------------------------------------------------------------
+[https://issues.jboss.org/browse/JGRP-1305]
+
+E.g. STABLE being below NAKACK would not throw an exception
+
+
+Custom thread factories, thread pools and timer overridden in init()
+--------------------------------------------------------------------
+[https://issues.jboss.org/browse/JGRP-1306]
+
+When setting a custom thread factory, pool or timer, they would get overwritten in TP.init()
+
+
+
+Manual
+======
+
+The manual is online at http://www.jgroups.org/manual/html/index.html
+
+
+
+The complete list of features and bug fixes can be found at http://jira.jboss.com/jira/browse/JGRP.
+
+
+Bela Ban, Kreuzlingen, Switzerland
+Vladimir Blagojevic, Toronto, Canada
+Richard Achmatowicz, Toronto, Canada
+Sanne Grinovero, Newcastle, Great Britain
+
+April 2011
+
diff -Nru libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.2.8.txt libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.2.8.txt
--- libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.2.8.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.2.8.txt 1970-01-01 00:00:00.000000000 +0000
@@ -1,72 +0,0 @@
-
-Release Notes JGroups 2.2.8
-===========================
-
-Version: $Id: ReleaseNotes-2.2.8.txt,v 1.2 2007/08/20 11:15:39 belaban Exp $
-Author: Bela Ban
-
-
-Fast Message marshalling
-------------------------
-- Replaced Externalizable for Message with Streamable, resulting in much faster marshalling and
- reduced size of marshalled messages, allowing for more messages to be sent / second
-- org.jgroups.tests.MessageSerializationTest2 can be used to compare Externalizable with
- Streamable:
-- For 50000 messages, size reduction is almost 50%, marshalling 150% faster and unmarshalling 650% faster
- flags="-Xmx500M -Xms500M -XX:NewRatio=1 -XX:+AggressiveHeap -verbose:gc
- -XX:+DisableExplicitGC -XX:ThreadStackSize=32 -XX:CompileThreshold=100"
- java $flags org.jgroups.tests.MessageSerializationTest2 -num 100000 -add_headers false
- serialized size=8588935, streamable size=5788899, streamable is 48 percent smaller
- serialized write=831, streamable write=331, streamable write is 151 percent faster
- serialized read=1352, streamable read=180, streamable read is 651 percent faster
-
-Performance numbers
--------------------
-- Real tests will be produced in 2.2.9, using org.jgroups.tests.perf.Test
-- With JGroups/conf/fc-fast-minimalthreads.xml, I got ca 5000 1K messages on my laptop:
- (2 members, 1 sender, 1 receiver, 1 CPU laptop, 20000 1K msgs, 100Mbps switch)
- - April 20 2005: **5006** msgs/sec (on 192.168.5.1):
- -Xmx500M -Xms500M -XX:NewRatio=1 -XX:+AggressiveHeap -verbose:gc -XX:+DisableExplicitGC
- -XX:ThreadStackSize=32 -XX:CompileThreshold=100:
- combined: num_msgs_expected=20000, num_msgs_received=20000 (loss rate=0%), received=20MB,
- time=3995ms, msgs/sec=5006.26, throughput=5.01MB/sec
-
-UDP
-----------
-- bind_to_all_interfaces="true" now allows to listen for multicast messages on *all* available interfaces.
- This requires 1.4, under 1.3 the default interface will be selected
-
-MPING
------
-- MPING allows for a combination where node discovery in a cluster uses multicast, but the real transport uses
- TCP. This is an addition to TCP:TCPPING and TCP:TCPGOSSIP. Example (short version of JGroups/conf/mping.xml):
-
-
-
-
-
-
-
-
-
-Concurrent startup
-------------------
-- When multiple members are started simultaneously, and no other member is running yet,
- they form singleton groups, and merge after some time.
- The new version avoids this merge, so merging occurs only after network partitions now, never
- on concurrent startup of initial members
-
-
-
-
-
-
diff -Nru libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.2.9.txt libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.2.9.txt
--- libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.2.9.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.2.9.txt 1970-01-01 00:00:00.000000000 +0000
@@ -1,143 +0,0 @@
-
-Release Notes JGroups 2.2.9
-===========================
-
-Version: $Id: ReleaseNotes-2.2.9.txt,v 1.8 2005/12/09 14:53:36 belaban Exp $
-Author: Bela Ban
-Date: Dec 9 2005
-
-
-JMX support
------------
-The channel and most protocols can now be accessed via JMX. This can
-be used in any environment that provides an MBeanServer, e.g. JBoss or
-JDK 5. With JDK 5's jconsole, for example, retransmission counters can
-be viewed in realtime, or operations can be invoked that dump the
-retransmission windows for NAKACK etc.
-More information is available at
-http://wiki.jboss.org/wiki/Wiki.jsp?page=JMX.
-
-
-Push model available in JChannel
---------------------------------
-Instead of having to pull (receive()) a message out of a channel, a Receiver listener can
-be registered with a channel. When a message, view change, state request etc
-is available, the listener is called immediately. This avoids a context switch, given
-that all messages are usually placed in a queue inside the channel and then pulled out
-by the application thread. Here's an example of how this can be used:
-
-JChannel ch=new JChannel();
-ch.setReceiver(new ReceiverAdapter() {
- public void receive(Message msg) {
- System.out.println("-- received " + msg);
- }
-
- public void viewAccepted(View new_view) {
- System.out.println("-- new view: " + new_view);
- }
-});
-ch.connect("demo");
-ch.send(new Message());
-
-Note that ReceiverAdapter is a class which implements the Receiver
-interface, so that only the methods one is interested in have to be
-overridden.
-
-
-Fine-grained interface binding
-------------------------------
-Attributes receive_on_all_interfaces and receive_interfaces enable
-receiving multicast packets on all or a number of interfaces, e.g.
-receive_interfaces="hme0,hme1,192.168.5.3"
-
-
-Retransmission from random member
----------------------------------
-[NAKACK] This is helpful if we have a large group, and want to avoid
-having to ask the original sender of a message for retransmission. By
-asking a random member, we take some potential load off of the
-original sender.
-
-
-Added payload to MethodCall
----------------------------
-Needed to pass additional information with a method call, required
-in JBossCache.
-
-
-Common transport protocol TP
-----------------------------
-UDP and TCP now derive from this, therefore common functionality has
-to be implemented and tested only once. TCP now has many more
-properties supported by TP.
-
-
-Bounded buffer in message bundling
-----------------------------------
-Message bundling has by default always used unbounded buffers. For
-very fast senders, this could result in more and more messages
-being stored in the queue before the bundling thread could dequeue and
-send them, resulting in out-of-memory issues.
-The bundling buffer is now bounded, by default a size of 2000 elements
-is configured. This can be set via
-outgoing_queue_max_size="".
-
-
-Performance improvements
-------------------------
-50% speed improvement for
-RpcDispatcher/MessageDispatcher/RequestCorrelator/MethodCall.
-Most headers now support size() and Streamable, making marshalling and
-unmarshalling faster.
-
-
-Discovery of all clusters in a network
---------------------------------------
-With JGroups/bin/probe.sh or probe.bat, it is now possible to discover *all* clusters running in
-a network. This is useful for
-- management tools that needs to discover the clusters running, and then drill down into each individual cluster
-- for diagnostics and trouble shooting
-Details at http://wiki.jboss.org/wiki/Wiki.jsp?page=Probe
-
-
-View reconciliation (VIEW_SYNC protocol)
-----------------------------------------
-When a coordinator sends out a new view V2 and then leaves (or crashes), it is possible that not
-all members receive that view. So we could end up with some members still having V1, and others having
-V2. The members having V2 will discard all messages from members with V1.
-Note that this is a very rare case, but when it happens, the cluster is screwed up.
-VIEW_SYNC solves this by having each member periodically broadcast its view. When a member receives a view
-that is greater than its own view, it installs it. Thus, all members will eventually end up with the same
-view should the above problem occur. Note that the view sending is done by default every 60 seconds, but it can
-also be triggered through JMX by calling the sendView() method directly.
-See JGroups/doc/ReliableViewInstallation for details.
-
-
-Address canonicalization
-------------------------
-To avoid many instances of Address, 2.2.9 now uses canonicalization, which points the same
-addresses to the same memory location. Therefore most addresses can be garbage collected as soon as they
-have been created, resulting in reduced memory overhead. Can be turned off with -Ddisable_canonicalization=true.
-
-
-TCP_NIO support
----------------
-A new implementation of NIO support has been added. See configuration sample tcp_nio.xml.
-You can configure the number of "reader_threads", "writer_threads" and "processor_threads".
-This should allow for large scale TCP based deployments, compared to TCP.
-
-Bug fixes
----------
-Critical: in rare cases, the digests could be computed incorrectly,
-leading to higher message buffering than necessary
-
-Critical: message bundling (in TP) changed the destination address, so
-when unicast messages had to be retransmitted, because dest=null, the
-receiver would drop them. This would cause UNICAST to stop delivering
-messages, which would accumulate forever ! This happened only in very
-rare cases when a high sustained throughput was encountered (e.g. 20
-million messages sent at the highest possible speed).
-Workaround: set enable_bundling="false" in UDP.
-
-Minor: Apply recv_buf_size/send_buf_size to all TCP socket connections.
-Many smaller bug fixes.
diff -Nru libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.3.txt libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.3.txt
--- libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.3.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.3.txt 1970-01-01 00:00:00.000000000 +0000
@@ -1,89 +0,0 @@
-
-Release Notes JGroups 2.3
-=========================
-
-Version: $Id: ReleaseNotes-2.3.txt,v 1.4 2006/04/26 07:56:01 belaban Exp $
-Author: Bela Ban
-
-
-Multiplexer
------------
-In JBoss we have multiple JGroups channels, one for each application (e.g. JBossCache, ClusterPartition etc).
-
-The goal of the Multiplexer is to combine all stacks with the *same* configuration into one, and have multiple
-apps on top of that same channel.
-
-To do this we have to introduce multiplexing and demultiplexing functionality, ie. each app will have to have
-a unique application ID (a string), and when sending a message, the message has to be tagged with that ID. When
-receiving a message, it will be dispatched to the right app based on the ID attached to the message.
-We require special handling for VIEW and SUSPECT messages: those need to be dispatched to *all* apps.
-State transfer also needs to be handled specially, here we probably have to use thread locals, or change the API (TBD).
-
-When deployed into JBoss, the Multiplexer will be exposed as an MBean, and all apps that depend on it will be deployed
-with dependency injection on the Multiplexer. Of course, the old configuration will still be supported.
-
-The config of the Multiplexer is done via a config file, which lists a number of stacks, each keyed by a name, e.g.
-"udp", "tcp", "tcp-nio" etc. See ./conf/stacks.xml for an example. An app is configured with the name of a stack, e.g.
-"udp", and a reference to the Multiplexer MBean. It will get a proxy channel through which all of its communication
-will take place. The proxy channel (MuxChannel) will mux/demux messages to the real JGroups channel.
-
-The advantage of the Multiplexer is that we can reduce N channels into M where M < N. This means fewer threads, therefore
-fewer context switches, less memory consumption and easier configuration and better support.
-
-
-Partial state transfer
-----------------------
-The Channel.getState() method can now define the ID of a substate to be fetched. This allows applications to
-get only a part of its state, not the entire state.
-See http://www.jgroups.org/javagroupsnew/docs/manual/html/user-channel.html#PartialStateTransfer for details.
-
-
-AUTH
-----
-AUTH is a protocol directly under GMS, which allows to authenticate members who want to join a group. Based on a
-pluggable authentication mechanism, new members are either admitted or rejected. In the latter case, Channel.connect()
-will fail with a security exception.
-For details see JGroups/doc/design/AUTH.txt.
-
-Sequencer based total order protocol
-------------------------------------
-SEQUENCER is an improved implementation of total order, and faster than TOTAL. When sending a message to
-the group, the sender sends the message via unicast to the coordinator, who then broadcasts the message
-(on behalf of the sender) to all members, with a unique sequence number. The coordinator uses FIFO,
-but since there is only 1 sender, this results in total order.
-SEQUENCER can be used for example to maintain identical replicas of a (JMS) queue: senders and receivers can
-send and receive messages to/from any queue replica simultaneously, without affecting the consistency
-of all replicas across the cluster.
-A quick 2 node performance test (perf.Test) with 2 million 1K messages showed
-ca 6500 messages/sec with sequencer.xml, compared to ca. 10500 messages/sec with fc-fast-minimalthreads.xml.
-For details see JGroups/doc/design/SEQUENCER.txt.
-
-ENCRYPT enhancements
---------------------
-The encrypt_entire_message flag (if set to true) will now encrypt the entire message (including the headers),
-as opposed to only encrypting the message buffer. Note that this operation requires serialization of the message,
-so setting this option to true is expensive. Why use it ? When one wants to prevent eavesdroppers from snooping
-out information located in the (non-encrypted) headers, such as sequence numbers.
-
-
-
-Incompatibilities to previous version
--------------------------------------
-Changed method signature of the RpcDispatcher.callRemoteMethod() methods to throw a Throwable.
-Previously they returned the exception as an object, now the exception will be thrown.
-Callers of these methods have to change their code, so this is an incompatible change. However,
-these calls are not used in JBossCache and JBoss Clustering.
-(http://jira.jboss.com/jira/browse/JGRP-154)
-
-
-
-Enhancements and bug fixes
---------------------------
-- FD_SOCK now uses the bind address of the transport unless a bind_addr is specifically
- specified, or the -Dbind.address system property is used.
-- FRAG had a bug that corrupted messages when messages were sent concurrently in multiple threads
-
-
-Documentation
--------------
-- The user's guide has been updated (http://www.jgroups.org/javagroupsnew/docs/manual/html/index.html)
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.4.txt libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.4.txt
--- libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.4.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.4.txt 1970-01-01 00:00:00.000000000 +0000
@@ -1,117 +0,0 @@
-
-Release Notes JGroups 2.4
-=========================
-
-Version: $Id: ReleaseNotes-2.4.txt,v 1.10 2006/10/27 12:58:17 belaban Exp $
-Author: Bela Ban
-
-JGroups 2.4 is a backward compatible release, that is it can replace previous versions (2.2.7 - 2.3) by simply replacing
-the JGroups JAR file. The new features are described below.
-
-The manual is online at http://www.jgroups.org/javagroupsnew/docs/manual/html/index.html
-
-
-FLUSH protocol
---------------
-This essentially adds another virtual synchrony implementation for JGroups (the old one being vsync.xml), however it
-is based on the default stack which has been used for quite a while now, and which is well tested.
-FLUSH is required when we have multiple services sitting on the same Multiplexer, and more than 1 of them requires
-state transfer (for an explanation see JGroups/doc/design/PartialStateTransfer.txt).
-
-
-Partial state transfer
-----------------------
-Sometimes an application doesn't want to transfer the entire state, but just a subset. Example: JBossCache in JBoss,
-where we may want to transfer just a subtree, not the entire tree.
-
-
-Streaming state transfer
-------------------------
-When we need to transfer large state, the existing state transfer requires an application programmer to provide the
-state as a byte[] buffer. If the state is large, or needs to be retrieved by traversing a tree structure (e.g.
-a DOM tree), then providing a byte[] buffer may not make much sense.
-Streaming state transfer provides an InputStream to read state and an OutputStream to write state, and transfer the
-written bytes in *chunks*, so that the memory requirements are smaller. Example: if we have a huge DOM tree, whose
-aggregate size is 2GB (and which has partly been passivated to disk), then the state provider (ie. the coordinator) can
-simply iterate over the DOM tree (activating the parts which have been passivated out to disk), and writing to the
-OutputStream as he traverses the tree. The receiver will simply read from the InputStream and reconstruct the tree
-on his side, possibly again passivating parts to disk. Rather than having to provide a 2GB byte[] buffer (besides the
-state, so the needed memory is ca 4GB temporarily), streaming state transfer transfers the state in chunks of N bytes
-(user configurable).
-Check out the documentation for details and sample code.
-
-
-View bundling
--------------
-When we have many concurrent JOINS, LEAVES or SUSPECTs, then we emit a view for each and every one of them. Say we have
-20 JOINs, then we will have 20 views. With view bundling, we can reduce this by simply handling multiple
-JOIN/LEAVE/SUSPECT requests together as one. This might generate 5 views rather than 20 (config-dependent).
-
-
-Failure detection: FD_PING
---------------------------
-This allows to run a script to probe for liveness of a host. Default is /sbin/ping (ping.exe on Windows). Can be used
-in addition with FD_SOCK/FD.
-
-
-Failure detection: FD_ICMP
---------------------------
-Uses InetAddress.isReachable() to determine whether a given host is reachable. Note that this may or may not use
-ICMP pings, depending on the JDK implementation. Can be used in conjunction with FD_SOCK/FD/FD_PING.
-
-
-Performance measurements
-------------------------
-Performed on 4, 6 and 8 node clusters. Results are available at http://www.jgroups.org/javagroupsnew/perf/Report.html.
-
-
-Use of variables in configuration files
----------------------------------------
-Variables of type ${var:default} or ${var} can now be used in configuration files (both XML and plain text).
-They will get replaced by the result of System.getProperty(var, default). If no system property is set, the
-variables will not get substituted. Note that variables and default values cannot contain characters '{', '}' or ':'.
-
-
-User-defined Marshaller is now used for return values too
----------------------------------------------------------
-Before, a user defined Marshaller in RpcDispatcher was only used for marshalling of a request at the caller and
-unmarshalling of the request at the receiver, but not for marshalling the response at the receiver and
-unmarshalling the response at the caller. In the latter 2 cases, Util.objectTo/FromByteBuffer() was used.
-Now, in all 4 cases, the Marshaller will be used (if set).
-
-
-Optimization in Util.objectTo/FromByteBuffer()
-----------------------------------------------
-We don't create an ObjectInput/OutputStream for null values and simple primitive types.
-
-
-Incompatibilities to previous version
--------------------------------------
-- ExtendedMessageListener: we added 4 methods, so if you used ExtendedReceiverAdapter you're fine. Otherwise you will
- have to recompile. Note that this does *not* affect just linking against JGroups, so if you simply replace your
- jgroups.jar, you're fine
-
-
-Enhancements and bug fixes
---------------------------
-- COMPRESS now uses multiple deflaters/inflaters, this results in more concurrent compression, more performance
-- Multiplexer: few bug fixes (detected by integrating into JBoss), there are now 2 new unit tests that cover the bugs fixed
-- Bug fix for VIEW_SYNC after network partition and subsequent merge (http://jira.jboss.com/jira/browse/JGRP-217)
-- DistributedLockManager now releases locks leftover by a crashed process
-- Multiplexer: problem with state transfer (http://jira.jboss.com/jira/browse/JGRP-280)
-- Issue when members would suspect themselves after a network partition and subsequent merge
- (FD, FD_SOCK and VERIFY_SUSPECT) (http://jira.jboss.com/jira/browse/JGRP-282, http://jira.jboss.com/jira/browse/JGRP-283)
-- Optimization of marshalling in Util.object{To,From}ByteBuffer() (http://jira.jboss.com/jira/browse/JGRP-284)
-- Incorrect suspect warning with FD_SOCK (http://jira.jboss.com/jira/browse/JGRP-285)
-- Multiplexer: view not sent when member crashes (http://jira.jboss.com/jira/browse/JGRP-286)
-- Multiplexer: underlying JChannel not closed in MuxChannel in certain scenarios
- (http://jira.jboss.com/jira/browse/JGRP-288)
-- Pull-the-plug scenarios with TCP, lead to incorrect behavior before, is now fixed:
- - http://jira.jboss.com/jira/browse/JGRP-217
- - http://jira.jboss.com/jira/browse/JGRP-302
- - http://jira.jboss.com/jira/browse/JGRP-304
-
-
-Documentation
--------------
-- The user's guide has been updated (http://www.jgroups.org/javagroupsnew/docs/manual/html/index.html)
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.5.1.txt libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.5.1.txt
--- libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.5.1.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.5.1.txt 1970-01-01 00:00:00.000000000 +0000
@@ -1,34 +0,0 @@
-
-Release Notes JGroups 2.5.1
-===========================
-
-Version: $Id: ReleaseNotes-2.5.1.txt,v 1.1 2007/09/20 08:13:53 belaban Exp $
-Author: Bela Ban
-
-JGroups 2.5.1 is a patch release for 2.5 GA. It contains no new functionality, but only bug fixes.
-
-
-
-Manual
-------
-The manual is online at http://www.jgroups.org/javagroupsnew/docs/manual/html/index.html
-
-
-Bug fixes
----------
-
-AUTH: bug in 2.5 which caused AUTH to fail on second and subsequent JOIN attempts *if* the first
-attempt was rejected by AUTH.
-[http://jira.jboss.com/jira/browse/JGRP-577]
-
-VIEW_SYNC: there was a regression in 2.5, which causes VIEW_SYNC messages to get dropped.
-Note that this bug didn't occur in 2.4.x.
-[http://jira.jboss.com/jira/browse/JGRP-586]
-
-X.509 token not marshalled correctly. This affects ENCRYPT.
-[http://jira.jboss.com/jira/browse/JGRP-576]
-
-The complete list of features and bug fixes can be found at http://jira.jboss.com/jira/browse/JGRP.
-
-
-Bela Ban, Kreuzlingen, Switzerland, Sept 2007
diff -Nru libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.5.txt libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.5.txt
--- libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.5.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.5.txt 1970-01-01 00:00:00.000000000 +0000
@@ -1,193 +0,0 @@
-
-Release Notes JGroups 2.5
-=========================
-
-Version: $Id: ReleaseNotes-2.5.txt,v 1.11 2007/07/03 12:28:05 belaban Exp $
-Author: Bela Ban
-
-JGroups 2.5 is still API-backwards compatible with previous versions (down to 2.2.5). However, there are some changes:
- - JDK 5 is required
- - some older protocols were tossed out, e.g. if you used protocols listed in vsync.xml, they won't be found anymore
-
-The biggest new functionality is the concurrent stack, which allows for concurrent processing of
-unrelated messages.
-
-Below is a summary (with links to the detailed description) of the major new features.
-
-
-
-Concurrent stack
-----------------
-[http://jira.jboss.com/jira/browse/JGRP-181]
-
-The concurrent stack is a major performance improvement for clusters where multiple nodes are sending messages at the
-same time. Up to and including 2.4.x, all messages from all senders were placed into a single queue and delivered in
-order of reception (FIFO) to the application.
-
-This means that, for a given message M, all messages ahead of M had to get processed before M could get processed, even
-if some of those messages were from different senders.
-
-Now, messages from different senders are processed concurrently. This is done through 2 thread pools, one for default
-messages and another one for out-of-band messages. Both pools can be configured through XML, e.g. core and max number
-of threads, rejection policy ("run", "discard", "discardoldest" etc), whether to use a queue and if so, queue length etc.
-
-The concurrent stack will improve performance dramatically when
-- there are multiple senders and/or
-- the processing of a message takes some time.
-
-In a cluster of N with N senders, X messages and T think time/message, we have seen total processing time of
-all messages drop from X * N * T to (X * T) + !
-
-
-
-Out-of-band (unordered) messages
---------------------------------
-[http://jira.jboss.com/jira/browse/JGRP-205]
-
-In some cases, messages do not need to get delivered in the order in which they were sent. For example, if a sender
-A sends messages M1 --> M2 --> M3 --> M4 --> M5 (--> means followed by), and all messages except M3 (heartbeat) and
-M5 (discovery request) are regular messages, then all 5 messages will be delivered sequentially.
-This means that M3 has to wait for M1 and M2 to get processed, and M5 has to wait for all 4 messages ahead of it, until
-it gets processed.
-An out-of-band (OOB) message is one that is tagged:
-Message msg;
-msg.setFlag(Message.OOB)
-
-An OOB message is reliably transmitted, that is if the network drops it, JGroups will retransmit it. However, the ordering
-defined by the stack is ignored for an OOB messages, e.g. in the above case, M3 and M5 can be delivered out of sequence
-with regard to the other messages.
-
-This is perfect for messages like heartbeats or discovery requests or responses, which do not need to be delivered in
-FIFO order with respect to other messages from the same sender. If a message is tagged as OOB, it will be handled by the
-OOB thread pool rather than the regular thread pool.
-
-
-
-Concurrent Multiplexer
-----------------------
-[http://jira.jboss.com/jira/browse/JGRP-415]
-
-A similar problem that the concurrent stack solved, was encountered in the Multiplexer: requests to different services,
-but sent by the same sender, were processed sequentially (even with the concurrent stack, where messages from the same sender
-are processed in FIFO order).
-
-This was solved by adding a thread pool to the Multiplexer, which handles requests to different services concurrently,
-even if they were sent by the same sender.
-
-
-
-Simplified and fast flow control (SFC)
---------------------------------------
-[http://jira.jboss.com/jira/browse/JGRP-402]
-
-SFC is a simple flow control protocol for group (= multipoint) messages. It is simpler than FC, but as the performance
-report (http://www.jgroups.org/javagroupsnew/perfnew/Report.html) shows, it has about the same performance as FC, so
-we may combine the 2 in the future. Note, however, that SFC does not apply flow control to unicast messages, whereas
-FC does.
-
-Every sender has max_credits bytes for sending multicast messages to the group.
-
-Every multicast message (we don't consider unicast messages) decrements max_credits by its size.
-When max_credits falls below 0, the sender asks all receivers for new credits and blocks
-until *all* credits have been received from all members.
-
-When the receiver receives a credit request, it checks whether it has received max_credits bytes from the requester since
-the last credit request. If yes, it sends new credits to the requester and resets the max_credits for the requester.
-Else, it takes a note of the credit request from P and - when max_credits bytes have finally been received from P - it
-sends the credits to P and resets max_credits for P.
-
-The maximum amount of memory for received messages is therefore * max_credits.
-
-The relationship with STABLE is as follows: when a member Q is slow, it will prevent STABLE from collecting messages above
-the ones seen by Q (everybody else has seen more messages). However, because Q will *not* send credits back to the senders
-until it has processed all messages worth max_credits bytes, the senders will block. This in turn allows STABLE to
-progress and eventually garbage collect most messages from all senders. Therefore, SFC and STABLE complement each other,
-with SFC blocking senders so that STABLE can catch up.
-
-
-
-Full support for virtual synchrony
-----------------------------------
-[http://jira.jboss.com/jira/browse/JGRP-341]
-
-The FLUSH protocol in 2.4.x supported virtual synchrony ([1]), but the flush phase didn't include a message
-reconciliation part. This has now been added in 2.5.
-
-FLUSH is very important for the Multiplexer, where a flush phase is run whenever a member joins, leaves or crashes, or
-when a new member acquires the state from an existing member (state transfer).
-
-
-
-Simple failure detection protocol (FD_ALL)
-------------------------------------------
-[http://jira.jboss.com/jira/browse/JGRP-395]
-
-Failure detection based on simple heartbeat protocol. Every member periodically multicasts a heartbeat.
-Every member also maintains a table of all members (minus itself).
-When data or a heartbeat from P are received, we reset the timestamp for P to the current time.
-Periodically, we check for expired members, and suspect those.
-
-Example:
-
-In the exampe above, we send a heartbeat every 3 seconds and suspect members if we haven't received a heartbeat
-(or traffic) for more than 10 seconds. Note that since we check the timestamps every 'interval' milliseconds,
-we will suspect a member after roughly 4 * 3s == 12 seconds. If we set the timeout to 8500, then we would suspect
-a member after 3 * 3 secs == 9 seconds.
-
-FD_ALL is interchangeable with FD.
-
-
-
-Better naming of threads
-------------------------
-Almost all threads have the cluster name and local address appended to their names. This is good if we have multiple
-clusters in the same JVM (e.g. in JBossAS), allowing for more meaningful stack traces (knowing which thread
-belongs to which cluster).
-
-
-No need for escape characters in stack configuration
-----------------------------------------------------
-Now backslashes are not needed for protocol attribute values, e.g. to define an IPv6 mcast_addr, the following works:
-
-
-
-The colons in mcast_addr do not need to be escaped with a backslash any longer. Note that '(', ')' and '=' are
-still reserved characters and cannot be used as part of an attribute name or value.
-
-
-
-Switch to java.util.concurrent classes (JDK 5)
-----------------------------------------------
-[http://jira.jboss.com/jira/browse/JGRP-391]
-
-We switched from concurrent.jar to java.util.concurrent, resulting in slightly better performance and we could also
-drop a JAR (concurrent.jar).
-
-
-
-Manual
-------
-The manual is online at http://www.jgroups.org/javagroupsnew/docs/manual/html/index.html
-
-
-Performance
------------
-
-We measured the performance of the 2.5 stack in a cluster of 4, 6 and 8 nodes. The results are discussed in
-http://www.jgroups.org/javagroupsnew/perfnew/Report.html.
-
-We'll present more comprehensive performance numbers (sepecially for the concurrent stack) in 2.6.
-
-
-Bug fixes
----------
-The list of features and bug fixes can be found at http://jira.jboss.com/jira/browse/JGRP.
-
-
-Bela Ban, Kreuzlingen, Switzerland, June 2007
-
-
-[1] Reliable communication in presence of failures.
- Kenneth P. Birman, Thomas A.Joseph.
- ACM Transactions on Computer Systems, Vol. 5, No. 1, Feb. 1987
-
diff -Nru libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.6.txt libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.6.txt
--- libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.6.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.6.txt 1970-01-01 00:00:00.000000000 +0000
@@ -1,124 +0,0 @@
-
-Release Notes JGroups 2.6
-=========================
-
-Version: $Id: ReleaseNotes-2.6.txt,v 1.3 2007/11/06 12:32:33 belaban Exp $
-Author: Bela Ban
-
-JGroups 2.6 is still API-backwards compatible with previous versions (down to 2.2.5).
-
-Below is a summary (with links to the detailed description) of the major new features.
-
-
-Join and state transfer
------------------------
-[http://jira.jboss.com/jira/browse/JGRP-236]
-
-We added another connect() method in JChannel, which combines joining a cluster and fetching the state from the
-coordinator into one method. This is especially useful when we have FLUSH in the stack; thus we only have to use 1 rather
-than 2 (1 for JOIN, 1 for state transfer) flush phases.
-
-
-Improved ReplicatedHashMap
---------------------------
-[http://jira.jboss.com/jira/browse/JGRP-581]
-
-ReplicatedHashMap was converted to use generics, and java.util.concurrent.ConcurrentHashMap. It therefore supports 4 new
-methods putIfAbsent(), remove() and the two replace() methods.
-Developers can choose whether to use asynchronous or synchronous replication, and also pick the timeout for synchronous
-calls.
-This class supercedes ReplicatedHashtable and DistributedHashtable, which will be removed in version 3.0.
-
-
-Reincarnation issue
--------------------
-[http://jira.jboss.com/jira/browse/JGRP-130]
-
-Using the GMS.reject_join_from_existing_member (default=false) property, we can reject a JOIN request from a reincarnated
-member X who crashed, but has not yet been removed (e.g. due to a high timeout in FD). The member would have to retry,
-and would only succeed when (the old) X has been excluded from the cluster.
-For shunned members who use AUTO_RECONNECT, we loop until this is true [http://jira.jboss.com/jira/browse/JGRP-584].
-
-
-New transport property 'bind_interface'
----------------------------------------
-[http://jira.jboss.com/jira/browse/JGRP-579]
-
-This can be used when multipler network interfaces have the *same* IP address, to define the interface to get used, e.g
-bind_addr="192.168.2.5" bind_interface="eth1". Useful e.g. with IP Bonding on Linux.
-
-
-FLUSH simplification
---------------------
-[http://jira.jboss.com/jira/browse/JGRP-598]
-
-Removed 2 phases from FLUSH protocol, which simplified code and made FLUSH faster.
-
-
-Unicast bundling can be disabled at the transport level
--------------------------------------------------------
-[http://jira.jboss.com/jira/browse/JGRP-429]
-
-When dealing with latency sensitive applications, we may want to disable message bundling for *responses* (but not for
-requests, as requests might carry large payloads). This can be done via the enable_unicast_bundling (default=true)
-property.
-
-
-RpcDispatcher can now filter responses as they arrive
-------------------------------------------------------
-[http://jira.jboss.com/jira/browse/JGRP-518]
-
-There's a new callRemoteMethods() method taking an RspFilter, which is called whenever a response has been received,
-allowing a request to return based on a condition (e.g. the first non null return value) before all responses
-have been received.
-
-
-Ability to add data to a view
------------------------------
-[http://jira.jboss.com/jira/browse/JGRP-597]
-
-Arbitrary data can be added to a View, which now has a hashmap. Keys and values need to be serializable.
-
-
-Improved thread naming
-----------------------
-[http://jira.jboss.com/jira/browse/JGRP-570]
-
-All threads now hae meaningful names, including their local address and cluster name. This makes it easier to
-read stack traces, when we have multiple channels (e.g. in JBoss).
-In addition, all threads are now created by the same thread pool.
-
-
-Manual
-------
-The manual is online at http://www.jgroups.org/javagroupsnew/docs/manual/html/index.html
-
-
-Performance
------------
-Links to performance tuning: http://wiki.jboss.org/wiki/Wiki.jsp?page=PerfTuning
-
-
-
-Bug fixes
----------
-AUTH: bug in 2.5 which caused AUTH to fail on second and subsequent JOIN attempts *if* the first
-attempt was rejected by AUTH.
-[http://jira.jboss.com/jira/browse/JGRP-577]
-
-VIEW_SYNC: there was a regression in 2.5, which causes VIEW_SYNC messages to get dropped.
-Note that this bug didn't occur in 2.4.x.
-[http://jira.jboss.com/jira/browse/JGRP-586]
-
-X.509 token not marshalled correctly. This affects ENCRYPT.
-[http://jira.jboss.com/jira/browse/JGRP-576]
-
-The complete list of features and bug fixes can be found at http://jira.jboss.com/jira/browse/JGRP.
-
-
-Bela Ban, Kreuzlingen, Switzerland
-Vladimir Blagojevic, Toronto, Canada
-
-Nov 2007
-
-
diff -Nru libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.7.txt libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.7.txt
--- libjgroups-java-2.7.0.GA/doc/ReleaseNotes-2.7.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/ReleaseNotes-2.7.txt 1970-01-01 00:00:00.000000000 +0000
@@ -1,213 +0,0 @@
-
-Release Notes JGroups 2.7
-=========================
-
-Version: $Id: ReleaseNotes-2.7.txt,v 1.6 2008/11/13 08:18:41 belaban Exp $
-Author: Bela Ban
-
-JGroups 2.7 is still API-backwards compatible with previous versions (down to 2.2.7).
-
-This is a big release, with close to 200 JIRA issues fixed and major new functionality.
-
-Below is a summary (with links to the detailed description) of the major new features.
-
-
-Features
-========
-
-Shared transport
-----------------
-[https://jira.jboss.org/jira/browse/JGRP-631]
-
-Multiple channels can now share the same transport (and still have different stack configurations on top). This
-replaces the Multiplexer, which is not supported any longer as of 2.7.
-
-See http://www.jgroups.org/javagroupsnew/docs/manual/html/user-advanced.html#d0e2204 for details.
-
-
-
-Converted unit tests from JUnit to TestNG
------------------------------------------
-[https://jira.jboss.org/jira/browse/JGRP-410]
-
-This cut down the time to run all tests from 2.5 hours to 15 minutes !
-
-
-Use of annotations to provide JMX management information
---------------------------------------------------------
-[https://jira.jboss.org/jira/browse/JGRP-723]
-[https://jira.jboss.org/jira/browse/JGRP-408]
-
-By annotating a protocol as @ManagedResource, an attribute as @ManagedAttribute or an operation as
-@ManagedOperation, we can simply expose JMX management information.
-
-This change allowed us to remove the parallel JMX class hierarchy (org.jgroups.jmx package), and dramatically
-reduced the effort needed to expose protocols via JMX.
-
-Credits for the initial implementation go to Chris Mills.
-
-
-
-Use of annotations to set properties
-------------------------------------
-[https://jira.jboss.org/jira/browse/JGRP-765]
-
-Instead of implementing setProperties() in each protocol, parsing the input string and converting it to a variable, we
-now use the @Property annoation to mark an attribute or getter/setter method. This way, input strings are
-automatically mapped to the corresponding fields in a protocol.
-
-This allowed us to remove a lot of boilerplate code.
-
-In addition, we now generate the protocol list
-documentation (http://www.jgroups.org/javagroupsnew/docs/manual/html/protlist.html) from the @Property annotations.
-The benefit is that we need to maintain the documentation only in one place (the code) instead of two, and we now
-have a complete documentation of all protocol properties.
-
-
-Ability to replace thread pools with custom thread pools
---------------------------------------------------------
-[https://jira.jboss.org/jira/browse/JGRP-632]
-
-This allows (for example) system integrators to use the thread pools they already have in their applications. It
-also gives greater control over thread pool management, e.g. a provider can make all threads in a pool daemon threads.
-
-
-Allow flushing of a cluster subset
-----------------------------------
-[https://jira.jboss.org/jira/browse/JGRP-661]
-
-Rather than flushing the entire cluster, we can now provide a list of target members for the FLUSH. This is needed
-for example for buddy replication in JBossCache.
-
-
-Performance improvements
-------------------------
-[https://jira.jboss.org/jira/browse/JGRP-846]
-[https://jira.jboss.org/jira/browse/JGRP-847]
-[https://jira.jboss.org/jira/browse/JGRP-805]
-[https://jira.jboss.org/jira/browse/JGRP-806]
-[https://jira.jboss.org/jira/browse/JGRP-829]
-[https://jira.jboss.org/jira/browse/JGRP-813]
-
-
-http://www.jgroups.org/javagroupsnew/docs/performance.html shows that we can get 150MB/sec/node on a 4 node
-cluster connected to a 1GB switch with udp.xml (IP multicasting) on 2.7. This means we get an aggregate cluster
-throughput of 600MB/sec !
-
-2.7 is ca 30-40% faster than 2.6 !
-
-
-FC: max block times depending on message size
----------------------------------------------
-[https://jira.jboss.org/jira/browse/JGRP-804]
-
-We can now set the max time to block for a given message, e.g. block 10ms max for messages up to 10K, 100ms for messages
-up to 1MB, 500ms for messages up to 10MB and 2000ms for messages larger than that.
-
-This means that - regardless of missing credits - messages will be sent after the deadline (max block time) has
-elapsed. This adds more predictability as to when messages are sent, but it also can lead to OOMEs if those values
-are too low, defying the purpose of flow control.
-
-
-UNICAST/NAKACK: eager lock release
-----------------------------------
-[https://jira.jboss.org/jira/browse/JGRP-656]
-
-Better performance in cases where the receiver of a message uses the calling thread to send a message down the stack.
-In this case, the lock will be release as soon as send() is called, releasing the lock and allowing threads with
-messages from the same sender to proceed.
-
-
-GossipRouter / GossipClient: make sockets non-blocking
-------------------------------------------------------
-[https://jira.jboss.org/jira/browse/JGRP-702]
-[https://jira.jboss.org/jira/browse/JGRP-852]
-
-Can now be configured to use non blocking socket close, connect and read/write
-
-
-Paralellize discovery phase
----------------------------
-[https://jira.jboss.org/jira/browse/JGRP-375]
-
-
-Pluggable Probe
----------------
-[https://jira.jboss.org/jira/browse/JGRP-832]
-
-This allows for users to write their own plugins which respond to a ping (a probe) and return (for example)
-application specific information.
-
-Details are at http://www.jboss.org/community/docs/DOC-11689 (towards the bottom of the page).
-
-
-
-
-
-Bug fixes
-=========
-
-FD: nodes would not get suspected if traffic from different nodes was received
-------------------------------------------------------------------------------
-[https://jira.jboss.org/jira/browse/JGRP-746]
-
-Traffic from *any* node was counted as a heartbeat. This is incorrect as only traffic from the pinged member
-should count as heartbeat.
-
-FRAG/FRAG2: fragment list is not cleared for crashed member (can lead to memory leak)
--------------------------------------------------------------------------------------
-[https://jira.jboss.org/jira/browse/JGRP-800]
-
-NAKACK: regular message not delivered (in some cases) until new message arrives
--------------------------------------------------------------------------------
-[https://jira.jboss.org/jira/browse/JGRP-781]
-
-STATE_TRANSFER: state transfer broken for large states
-------------------------------------------------------
-[https://jira.jboss.org/jira/browse/JGRP-774]
-
-Concurrent connect of multiple channels with shared transport fails
--------------------------------------------------------------------
-[https://jira.jboss.org/jira/browse/JGRP-849]
-
-Eliminate Linux cross-talk in MPING
------------------------------------
-[https://jira.jboss.org/jira/browse/JGRP-836]
-
-FLUSH fixes
------------
-[https://jira.jboss.org/jira/browse/JGRP-756]
-[https://jira.jboss.org/jira/browse/JGRP-759]
-[https://jira.jboss.org/jira/browse/JGRP-700]
-[https://jira.jboss.org/jira/browse/JGRP-622]
-
-FD_SOCK: fixes
---------------
-[https://jira.jboss.org/jira/browse/JGRP-841]
-[https://jira.jboss.org/jira/browse/JGRP-845]
-[https://jira.jboss.org/jira/browse/JGRP-794]
-[https://jira.jboss.org/jira/browse/JGRP-745]
-
-NAKACK: merging of digests is incorrect
----------------------------------------
-[https://jira.jboss.org/jira/browse/JGRP-699]
-
-
-
-
-
-Manual
-------
-The manual is online at http://www.jgroups.org/javagroupsnew/docs/manual/html/index.html
-
-
-
-The complete list of features and bug fixes can be found at http://jira.jboss.com/jira/browse/JGRP.
-
-
-Bela Ban, Kreuzlingen, Switzerland
-Vladimir Blagojevic, Toronto, Canada
-
-Nov 2008
-
-
diff -Nru libjgroups-java-2.7.0.GA/doc/RULES libjgroups-java-2.12.2.Final/doc/RULES
--- libjgroups-java-2.7.0.GA/doc/RULES 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/RULES 2011-10-18 11:22:35.000000000 +0000
@@ -1,5 +1,4 @@
-# $Id: RULES,v 1.7 2008/03/13 08:11:32 belaban Exp $
Rules developers should adhere to
---------------------------------
diff -Nru libjgroups-java-2.7.0.GA/doc/tests/ManualTests.txt libjgroups-java-2.12.2.Final/doc/tests/ManualTests.txt
--- libjgroups-java-2.7.0.GA/doc/tests/ManualTests.txt 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/tests/ManualTests.txt 2011-10-18 11:22:35.000000000 +0000
@@ -1,4 +1,3 @@
-$Id: ManualTests.txt,v 1.13 2009/01/05 12:14:00 belaban Exp $
Group Membership Service (GMS) Protocol
@@ -12,7 +11,6 @@
- All the tests use the JGroups/Demos/Draw program
- All tests should be run with both FD and FD_SOCK
- All test should be run with FLUSH (flush-udp.xml) and without FLUSH (udp.xml)
-- When FLUSH is used tests should be run with both Channel.BLOCK turned off and on
When *FD only* is used make sure that timeout and max_tries are relatively low. For example,
@@ -139,9 +137,9 @@
-------
- Start A, B
-- Shun A (CTRL-Z and then fg)
-- When A has rejoined the group, kill A
-- The view needs to be {B} now
+- Suspend A (CTRL-Z)
+- Wait until B shows membershiop of 1, then resume A (fg)
+- A and B needs to merge back into a group of 2
diff -Nru libjgroups-java-2.7.0.GA/doc/todo.lst libjgroups-java-2.12.2.Final/doc/todo.lst
--- libjgroups-java-2.7.0.GA/doc/todo.lst 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/todo.lst 2011-10-18 11:22:35.000000000 +0000
@@ -1,4 +1,3 @@
-$Id: todo.lst,v 1.22 2005/06/06 07:47:57 belaban Exp $
diff -Nru libjgroups-java-2.7.0.GA/doc/tutorial/.cvsignore libjgroups-java-2.12.2.Final/doc/tutorial/.cvsignore
--- libjgroups-java-2.7.0.GA/doc/tutorial/.cvsignore 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/tutorial/.cvsignore 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1 @@
+build
diff -Nru libjgroups-java-2.7.0.GA/doc/tutorial/en/master.xml libjgroups-java-2.12.2.Final/doc/tutorial/en/master.xml
--- libjgroups-java-2.7.0.GA/doc/tutorial/en/master.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/tutorial/en/master.xml 2011-10-18 11:22:35.000000000 +0000
@@ -9,8 +9,7 @@
JGroups tutorial
- $Date: 2007/07/18 14:26:26 $
- $Id: master.xml,v 1.4 2007/07/18 14:26:26 belaban Exp $
+ 2009Bela
@@ -30,12 +29,15 @@
Bela Ban
- 2006-2007
+ 2006-2011Red Hat Inc
- This document is copyrighted. Copies are allowed for
- personal use. Redistribution only with written permission of the author(s).
+ This document is licensed under the
+
+ Creative Commons Attribution-ShareAlike (CC-BY-SA) 3.0
+
+
diff -Nru libjgroups-java-2.7.0.GA/doc/tutorial/en/modules/installation.xml libjgroups-java-2.12.2.Final/doc/tutorial/en/modules/installation.xml
--- libjgroups-java-2.7.0.GA/doc/tutorial/en/modules/installation.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/doc/tutorial/en/modules/installation.xml 2011-10-18 11:22:35.000000000 +0000
@@ -28,10 +28,6 @@
INSTALL.html: detailed configuration instructions plus trouble shooting
- commons-logging.jar: required JAR that provides general logging. This
- might get dropped in 3.0
-
-
jgroups-all.jar (required): JGroups functionality, including demo and junit
apps. If a smaller JAR is required, this can be done by downloading the source distribution and
invoking the "jar" target, which creates a jgroups-core.jar file (ca 1MB).
@@ -76,7 +72,7 @@
Configuration
- Add jgroups-all.jar and commons-logging.jar to your CLASSPATH. If you use the log4j logging system, you also
+ Add jgroups-all.jar to your CLASSPATH. If you use the log4j logging system, you also
have to add log4j.jar (this is not necessary if you use the JDK logging system).
@@ -107,7 +103,7 @@
$ java -jar jgroups-all.jar
Version: 2.5.0
- CVS: $Id: installation.xml,v 1.3 2007/07/16 11:04:12 belaban Exp $
+ CVS: $Id: installation.xml,v 1.4 2009/05/13 13:22:09 belaban Exp $
History: (see doc/history.txt for details)
diff -Nru libjgroups-java-2.7.0.GA/EULA libjgroups-java-2.12.2.Final/EULA
--- libjgroups-java-2.7.0.GA/EULA 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/EULA 1970-01-01 00:00:00.000000000 +0000
@@ -1,109 +0,0 @@
-// $Id: EULA,v 1.1 2006/11/02 08:04:26 belaban Exp $
-
-LICENSE AGREEMENT
-JBOSS(r)
-
-This License Agreement governs the use of the Software Packages and any updates to the Software
-Packages, regardless of the delivery mechanism. Each Software Package is a collective work
-under U.S. Copyright Law. Subject to the following terms, Red Hat, Inc. ("Red Hat") grants to
-the user ("Client") a license to the applicable collective work(s) pursuant to the
-GNU Lesser General Public License v. 2.1 except for the following Software Packages:
-(a) JBoss Portal Forums and JBoss Transactions JTS, each of which is licensed pursuant to the
-GNU General Public License v.2;
-
-(b) JBoss Rules, which is licensed pursuant to the Apache License v.2.0;
-
-(c) an optional download for JBoss Cache for the Berkeley DB for Java database, which is licensed under the
-(open source) Sleepycat License (if Client does not wish to use the open source version of this database,
-it may purchase a license from Sleepycat Software);
-
-and (d) the BPEL extension for JBoss jBPM, which is licensed under the Common Public License v.1,
-and, pursuant to the OASIS BPEL4WS standard, requires parties wishing to redistribute to enter various
-royalty-free patent licenses.
-
-Each of the foregoing licenses is available at http://www.opensource.org/licenses/index.php.
-
-1. The Software. "Software Packages" refer to the various software modules that are created and made available
-for distribution by the JBoss.org open source community at http://www.jboss.org. Each of the Software Packages
-may be comprised of hundreds of software components. The end user license agreement for each component is located in
-the component's source code. With the exception of certain image files identified in Section 2 below,
-the license terms for the components permit Client to copy, modify, and redistribute the component,
-in both source code and binary code forms. This agreement does not limit Client's rights under,
-or grant Client rights that supersede, the license terms of any particular component.
-
-2. Intellectual Property Rights. The Software Packages are owned by Red Hat and others and are protected under copyright
-and other laws. Title to the Software Packages and any component, or to any copy, modification, or merged portion shall
-remain with the aforementioned, subject to the applicable license. The "JBoss" trademark, "Red Hat" trademark, the
-individual Software Package trademarks, and the "Shadowman" logo are registered trademarks of Red Hat and its affiliates
-in the U.S. and other countries. This agreement permits Client to distribute unmodified copies of the Software Packages
-using the Red Hat trademarks that Red Hat has inserted in the Software Packages on the condition that Client follows Red Hat's
-trademark guidelines for those trademarks located at http://www.redhat.com/about/corporate/trademark/. Client must abide by
-these trademark guidelines when distributing the Software Packages, regardless of whether the Software Packages have been modified.
-If Client modifies the Software Packages, then Client must replace all Red Hat trademarks and logos identified at
-http://www.jboss.com/company/logos, unless a separate agreement with Red Hat is executed or other permission granted.
-Merely deleting the files containing the Red Hat trademarks may corrupt the Software Packages.
-
-3. Limited Warranty. Except as specifically stated in this Paragraph 3 or a license for a particular
-component, to the maximum extent permitted under applicable law, the Software Packages and the
-components are provided and licensed "as is" without warranty of any kind, expressed or implied,
-including the implied warranties of merchantability, non-infringement or fitness for a particular purpose.
-Red Hat warrants that the media on which Software Packages may be furnished will be free from defects in
-materials and manufacture under normal use for a period of 30 days from the date of delivery to Client.
-Red Hat does not warrant that the functions contained in the Software Packages will meet Client's requirements
-or that the operation of the Software Packages will be entirely error free or appear precisely as described
-in the accompanying documentation. This warranty extends only to the party that purchases the Services
-pertaining to the Software Packages from Red Hat or a Red Hat authorized distributor.
-
-4. Limitation of Remedies and Liability. To the maximum extent permitted by applicable law, the remedies
-described below are accepted by Client as its only remedies. Red Hat's entire liability, and Client's
-exclusive remedies, shall be: If the Software media is defective, Client may return it within 30 days of
-delivery along with a copy of Client's payment receipt and Red Hat, at its option, will replace it or
-refund the money paid by Client for the Software. To the maximum extent permitted by applicable law,
-Red Hat or any Red Hat authorized dealer will not be liable to Client for any incidental or consequential
-damages, including lost profits or lost savings arising out of the use or inability to use the Software,
-even if Red Hat or such dealer has been advised of the possibility of such damages. In no event shall
-Red Hat's liability under this agreement exceed the amount that Client paid to Red Hat under this
-Agreement during the twelve months preceding the action.
-
-5. Export Control. As required by U.S. law, Client represents and warrants that it:
-(a) understands that the Software Packages are subject to export controls under the
-U.S. Commerce Department's Export Administration Regulations ("EAR");
-
-(b) is not located in a prohibited destination country under the EAR or U.S. sanctions regulations
-(currently Cuba, Iran, Iraq, Libya, North Korea, Sudan and Syria);
-
-(c) will not export, re-export, or transfer the Software Packages to any prohibited destination, entity,
-or individual without the necessary export license(s) or authorizations(s) from the U.S. Government;
-
-(d) will not use or transfer the Software Packages for use in any sensitive nuclear, chemical or
-biological weapons, or missile technology end-uses unless authorized by the U.S. Government by
-regulation or specific license;
-
-(e) understands and agrees that if it is in the United States and exports or transfers the Software
-Packages to eligible end users, it will, as required by EAR Section 740.17(e), submit semi-annual
-reports to the Commerce Department's Bureau of Industry & Security (BIS), which include the name and
-address (including country) of each transferee;
-
-and (f) understands that countries other than the United States may restrict the import, use, or
-export of encryption products and that it shall be solely responsible for compliance with any such
-import, use, or export restrictions.
-
-6. Third Party Programs. Red Hat may distribute third party software programs with the Software Packages
-that are not part of the Software Packages and which Client must install separately. These third party
-programs are subject to their own license terms. The license terms either accompany the programs or
-can be viewed at http://www.redhat.com/licenses/. If Client does not agree to abide by the applicable
-license terms for such programs, then Client may not install them. If Client wishes to install the programs
-on more than one system or transfer the programs to another party, then Client must contact the licensor
-of the programs.
-
-7. General. If any provision of this agreement is held to be unenforceable, that shall not affect the
-enforceability of the remaining provisions. This License Agreement shall be governed by the laws of the
-State of North Carolina and of the United States, without regard to any conflict of laws provisions,
-except that the United Nations Convention on the International Sale of Goods shall not apply.
-
-Copyright 2006 Red Hat, Inc. All rights reserved.
-"JBoss" and the JBoss logo are registered trademarks of Red Hat, Inc.
-All other trademarks are the property of their respective owners.
-
- Page 1 of 1 18 October 2006
-
diff -Nru libjgroups-java-2.7.0.GA/.gitignore libjgroups-java-2.12.2.Final/.gitignore
--- libjgroups-java-2.7.0.GA/.gitignore 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/.gitignore 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,15 @@
+*~
+*.iws
+*.ipr
+*.iml
+.project
+.classpath
+.idea/
+.idea
+classes/
+build.properties
+dist/
+atlassian*
+keystore/
+tmp/
+bla*.java
diff -Nru libjgroups-java-2.7.0.GA/INSTALL.html libjgroups-java-2.12.2.Final/INSTALL.html
--- libjgroups-java-2.7.0.GA/INSTALL.html 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/INSTALL.html 2011-10-18 11:22:35.000000000 +0000
@@ -5,7 +5,7 @@
content="text/html; charset=iso-8859-1">
- JGroups 2.2.X Installation
+ JGroups 2.8.x Installation
jgroups-all.jar: the JGroups library including the demos
-
commons-logging.jar
-
concurrent.jar
-
log4j.jar
-
jmxri.jar: the JMX reference implementation, this is not needed
-if running in JDK 5 or higher
jgroups.bat/jgroups.sh: convenience script to start demo programs
(set the CLASSPATH etc) - see below
Some sample configuration files, udp.xml, mping.xml etc
@@ -95,8 +90,6 @@
test cases
xalan.jar : to format the
output of the JUnit tests using an XSLT converter to HTML
-
concurrent.jar
-
commons-logging.jar
log4j.jar
etc
@@ -166,7 +159,7 @@
You should see the following output (more or less) if the class is
found:
-
Version: 2.2.8 RC1 CVS: $Id: INSTALL.html,v 1.9 2006/12/27 10:17:58 belaban Exp $ History: (see doc/history.txt for details)
+
Version: 2.2.8 RC1 CVS: $Id: INSTALL.html,v 1.11 2009/12/02 13:00:10 belaban Exp $ History: (see doc/history.txt for details)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff -Nru libjgroups-java-2.7.0.GA/jgroups-pom.xml libjgroups-java-2.12.2.Final/jgroups-pom.xml
--- libjgroups-java-2.7.0.GA/jgroups-pom.xml 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/jgroups-pom.xml 1970-01-01 00:00:00.000000000 +0000
@@ -1,72 +0,0 @@
-
-
-
- 4.0.0
- jgroups
- jgroups
- JGroups
- 2.7.0.GA
- http://www.jgroups.org
-
- src
- tests
-
-
- conf
-
- **/*.xml
-
-
-
-
-
- maven-compiler-plugin
-
-
- 1.5
-
- functional/**/*.java
-
-
-
-
- maven-surefire-plugin
-
- true
-
-
-
-
-
-
- jboss
- JBoss Inc. Repository
- http://repository.jboss.com/maven2/
-
- true
-
-
-
-
-
- ant
- ant
- 1.6.5
- true
-
-
- ant
- ant-junit
- 1.6.5
- true
-
-
- junit
- junit
- 3.8.1
- test
-
-
-
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/pom.xml libjgroups-java-2.12.2.Final/pom.xml
--- libjgroups-java-2.7.0.GA/pom.xml 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/pom.xml 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,228 @@
+
+ 4.0.0
+ org.jgroups
+ jgroups
+ bundle
+ JGroups
+ 2.12.2.Final
+ http://www.jgroups.org
+
+ Reliable cluster communication toolkit
+
+
+
+ JBoss, a division of Red Hat
+ http://www.jboss.org
+
+
+
+
+ Bela Ban
+ belaban@yahoo.com
+
+
+
+
+
+ GNU Lesser General Public License 2.1
+ http://www.opensource.org/licenses/lgpl-2.1.php
+
+
+
+
+ cvs -d:pserver:anonymous@javagroups.cvs.sourceforge.net:/cvsroot/javagroups
+ cvs -d:ext:USER@javagroups.cvs.sf.net/cvsroot/javagroups
+ cvs -d:pserver:anonymous@javagroups.cvs.sourceforge.net:/cvsroot/javagroups
+
+
+
+ jira
+ https://jira.jboss.com/jira/browse/JGRP
+
+
+
+
+ jboss-releases-repository
+ JBoss Releases Repository
+ https://repository.jboss.org/nexus/service/local/staging/deploy/maven2/
+
+
+
+
+
+ jboss-public-repository-group
+ JBoss Public Maven Repository Group
+ https://repository.jboss.org/nexus/content/groups/public/
+ default
+
+ true
+ never
+
+
+ true
+ never
+
+
+
+
+
+
+ bsh
+ bsh
+ 1.2b7
+ true
+ compile
+
+
+ log4j
+ log4j
+ 1.2.14
+ true
+ compile
+
+
+
+
+
+ src
+
+
+ conf
+
+ *.xml
+
+
+ *-service.xml
+
+
+
+ ${project.build.outputDirectory}/schema
+
+
+
+
+ maven-compiler-plugin
+
+
+ 1.6
+
+ org/jgroups/util/JUnitXMLReporter.java
+
+
+
+
+
+ maven-antrun-plugin
+
+
+ compile
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ xalan
+ xalan
+ 2.7.1
+
+
+ xalan
+ serializer
+ 2.7.1
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 2.1.1
+ true
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ conf/manifest.mf
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ true
+
+
+
+ schema;version=${project.version},
+ org.jgroups;version=${project.version},
+ org.jgroups.annotations;version=${project.version},
+ org.jgroups.auth;version=${project.version},
+ org.jgroups.blocks;version=${project.version},
+ org.jgroups.blocks.mux;version=${project.version},
+ org.jgroups.blocks.locking;version=${project.version},
+ org.jgroups.blocks.executor;version=${project.version},
+ org.jgroups.client;version=${project.version},
+ org.jgroups.conf;version=${project.version},
+ org.jgroups.debug;version=${project.version},
+ org.jgroups.demos;version=${project.version},
+ org.jgroups.demos.wb;version=${project.version},
+ org.jgroups.jmx;version=${project.version},
+ org.jgroups.logging;version=${project.version},
+ org.jgroups.mux;version=${project.version},
+ org.jgroups.persistence;version=${project.version},
+ org.jgroups.protocols;version=${project.version},
+ org.jgroups.protocols.pbcast;version=${project.version},
+ org.jgroups.stack;version=${project.version},
+ org.jgroups.util;version=${project.version},
+ org.jgroups.tests;version=${project.version}
+
+
+ !bsh.*,*
+
+ J2SE-1.6
+
+
+
+
+
+
diff -Nru libjgroups-java-2.7.0.GA/README libjgroups-java-2.12.2.Final/README
--- libjgroups-java-2.7.0.GA/README 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/README 2011-10-18 11:22:35.000000000 +0000
@@ -1,4 +1,3 @@
-// $Id: README,v 1.7 2006/08/09 13:08:02 belaban Exp $
@@ -15,34 +14,33 @@
belaban@yahoo.com
-JGroups is a Java package for reliable group communication. It
+JGroups is a Java library for reliable group communication. It
consists of 3 parts: (1) a socket-like API for application
development, (2) a protocol stack, which implements reliable
communication, and (3) a set of building blocks, which give the
-application/protocol programmer high-level abstractions
-(e.g. DistributedHashtable, derived from java.util.Hashtable, which is
-similar to Linda/JavaSpaces).
+developer high-level abstractions (e.g. ReplicatedHashMap, an
+implementation of java.util.Map.
-The API (a channel) looks like a socket: there a methods for joining
-and leaving groups, sending and receiving messages to/from members,
+The API (a channel) looks like a socket: there are methods for joining
+and leaving groups, sending and receiving messages,
getting the shared group state, and registering for notifications when
a member joins, or an existing member leaves or crashes.
-The protocol stack is a linked list of protocols, through which each
-message has to be passed. Each protocol implements an up() and down()
-method, and may modify, reorder, encrypt, fragment/unfragment, drop a
-message, or pass it up/down unchanged. The protocol stack is created
+The protocol stack is a list of protocols, through which each
+message passes. Each protocol implements an up() and down()
+method, and may modify, reorder, encrypt, fragment/unfragment, drop,
+or pass a message up/down. The protocol stack is created
according to a specification given when a channel is created. New
protocols can be plugged into the stack easily.
-Building blocks hide the channel and provide a higher
-abstraction. Example: DistributedHashtable is a subclass of
-java.util.Hashtable and overrides all methods that change the
-hashtable (clear, put, remove). Those methods are invoked on all
-hashtables in the same group simultaneously, so that all hashtables
-have the same state. A new hashtable uses a state transfer protocol to
-initially obtain the shared group state from an existing member. This
-enables replication of data structures across process boundaries.
+Building blocks hide the channel and provide a higher abstraction.
+Example: ReplicatedHashMap implements java.util.Mapand implements
+all methods that change the map (clear(), put(), remove()).
+Those methods are invoked on all hashmap instances in the same group
+simultaneously, so that all hashmaps have the same state.
+A new hashmap uses a state transfer protocol to initially obtain
+the shared group state from an existing member. This allows for
+replication of data structures across processes.
@@ -59,8 +57,8 @@
- Notification service / push technology: receivers subscribe to a
channel, senders send data to the channels, channels distribute
- data to all receivers subscribed to the channel (see iBus, CastaNet
- etc.). Used for example for video distribution, videoconferencing
+ data to all receivers subscribed to the channel.
+ Used for example for video distribution, videoconferencing
JGroups deliberately models a rather low-level message-oriented
@@ -72,13 +70,6 @@
extend/replace classes at will, as the granularity of the system is
finer.
-JGroups can also be used for the construction of higher level
-toolkits/frameworks. Such frameworks should provide a certain
-transparency, without, however, preventing extensions to be made. The
-principle of creating partly 'opened-up' black boxes is called Open
-Implementation (OI, http://www.parc.xerox.com/spl/projects/oi/) and
-will be applied both to JGroups and to a further higher level
-toolkit.
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/Address.java libjgroups-java-2.12.2.Final/src/org/jgroups/Address.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/Address.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/Address.java 2011-10-18 11:22:35.000000000 +0000
@@ -1,4 +1,3 @@
-// $Id: Address.java,v 1.5 2008/01/10 08:06:59 belaban Exp $
package org.jgroups;
@@ -14,6 +13,11 @@
* @author Bela Ban
*/
public interface Address extends Externalizable, Streamable, Comparable, Cloneable { // todo: remove Externalizable
+ // flags used for marshalling
+ public static final byte NULL = 1 << 0;
+ public static final byte UUID_ADDR = 1 << 1;
+ public static final byte IP_ADDR = 1 << 2;
+
/**
* Checks whether this is an address that represents multiple destinations;
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/annotations/DeprecatedProperty.java libjgroups-java-2.12.2.Final/src/org/jgroups/annotations/DeprecatedProperty.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/annotations/DeprecatedProperty.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/annotations/DeprecatedProperty.java 2011-10-18 11:22:35.000000000 +0000
@@ -8,7 +8,6 @@
*
*
* @author Vladimir Blagojevic
- * @version $Id: DeprecatedProperty.java,v 1.1 2008/05/29 13:53:04 vlada Exp $
*/
@Retention(RetentionPolicy.RUNTIME)
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/annotations/Experimental.java libjgroups-java-2.12.2.Final/src/org/jgroups/annotations/Experimental.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/annotations/Experimental.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/annotations/Experimental.java 2011-10-18 11:22:35.000000000 +0000
@@ -8,9 +8,8 @@
/**
* Elements annotated with this annotation are experimental and may get removed from the distribution at any time
* @author Bela Ban
- * @version $Id: Experimental.java,v 1.3 2008/10/21 08:59:03 vlada Exp $
*/
-@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PACKAGE})
+@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PACKAGE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Experimental {
String comment() default "";
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/annotations/LocalAddress.java libjgroups-java-2.12.2.Final/src/org/jgroups/annotations/LocalAddress.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/annotations/LocalAddress.java 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/annotations/LocalAddress.java 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,18 @@
+package org.jgroups.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This is an assertion, checked at startup time. It ensures that the field this annotation is on is (1) an InetAddress
+ * and (2) a valid address on a local network interface
+ * @author Bela Ban
+ * @since 2.11.2
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface LocalAddress {
+}
+
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/annotations/ManagedAttribute.java libjgroups-java-2.12.2.Final/src/org/jgroups/annotations/ManagedAttribute.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/annotations/ManagedAttribute.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/annotations/ManagedAttribute.java 2011-10-18 11:22:35.000000000 +0000
@@ -10,7 +10,6 @@
* a superclass.
*
* @author Chris Mills
- * @version $Id: ManagedAttribute.java,v 1.6 2008/03/13 02:00:23 vlada Exp $
*/
@Retention(RetentionPolicy.RUNTIME)
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/annotations/ManagedOperation.java libjgroups-java-2.12.2.Final/src/org/jgroups/annotations/ManagedOperation.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/annotations/ManagedOperation.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/annotations/ManagedOperation.java 2011-10-18 11:22:35.000000000 +0000
@@ -10,7 +10,6 @@
* annotation from a superclass.
*
* @author Chris Mills
- * @version $Id: ManagedOperation.java,v 1.4 2008/03/12 00:26:42 vlada Exp $
*/
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/annotations/MBean.java libjgroups-java-2.12.2.Final/src/org/jgroups/annotations/MBean.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/annotations/MBean.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/annotations/MBean.java 2011-10-18 11:22:35.000000000 +0000
@@ -12,7 +12,6 @@
*
*
* @author Chris Mills
- * @version $Id: MBean.java,v 1.6 2008/04/28 13:43:10 vlada Exp $
*/
@Retention(RetentionPolicy.RUNTIME)
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/annotations/Property.java libjgroups-java-2.12.2.Final/src/org/jgroups/annotations/Property.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/annotations/Property.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/annotations/Property.java 2011-10-18 11:22:35.000000000 +0000
@@ -29,7 +29,6 @@
*
*
* @author Vladimir Blagojevic
- * @version $Id: Property.java,v 1.5 2008/05/23 11:11:02 belaban Exp $
*/
@Retention(RetentionPolicy.RUNTIME)
@@ -43,4 +42,26 @@
String deprecatedMessage() default "";
Class> converter() default PropertyConverters.Default.class;
+
+ String dependsUpon() default "";
+
+ String[] systemProperty() default {};
+
+ /**
+ * Global.NON_LOOPBACK_ADDRESS means pick any valid non-loopback IPv4 address
+ */
+ String defaultValueIPv4() default "" ;
+
+ /**
+ * Global.NON_LOOPBACK_ADDRESS means pick any valid non-loopback IPv6 address
+ */
+ String defaultValueIPv6() default "" ;
+
+ /** Expose this property also as a managed attribute */
+ boolean exposeAsManagedAttribute() default true;
+
+ /* Should this managed attribute be writeable ? If set to true, automatically sets exposeAsManagedAttribute to true */
+ boolean writable() default true;
}
+
+
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/annotations/Unsupported.java libjgroups-java-2.12.2.Final/src/org/jgroups/annotations/Unsupported.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/annotations/Unsupported.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/annotations/Unsupported.java 2011-10-18 11:22:35.000000000 +0000
@@ -8,7 +8,6 @@
/**
* Elements annotated with this annotation are unsupported and may get removed from the distribution at any time
* @author Bela Ban
- * @version $Id: Unsupported.java,v 1.3 2008/10/21 12:10:32 vlada Exp $
*/
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PACKAGE})
@Retention(RetentionPolicy.RUNTIME)
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/auth/AuthToken.java libjgroups-java-2.12.2.Final/src/org/jgroups/auth/AuthToken.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/auth/AuthToken.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/auth/AuthToken.java 2011-10-18 11:22:35.000000000 +0000
@@ -1,29 +1,45 @@
package org.jgroups.auth;
-import org.jgroups.util.Streamable;
+import java.io.Serializable;
+
import org.jgroups.Message;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.jgroups.logging.Log;
+import org.jgroups.logging.LogFactory;
+import org.jgroups.protocols.AUTH;
+import org.jgroups.util.Streamable;
-import java.io.Serializable;
-import java.util.Properties;
/**
* Abstract AuthToken class used by implementations of AUTH, e.g. SimpleToken, X509Token
+ *
* @author Chris Mills
*/
-public abstract class AuthToken implements Serializable, Streamable{
+public abstract class AuthToken implements Serializable, Streamable {
protected final Log log = LogFactory.getLog(this.getClass());
-
+
+ /** A reference to AUTH */
+ protected transient AUTH auth = null;
+
+ public void setAuth(AUTH auth) {
+ this.auth = auth;
+ }
+
+ public void init() {}
+
/**
- * Used to return the full package and class name of the implementation. This is used by the AUTH protocol to create an instance of the implementation.
+ * Used to return the full package and class name of the implementation. This is used by the
+ * AUTH protocol to create an instance of the implementation.
+ *
* @return a java.lang.String object of the package and class name
*/
public abstract String getName();
/**
* This method should be implemented to perform the actual authentication of joining members.
- * @param token the token sent by the joiner
- * @param msg the Message object containing the actual JOIN_REQ
+ *
+ * @param token
+ * the token sent by the joiner
+ * @param msg
+ * the Message object containing the actual JOIN_REQ
* @return true if authenticaion passed or false if it failed.
*/
public abstract boolean authenticate(AuthToken token, Message msg);
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/auth/FixedMembershipToken.java libjgroups-java-2.12.2.Final/src/org/jgroups/auth/FixedMembershipToken.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/auth/FixedMembershipToken.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/auth/FixedMembershipToken.java 2011-10-18 11:22:35.000000000 +0000
@@ -1,30 +1,26 @@
/*
-* JBoss, Home of Professional Open Source
-* Copyright 2005, JBoss Inc., and individual contributors as indicated
-* by the @authors tag. See the copyright.txt in the distribution for a
-* full listing of individual contributors.
-*
-* This is free software; you can redistribute it and/or modify it
-* under the terms of the GNU Lesser General Public License as
-* published by the Free Software Foundation; either version 2.1 of
-* the License, or (at your option) any later version.
-*
-* This software is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public
-* License along with this software; if not, write to the Free
-* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
-* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-*/
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
package org.jgroups.auth;
-import org.jgroups.Message;
-import org.jgroups.annotations.Property;
-import org.jgroups.util.Util;
-
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -32,26 +28,35 @@
import java.util.List;
import java.util.StringTokenizer;
+import org.jgroups.Event;
+import org.jgroups.Message;
+import org.jgroups.PhysicalAddress;
+import org.jgroups.annotations.Property;
+import org.jgroups.util.Util;
+
/**
*
- * The FixedMemberShipToken object predefines a list of IP addresses and Ports that can join the group.
+ * The FixedMemberShipToken object predefines a list of IP addresses and ports that can join the
+ * group.
*
*
* Configuration parameters for this example are shown below:
*
*
- *
fixed_members_value (required) = List of IP addresses & ports (optionally) - ports must be seperated by a '/' e.g. 127.0.0.1/1010*127.0.0.1/4567
+ *
fixed_members_value (required) = List of IP addresses & ports (optionally) - ports must be
+ * seperated by a '/' e.g. 127.0.0.1/1010*127.0.0.1/4567
*
fixed_members_seperator (required) = The seperator used between IP addresses - e.g. *
*
+ *
* @author Chris Mills (millsy@jboss.com)
*/
public class FixedMembershipToken extends AuthToken {
-
- private List memberList=null;
- private String token="emptyToken";
+ private List memberList = null;
+ private String token = "emptyToken";
@Property
- private String fixed_members_seperator=",";
+ private String fixed_members_seperator = ",";
+ private static final long serialVersionUID = 4717069536900221681L;
public FixedMembershipToken() {
}
@@ -60,56 +65,68 @@
return "org.jgroups.auth.FixedMembershipToken";
}
+ @Property
+ public void setFixedMembersSeparator(String value) {
+ fixed_members_seperator = value;
+ }
+
public boolean authenticate(AuthToken token, Message msg) {
- if((token != null) && (token instanceof FixedMembershipToken) && (this.memberList != null)) {
- //Found a valid Token to authenticate against
- FixedMembershipToken serverToken=(FixedMembershipToken)token;
+ if ((token != null) && (token instanceof FixedMembershipToken) && (this.memberList != null)) {
+ PhysicalAddress src = (PhysicalAddress) auth.down(new Event(Event.GET_PHYSICAL_ADDRESS,
+ msg.getSrc()));
+ if (src == null) {
+ if (log.isErrorEnabled())
+ log.error("didn't find physical address for " + msg.getSrc());
+ return false;
+ }
- String sourceAddressWithPort=msg.getSrc().toString();
- String sourceAddressWithoutPort=sourceAddressWithPort.substring(0, sourceAddressWithPort.indexOf(":"));
+ String sourceAddressWithPort = src.toString();
+ String sourceAddressWithoutPort = sourceAddressWithPort.substring(0,
+ sourceAddressWithPort.indexOf(":"));
- if(log.isDebugEnabled()) {
+ if (log.isDebugEnabled()) {
log.debug("AUTHToken received from " + sourceAddressWithPort);
}
- if((this.memberList.contains(sourceAddressWithPort)) || (this.memberList.contains(sourceAddressWithoutPort))) {
- //validated
- if(log.isDebugEnabled()) {
- log.debug("FixedMembershipToken match");
+ for (String member : memberList) {
+ if (hasPort(member)) {
+ if (member.equals(sourceAddressWithPort))
+ return true;
+ } else {
+ if (member.equals(sourceAddressWithoutPort))
+ return true;
}
- return true;
- }
- else {
-// if(log.isWarnEnabled()){
-// log.warn("Authentication failed on FixedMembershipToken");
-// }
- return false;
}
+ return false;
}
- if(log.isWarnEnabled()) {
+ if (log.isWarnEnabled()) {
log.warn("Invalid AuthToken instance - wrong type or null");
}
return false;
}
- @Property(name="fixed_members_value")
+ private static boolean hasPort(String member) {
+ return member.contains(":");
+ }
+
+ @Property(name = "fixed_members_value")
public void setMemberList(String list) {
- memberList=new ArrayList();
- StringTokenizer memberListTokenizer=new StringTokenizer(list, fixed_members_seperator);
- while(memberListTokenizer.hasMoreTokens()) {
+ memberList = new ArrayList();
+ StringTokenizer memberListTokenizer = new StringTokenizer(list, fixed_members_seperator);
+ while (memberListTokenizer.hasMoreTokens()) {
memberList.add(memberListTokenizer.nextToken().replace('/', ':'));
}
}
-
/**
* Required to serialize the object to pass across the wire
+ *
* @param out
* @throws java.io.IOException
*/
public void writeTo(DataOutputStream out) throws IOException {
- if(log.isDebugEnabled()) {
+ if (log.isDebugEnabled()) {
log.debug("SimpleToken writeTo()");
}
Util.writeString(this.token, out);
@@ -117,15 +134,17 @@
/**
* Required to deserialize the object when read in from the wire
+ *
* @param in
* @throws IOException
* @throws IllegalAccessException
* @throws InstantiationException
*/
- public void readFrom(DataInputStream in) throws IOException, IllegalAccessException, InstantiationException {
- if(log.isDebugEnabled()) {
+ public void readFrom(DataInputStream in) throws IOException, IllegalAccessException,
+ InstantiationException {
+ if (log.isDebugEnabled()) {
log.debug("SimpleToken readFrom()");
}
- this.token=Util.readString(in);
+ this.token = Util.readString(in);
}
}
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/auth/MD5Token.java libjgroups-java-2.12.2.Final/src/org/jgroups/auth/MD5Token.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/auth/MD5Token.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/auth/MD5Token.java 2011-10-18 11:22:35.000000000 +0000
@@ -1,56 +1,58 @@
package org.jgroups.auth;
-import org.jgroups.Message;
-import org.jgroups.annotations.Property;
-import org.jgroups.util.Util;
-
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
-import java.util.Properties;
+
+import org.jgroups.Message;
+import org.jgroups.annotations.Property;
+import org.jgroups.util.Util;
/**
*
- * This is an example of using a preshared token that is encrypted using an MD5/SHA hash for authentication purposes. All members of the group have to have the same string value in the JGroups config.
+ * This is an example of using a preshared token that is encrypted using an MD5/SHA hash for
+ * authentication purposes. All members of the group have to have the same string value in the
+ * JGroups config.
*
*
* Configuration parameters for this example are shown below:
*
*
- *
token_hash (required) = MD5(default)/SHA
- *
auth_value (required) = the string to encrypt
+ *
token_hash (required) = MD5(default)/SHA
+ *
auth_value (required) = the string to encrypt
*
+ *
* @see org.jgroups.auth.AuthToken
* @author Chris Mills
*/
public class MD5Token extends AuthToken {
@Property
- private String auth_value= null;
+ private String auth_value = null;
- @Property(name="token_hash")
+ @Property(name = "token_hash")
private String hash_type = "MD5";
+ private static final long serialVersionUID = -5787154335375249191L;
- public MD5Token(){
- //need an empty constructor
+ public MD5Token() {
+ // need an empty constructor
}
- public MD5Token(String authvalue){
- this.auth_value= hash(authvalue);
+ public MD5Token(String authvalue) {
+ this.auth_value = hash(authvalue);
}
- public MD5Token(String authvalue, String hash_type){
- this.auth_value= hash(authvalue);
+ public MD5Token(String authvalue, String hash_type) {
+ this.auth_value = hash(authvalue);
this.hash_type = hash_type;
}
-
public String getHashType() {
return hash_type;
}
public void setHashType(String hash_type) {
- this.hash_type=hash_type;
+ this.hash_type = hash_type;
}
public String getAuthValue() {
@@ -58,33 +60,33 @@
}
public void setAuthValue(String auth_value) {
- this.auth_value=auth_value;
+ this.auth_value = auth_value;
}
- public String getName(){
+ public String getName() {
return "org.jgroups.auth.MD5Token";
}
-
-
/**
* Called during setup to hash the auth_value string in to an MD5/SHA hash
- * @param token the string to hash
+ *
+ * @param token
+ * the string to hash
* @return the hashed version of the string
*/
- private String hash(String token){
- //perform the hashing of the token key
+ private String hash(String token) {
+ // perform the hashing of the token key
String hashedToken = null;
- if(hash_type.equalsIgnoreCase("SHA")){
+ if (hash_type.equalsIgnoreCase("SHA")) {
hashedToken = Util.sha(token);
- }else{
+ } else {
hashedToken = Util.md5(token);
}
- if(hashedToken == null){
- //failed to encrypt
- if(log.isWarnEnabled()){
+ if (hashedToken == null) {
+ // failed to encrypt
+ if (log.isWarnEnabled()) {
log.warn("Failed to hash token - sending in clear text");
}
return token;
@@ -92,43 +94,45 @@
return hashedToken;
}
- public boolean authenticate(AuthToken token, Message msg){
+ public boolean authenticate(AuthToken token, Message msg) {
- if((token != null) && (token instanceof MD5Token)){
- //Found a valid Token to authenticate against
+ if ((token != null) && (token instanceof MD5Token)) {
+ // Found a valid Token to authenticate against
MD5Token serverToken = (MD5Token) token;
- if((this.auth_value != null) && (serverToken.auth_value != null) && (this.auth_value.equalsIgnoreCase(serverToken.auth_value))){
- //validated
- if(log.isDebugEnabled()){
+ if ((this.auth_value != null) && (serverToken.auth_value != null)
+ && (this.auth_value.equalsIgnoreCase(serverToken.auth_value))) {
+ // validated
+ if (log.isDebugEnabled()) {
log.debug("MD5Token match");
}
return true;
- }else{
-// if(log.isWarnEnabled()){
-// log.warn("Authentication failed on MD5Token");
-// }
+ } else {
+ // if(log.isWarnEnabled()){
+ // log.warn("Authentication failed on MD5Token");
+ // }
return false;
}
}
- if(log.isWarnEnabled()){
+ if (log.isWarnEnabled()) {
log.warn("Invalid AuthToken instance - wrong type or null");
}
return false;
}
public void writeTo(DataOutputStream out) throws IOException {
- if(log.isDebugEnabled()){
+ if (log.isDebugEnabled()) {
log.debug("MD5Token writeTo()");
}
Util.writeString(this.auth_value, out);
}
- public void readFrom(DataInputStream in) throws IOException, IllegalAccessException, InstantiationException {
- if(log.isDebugEnabled()){
+ public void readFrom(DataInputStream in) throws IOException, IllegalAccessException,
+ InstantiationException {
+ if (log.isDebugEnabled()) {
log.debug("MD5Token readFrom()");
}
- this.auth_value= Util.readString(in);
+ this.auth_value = Util.readString(in);
}
}
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/auth/RegexMembership.java libjgroups-java-2.12.2.Final/src/org/jgroups/auth/RegexMembership.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/auth/RegexMembership.java 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/auth/RegexMembership.java 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,126 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jgroups.auth;
+
+import org.jgroups.Address;
+import org.jgroups.Event;
+import org.jgroups.Message;
+import org.jgroups.PhysicalAddress;
+import org.jgroups.annotations.Property;
+import org.jgroups.util.UUID;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Matches the IP address or logical name of a joiner against a regular expression and accepts or rejects based on
+ * pattern matching
+ * @author Bela Ban
+ */
+public class RegexMembership extends AuthToken {
+
+ @Property(description="The regular expression against which the IP address or logical host of a joiner will be matched")
+ protected String match_string=null;
+
+ @Property(description="Matches the IP address of the joiner against the match string")
+ protected boolean match_ip_address=true;
+
+ @Property(description="Matches the logical name of the joiner against the match string")
+ protected boolean match_logical_name=false;
+
+
+ // ------------------------------------------- Fields ------------------------------------------------------ //
+
+ protected Pattern pattern;
+
+ private static final long serialVersionUID=4717069536900221681L;
+
+
+
+
+ public RegexMembership() {
+ }
+
+
+ public String getName() {
+ return "org.jgroups.auth.RegexMembership";
+ }
+
+
+ public void init() {
+ super.init();
+ if(!match_ip_address && !match_logical_name)
+ throw new IllegalArgumentException("either match_ip_address or match_logical_address has to be true");
+ if(match_string == null)
+ throw new IllegalArgumentException("match_string cannot be null");
+ pattern=Pattern.compile(match_string);
+ }
+
+
+ public boolean authenticate(AuthToken token, Message msg) {
+ Address sender=msg.getSrc();
+
+
+ if(match_ip_address) {
+ PhysicalAddress src=sender != null? (PhysicalAddress)auth.down(new Event(Event.GET_PHYSICAL_ADDRESS, sender)) : null;
+ String ip_addr=src != null? src.toString() : null;
+ if(ip_addr != null) {
+ Matcher matcher=pattern.matcher(ip_addr);
+ boolean result=matcher.matches();
+ if(log.isTraceEnabled())
+ log.trace("matching ip_address: pattern= " + pattern + ", input= " + ip_addr + ", result= " + result);
+ if(result)
+ return true;
+ }
+ }
+ if(match_logical_name) {
+ String logical_name=sender != null? UUID.get(sender) : null;
+ if(logical_name != null) {
+ Matcher matcher=pattern.matcher(logical_name);
+ boolean result=matcher.matches();
+ if(log.isTraceEnabled())
+ log.trace("matching logical_name: pattern= " + pattern + ", input= " + logical_name + ", result= " + result);
+ if(result)
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+
+ public void writeTo(DataOutputStream out) throws IOException {
+ }
+
+ /**
+ * Required to deserialize the object when read in from the wire
+ * @param in
+ * @throws java.io.IOException
+ * @throws IllegalAccessException
+ * @throws InstantiationException
+ */
+ public void readFrom(DataInputStream in) throws IOException, IllegalAccessException, InstantiationException {
+ }
+}
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/auth/SimpleToken.java libjgroups-java-2.12.2.Final/src/org/jgroups/auth/SimpleToken.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/auth/SimpleToken.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/auth/SimpleToken.java 2011-10-18 11:22:35.000000000 +0000
@@ -1,38 +1,41 @@
package org.jgroups.auth;
-import org.jgroups.Message;
-import org.jgroups.annotations.Property;
-import org.jgroups.util.Util;
-
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
-import java.util.Properties;
+
+import org.jgroups.Message;
+import org.jgroups.annotations.Property;
+import org.jgroups.util.Util;
/**
*
- * This is an example of using a preshared token for authentication purposes. All members of the group have to have the same string value in the JGroups config.
+ * This is an example of using a preshared token for authentication purposes. All members of the
+ * group have to have the same string value in the JGroups config.
+ *
+ *
+ * JGroups config parameters:
*
- *
JGroups config parameters:
*
*
auth_value (required) = the string to encrypt
*
+ *
* @author Chris Mills
* @see org.jgroups.auth.AuthToken
*/
public class SimpleToken extends AuthToken {
@Property
- private String auth_value=null;
+ private String auth_value = null;
+ private static final long serialVersionUID = 5020668015439045326L;
public SimpleToken() { // need an empty constructor
}
public SimpleToken(String authvalue) {
- this.auth_value=authvalue;
+ this.auth_value = authvalue;
}
-
public String getName() {
return "org.jgroups.auth.SimpleToken";
}
@@ -42,30 +45,30 @@
}
public void setAuthValue(String auth_value) {
- this.auth_value=auth_value;
+ this.auth_value = auth_value;
}
public boolean authenticate(AuthToken token, Message msg) {
- if((token != null) && (token instanceof SimpleToken)) {
- //Found a valid Token to authenticate against
- SimpleToken serverToken=(SimpleToken)token;
-
- if((this.auth_value != null) && (serverToken.auth_value != null) && (this.auth_value.equalsIgnoreCase(serverToken.auth_value))) {
- //validated
- if(log.isDebugEnabled()) {
+ if ((token != null) && (token instanceof SimpleToken)) {
+ // Found a valid Token to authenticate against
+ SimpleToken serverToken = (SimpleToken) token;
+
+ if ((this.auth_value != null) && (serverToken.auth_value != null)
+ && (this.auth_value.equalsIgnoreCase(serverToken.auth_value))) {
+ // validated
+ if (log.isDebugEnabled()) {
log.debug("SimpleToken match");
}
return true;
- }
- else {
- //if(log.isWarnEnabled()){
- // log.warn("Authentication failed on SimpleToken");
- //}
+ } else {
+ // if(log.isWarnEnabled()){
+ // log.warn("Authentication failed on SimpleToken");
+ // }
return false;
}
}
- if(log.isWarnEnabled()) {
+ if (log.isWarnEnabled()) {
log.warn("Invalid AuthToken instance - wrong type or null");
}
return false;
@@ -73,11 +76,12 @@
/**
* Required to serialize the object to pass across the wire
+ *
* @param out
* @throws IOException
*/
public void writeTo(DataOutputStream out) throws IOException {
- if(log.isDebugEnabled()) {
+ if (log.isDebugEnabled()) {
log.debug("SimpleToken writeTo()");
}
Util.writeString(this.auth_value, out);
@@ -85,15 +89,17 @@
/**
* Required to deserialize the object when read in from the wire
+ *
* @param in
* @throws IOException
* @throws IllegalAccessException
* @throws InstantiationException
*/
- public void readFrom(DataInputStream in) throws IOException, IllegalAccessException, InstantiationException {
- if(log.isDebugEnabled()) {
+ public void readFrom(DataInputStream in) throws IOException, IllegalAccessException,
+ InstantiationException {
+ if (log.isDebugEnabled()) {
log.debug("SimpleToken readFrom()");
}
- this.auth_value=Util.readString(in);
+ this.auth_value = Util.readString(in);
}
-}
+}
\ No newline at end of file
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/auth/X509Token.java libjgroups-java-2.12.2.Final/src/org/jgroups/auth/X509Token.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/auth/X509Token.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/auth/X509Token.java 2011-10-18 11:22:35.000000000 +0000
@@ -1,185 +1,202 @@
package org.jgroups.auth;
-import org.jgroups.Message;
-import org.jgroups.annotations.Property;
-import org.jgroups.util.Util;
-
-import javax.crypto.Cipher;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.BadPaddingException;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
-import java.io.FileNotFoundException;
-import java.security.*;
-import java.security.cert.X509Certificate;
+import java.security.InvalidKeyException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableEntryException;
import java.security.cert.CertificateException;
-import java.util.Properties;
+import java.security.cert.X509Certificate;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+
+import org.jgroups.Message;
+import org.jgroups.annotations.Property;
+import org.jgroups.util.Util;
/**
*
- * This is an example of using a preshared token that is encrypted using an X509 certificate for authentication purposes. All members of the group have to have the same string value in the JGroups config.
+ * This is an example of using a preshared token that is encrypted using an X509 certificate for
+ * authentication purposes. All members of the group have to have the same string value in the
+ * JGroups config.
*
*
- * This example uses certificates contained within a specified keystore. Configuration parameters for this example are shown below:
+ * This example uses certificates contained within a specified keystore. Configuration parameters
+ * for this example are shown below:
*
*
- *
keystore_type = JKS(default)/PKCS12 - see http://java.sun.com/j2se/1.4.2/docs/guide/security/CryptoSpec.html#AppA
+ *
keystore_type = JKS(default)/PKCS12 - see
+ * http://java.sun.com/j2se/1.4.2/docs/guide/security/CryptoSpec.html#AppA
*
keystore_path (required) = the location of the keystore
- *
keystore_password (required) = the password of the keystore
+ *
keystore_password (required) = the password of the keystore
*
cert_alias (required) = the alias of the certification within the keystore
*
cert_password = the password of the certification within the keystore
*
auth_value (required) = the string to encrypt
- *
cipher_type = RSA(default)/AES/Blowfish/DES/DESede/PBEWithMD5AndDES/PBEWithHmacSHA1AndDESede/RC2/RC4/RC5 - see http://java.sun.com/j2se/1.4.2/docs/guide/security/jce/JCERefGuide.html#AppA
+ *
cipher_type =
+ * RSA(default)/AES/Blowfish/DES/DESede/PBEWithMD5AndDES/PBEWithHmacSHA1AndDESede/RC2/RC4/RC5 - see
+ * http://java.sun.com/j2se/1.4.2/docs/guide/security/jce/JCERefGuide.html#AppA
*
+ *
* @author Chris Mills
* @see org.jgroups.auth.AuthToken
*/
public class X509Token extends AuthToken {
- public static final String KEYSTORE_TYPE="keystore_type";
- public static final String KEYSTORE_PATH="keystore_path";
- public static final String KEYSTORE_PASSWORD="keystore_password";
- public static final String CERT_ALIAS="cert_alias";
- public static final String CERT_PASSWORD="cert_password";
- public static final String TOKEN_ATTR="auth_value";
- public static final String CIPHER_TYPE="cipher_type";
+ public static final String KEYSTORE_TYPE = "keystore_type";
+ public static final String KEYSTORE_PATH = "keystore_path";
+ public static final String KEYSTORE_PASSWORD = "keystore_password";
+ public static final String CERT_ALIAS = "cert_alias";
+ public static final String CERT_PASSWORD = "cert_password";
+ public static final String TOKEN_ATTR = "auth_value";
+ public static final String CIPHER_TYPE = "cipher_type";
- private boolean valueSet=false;
+ private boolean valueSet = false;
@Property
- private String keystore_type="JKS";
+ private String keystore_type = "JKS";
@Property
- private String cert_alias=null;
+ private String cert_alias = null;
@Property
- private String keystore_path=null;
+ private String keystore_path = null;
@Property
- private String auth_value=null;
+ private String auth_value = null;
@Property
- private String cipher_type="RSA";
+ private String cipher_type = "RSA";
- private byte[] encryptedToken=null;
+ private byte[] encryptedToken = null;
- private char[] cert_password=null;
- private char[] keystore_password=null;
+ private char[] cert_password = null;
+ private char[] keystore_password = null;
- private Cipher cipher=null;
- private PrivateKey certPrivateKey=null;
- private X509Certificate certificate=null;
+ private Cipher cipher = null;
+ private PrivateKey certPrivateKey = null;
+ private X509Certificate certificate = null;
+ private static final long serialVersionUID = -514501306160844271L;
public X509Token() {
- //need an empty constructor
+ // need an empty constructor
}
-
- @Property(name="cert_password")
+ @Property(name = "cert_password")
public void setCertPassword(String pwd) {
- this.cert_password=pwd.toCharArray();
+ this.cert_password = pwd.toCharArray();
}
- @Property(name="keystore_password")
+ @Property(name = "keystore_password")
public void setKeyStorePassword(String pwd) {
- this.keystore_password=pwd.toCharArray();
- if(cert_password == null)
- cert_password=keystore_password;
+ this.keystore_password = pwd.toCharArray();
+ if (cert_password == null)
+ cert_password = keystore_password;
}
-
-
public String getName() {
return "org.jgroups.auth.X509Token";
}
public boolean authenticate(AuthToken token, Message msg) {
- if(!this.valueSet) {
- if(log.isFatalEnabled()) {
+ if (!this.valueSet) {
+ if (log.isFatalEnabled()) {
log.fatal("X509Token not setup correctly - check token attrs");
}
return false;
}
- if((token != null) && (token instanceof X509Token)) {
- //got a valid X509 token object
- X509Token serverToken=(X509Token)token;
- if(!serverToken.valueSet) {
- if(log.isFatalEnabled()) {
+ if ((token != null) && (token instanceof X509Token)) {
+ // got a valid X509 token object
+ X509Token serverToken = (X509Token) token;
+ if (!serverToken.valueSet) {
+ if (log.isFatalEnabled()) {
log.fatal("X509Token - recieved token not valid");
}
return false;
}
try {
- if(log.isDebugEnabled()) {
+ if (log.isDebugEnabled()) {
log.debug("setting cipher to decrypt mode");
}
this.cipher.init(Cipher.DECRYPT_MODE, this.certPrivateKey);
- String serverBytes=new String(this.cipher.doFinal(serverToken.encryptedToken));
- if((serverBytes.equalsIgnoreCase(this.auth_value))) {
- if(log.isDebugEnabled()) {
+ String serverBytes = new String(this.cipher.doFinal(serverToken.encryptedToken));
+ if ((serverBytes.equalsIgnoreCase(this.auth_value))) {
+ if (log.isDebugEnabled()) {
log.debug("X509 authentication passed");
}
return true;
}
- }
- catch(Exception e) {
- if(log.isFatalEnabled()) {
- log.fatal(e);
+ } catch (Exception e) {
+ if (log.isFatalEnabled()) {
+ log.fatal(e.toString());
}
}
}
-// if(log.isWarnEnabled()){
-// log.warn("X509 authentication failed");
-// }
+ // if(log.isWarnEnabled()){
+ // log.warn("X509 authentication failed");
+ // }
return false;
}
public void writeTo(DataOutputStream out) throws IOException {
- if(log.isDebugEnabled()) {
+ if (log.isDebugEnabled()) {
log.debug("X509Token writeTo()");
}
Util.writeByteBuffer(this.encryptedToken, out);
}
- public void readFrom(DataInputStream in) throws IOException, IllegalAccessException, InstantiationException {
- if(log.isDebugEnabled()) {
+ public void readFrom(DataInputStream in) throws IOException, IllegalAccessException,
+ InstantiationException {
+ if (log.isDebugEnabled()) {
log.debug("X509Token readFrom()");
}
- this.encryptedToken=Util.readByteBuffer(in);
- this.valueSet=true;
+ this.encryptedToken = Util.readByteBuffer(in);
+ this.valueSet = true;
}
/**
- * Used during setup to get the certification from the keystore and encrypt the auth_value with the private key
- * @return true if the certificate was found and the string encypted correctly otherwise returns false
+ * Used during setup to get the certification from the keystore and encrypt the auth_value with
+ * the private key
+ *
+ * @return true if the certificate was found and the string encypted correctly otherwise returns
+ * false
*/
- public void setCertificate() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnrecoverableEntryException {
- KeyStore store=KeyStore.getInstance(this.keystore_type);
- java.io.FileInputStream fis=new java.io.FileInputStream(this.keystore_path);
+ public void setCertificate() throws KeyStoreException, IOException, NoSuchAlgorithmException,
+ CertificateException, NoSuchPaddingException, InvalidKeyException,
+ IllegalBlockSizeException, BadPaddingException, UnrecoverableEntryException {
+ KeyStore store = KeyStore.getInstance(this.keystore_type);
+ java.io.FileInputStream fis = new java.io.FileInputStream(this.keystore_path);
store.load(fis, this.keystore_password);
- this.cipher=Cipher.getInstance(this.cipher_type);
- this.certificate=(X509Certificate)store.getCertificate(this.cert_alias);
+ this.cipher = Cipher.getInstance(this.cipher_type);
+ this.certificate = (X509Certificate) store.getCertificate(this.cert_alias);
- if(log.isDebugEnabled()) {
+ if (log.isDebugEnabled()) {
log.debug("certificate = " + this.certificate.toString());
}
this.cipher.init(Cipher.ENCRYPT_MODE, this.certificate);
- this.encryptedToken=this.cipher.doFinal(this.auth_value.getBytes());
+ this.encryptedToken = this.cipher.doFinal(this.auth_value.getBytes());
- if(log.isDebugEnabled()) {
+ if (log.isDebugEnabled()) {
log.debug("encryptedToken = " + this.encryptedToken);
}
- KeyStore.PrivateKeyEntry privateKey=(KeyStore.PrivateKeyEntry)store.getEntry(this.cert_alias, new KeyStore.PasswordProtection(this.cert_password));
- this.certPrivateKey=privateKey.getPrivateKey();
+ KeyStore.PrivateKeyEntry privateKey = (KeyStore.PrivateKeyEntry) store.getEntry(
+ this.cert_alias, new KeyStore.PasswordProtection(this.cert_password));
+ this.certPrivateKey = privateKey.getPrivateKey();
+
+ this.valueSet=true;
- if(log.isDebugEnabled()) {
+ if (log.isDebugEnabled()) {
log.debug("certPrivateKey = " + this.certPrivateKey.toString());
}
}
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/BlockEvent.java libjgroups-java-2.12.2.Final/src/org/jgroups/BlockEvent.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/BlockEvent.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/BlockEvent.java 2011-10-18 11:22:35.000000000 +0000
@@ -1,4 +1,3 @@
-// $Id: BlockEvent.java,v 1.2 2005/07/17 11:38:05 chrislott Exp $
package org.jgroups;
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/AbstractConnectionMap.java libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/AbstractConnectionMap.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/AbstractConnectionMap.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/AbstractConnectionMap.java 2011-10-18 11:22:35.000000000 +0000
@@ -1,22 +1,17 @@
package org.jgroups.blocks;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Vector;
-import java.util.Map.Entry;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.jgroups.logging.Log;
+import org.jgroups.logging.LogFactory;
import org.jgroups.Address;
import org.jgroups.Global;
import org.jgroups.util.ThreadFactory;
import org.jgroups.util.Util;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
public abstract class AbstractConnectionMap implements ConnectionMap {
protected final Vector> conn_listeners=new Vector>();
@@ -70,7 +65,8 @@
public void addConnection(Address address, V conn) {
lock.lock();
try {
- conns.put(address, conn);
+ V previous = conns.put(address, conn);
+ Util.close(previous);
}
finally {
lock.unlock();
@@ -93,6 +89,22 @@
}
}
+ public String printConnections() {
+ StringBuilder sb=new StringBuilder();
+
+ lock.lock();
+ try {
+ for(Map.Entry entry: conns.entrySet()) {
+ sb.append(entry.getKey()).append(": ").append(entry.getValue()).append("\n");
+ }
+ }
+ finally {
+ lock.unlock();
+ }
+
+ return sb.toString();
+ }
+
public ThreadFactory getThreadFactory() {
return factory;
}
@@ -115,8 +127,7 @@
}
/**
- * Removes all connections from ConnectionTable which are not in
- * current_mbrs
+ * Removes all connections which are not in current_mbrs
*
* @param current_mbrs
*/
@@ -157,12 +168,12 @@
for(Iterator> i = conns.entrySet().iterator();i.hasNext();) {
Entry e = i.next();
Util.close(e.getValue());
- }
+ }
+ clear();
}
finally {
lock.unlock();
- }
- clear();
+ }
conn_listeners.clear();
}
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/BasicConnectionTable.java libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/BasicConnectionTable.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/BasicConnectionTable.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/BasicConnectionTable.java 2011-10-18 11:22:35.000000000 +0000
@@ -1,15 +1,12 @@
package org.jgroups.blocks;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.jgroups.logging.Log;
+import org.jgroups.logging.LogFactory;
import org.jgroups.Address;
import org.jgroups.Global;
import org.jgroups.Version;
import org.jgroups.stack.IpAddress;
-import org.jgroups.util.DefaultThreadFactory;
-import org.jgroups.util.PortsManager;
-import org.jgroups.util.ThreadFactory;
-import org.jgroups.util.Util;
+import org.jgroups.util.*;
import java.io.*;
import java.net.InetAddress;
@@ -53,8 +50,7 @@
volatile ServerSocket srv_sock=null;
boolean tcp_nodelay=false;
int linger=-1;
-
- protected PortsManager pm=null;
+ protected SocketFactory socket_factory=new DefaultSocketFactory();
/**
* The address which will be broadcast to the group (the externally visible address which this host should
@@ -69,6 +65,8 @@
final static long MAX_JOIN_TIMEOUT=Global.THREAD_SHUTDOWN_WAIT_TIME;
+
+
protected BasicConnectionTable() {
factory = new DefaultThreadFactory(new ThreadGroup(Util.getGlobalThreadGroup(),"ConnectionTable"),"Connection Table", false);
}
@@ -156,6 +154,14 @@
return factory;
}
+ public SocketFactory getSocketFactory() {
+ return socket_factory;
+ }
+
+ public void setSocketFactory(SocketFactory socket_factory) {
+ this.socket_factory=socket_factory;
+ }
+
public boolean getUseSendQueues() {return use_send_queues;}
public void setUseSendQueues(boolean flag) {this.use_send_queues=flag;}
@@ -182,13 +188,9 @@
// 2. close the server socket (this also stops the acceptor thread)
if(srv_sock != null) {
try {
- if(pm != null) {
- int tmp_port=srv_sock.getLocalPort();
- pm.updatePort(tmp_port);
- }
ServerSocket tmp=srv_sock;
srv_sock=null;
- tmp.close();
+ socket_factory.close(tmp);
if(acceptor != null)
Util.interruptAndWaitToDie(acceptor);
}
@@ -257,7 +259,7 @@
entry=it.next();
key=entry.getKey();
val=entry.getValue();
- ret.append("key: " + key + ": " + val + '\n');
+ ret.append(key + ": " + val + '\n');
}
ret.append('\n');
return ret.toString();
@@ -572,7 +574,7 @@
initCookie(input_cookie);
// read the cookie first
- in.read(input_cookie, 0, input_cookie.length);
+ in.readFully(input_cookie, 0, input_cookie.length);
if(!matchCookie(input_cookie))
throw new SocketException("ConnectionTable.Connection.readPeerAddress(): cookie sent by " +
client_peer_addr + " does not match own cookie; terminating connection");
@@ -583,7 +585,7 @@
if(log.isWarnEnabled())
log.warn(new StringBuilder("packet from ").append(client_addr).append(':').append(client_port).
append(" has different version (").append(Version.print(version)).append(") from ours (").
- append(Version.printVersion()).append("). This may cause problems"));
+ append(Version.printVersion()).append("). This may cause problems").toString());
}
client_peer_addr=new IpAddress();
client_peer_addr.readFrom(in);
@@ -646,18 +648,14 @@
public void run() {
- byte[] buf=new byte[256]; // start with 256, increase as we go
- int len=0;
-
while(receiverThread != null && receiverThread.equals(Thread.currentThread()) && is_running) {
try {
if(in == null) {
if(log.isErrorEnabled()) log.error("input stream is null !");
break;
}
- len=in.readInt();
- if(len > buf.length)
- buf=new byte[len];
+ int len=in.readInt();
+ byte[] buf=new byte[len];
in.readFully(buf, 0, len);
updateLastAccessed();
receive(peer_addr, buf, 0, len); // calls receiver.receive(msg)
@@ -668,7 +666,7 @@
}
catch(IOException io_ex) {
//this is very common occurrence, hence log under trace level
- if(log.isTraceEnabled()) log.trace("Excption while read blocked for data from peer ", io_ex);
+ if(log.isTraceEnabled()) log.trace("Exception while read blocked for data from peer ", io_ex);
notifyConnectionClosed(peer_addr);
break;
}
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/Cache.java libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/Cache.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/Cache.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/Cache.java 2011-10-18 11:22:35.000000000 +0000
@@ -1,11 +1,12 @@
package org.jgroups.blocks;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.jgroups.logging.Log;
+import org.jgroups.logging.LogFactory;
import org.jgroups.annotations.Experimental;
import org.jgroups.annotations.Unsupported;
import org.jgroups.annotations.ManagedAttribute;
import org.jgroups.annotations.ManagedOperation;
+import org.jgroups.util.Util;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -16,17 +17,18 @@
* Simple cache which maintains keys and value. A reaper can be enabled which periodically evicts expired entries.
* Also, when the cache is configured to be bounded, entries in excess of the max size will be evicted on put().
* @author Bela Ban
- * @version $Id: Cache.java,v 1.10 2008/09/03 10:38:25 belaban Exp $
*/
@Experimental
@Unsupported
public class Cache {
private static final Log log=LogFactory.getLog(Cache.class);
- private final ConcurrentMap> map=new ConcurrentHashMap>();
+ private final ConcurrentMap> map=Util.createConcurrentMap();
private ScheduledThreadPoolExecutor timer=new ScheduledThreadPoolExecutor(1);
private Future task=null;
private final AtomicBoolean is_reaping=new AtomicBoolean(false);
+ private Set change_listeners=new HashSet();
+
/** The maximum number of keys, When this value is exceeded we evict older entries, until we drop below this
* mark again. This effectively maintains a bounded cache. A value of 0 means don't bound the cache.
*/
@@ -41,6 +43,14 @@
this.max_num_entries=max_num_entries;
}
+ public void addChangeListener(ChangeListener l) {
+ change_listeners.add(l);
+ }
+
+ public void removeChangeListener(ChangeListener l) {
+ change_listeners.remove(l);
+ }
+
@ManagedAttribute
public int getSize() {
return map.size();
@@ -93,7 +103,7 @@
public V put(K key, V val, long caching_time) {
if(log.isTraceEnabled())
log.trace("put(" + key + ", " + val + ", " + caching_time + ")");
- Value value=new Value(val, caching_time <= 0? caching_time : System.currentTimeMillis() + caching_time);
+ Value value=new Value(val, caching_time);
Value retval=map.put(key, value);
if(max_num_entries > 0 && map.size() > max_num_entries) {
@@ -149,14 +159,23 @@
Value val=map.get(key);
if(val == null)
return null;
- if(val.expiration_time == -1 ||
- (val.expiration_time > 0 && val.expiration_time < System.currentTimeMillis())) {
+ if(val.timeout == -1 ||
+ (val.timeout > 0 && val.timeout < System.currentTimeMillis())) {
map.remove(key);
return null;
}
return val.value;
}
+ /**
+ * This method should not be used to add or remove elements ! It was just added because ReplCacheDemo
+ * requires it for its data model
+ * @return
+ */
+ public ConcurrentMap> getInternalMap() {
+ return map;
+ }
+
public Value getEntry(K key) {
if(log.isTraceEnabled())
log.trace("getEntry(" + key + ")");
@@ -181,7 +200,7 @@
Value val=entry.getValue();
sb.append(entry.getKey()).append(": ").append(entry.getValue().getValue());
sb.append(" (expiration_time: ");
- long expiration_time=val.getExpirationTime();
+ long expiration_time=val.getTimeout();
if(expiration_time <= 0)
sb.append(expiration_time);
else {
@@ -210,17 +229,33 @@
}
private void evict() {
+ boolean evicted=false;
for(Iterator>> it=map.entrySet().iterator(); it.hasNext();) {
Map.Entry> entry=it.next();
Value val=entry.getValue();
if(val != null) {
- if(val.expiration_time == -1 || (val.expiration_time > 0 && System.currentTimeMillis() > val.expiration_time)) {
+ if(val.timeout == -1 || (val.timeout > 0 && System.currentTimeMillis() > val.insertion_time + val.timeout)) {
if(log.isTraceEnabled())
log.trace("evicting " + entry.getKey() + ": " + entry.getValue().value);
it.remove();
+ evicted=true;
}
}
}
+ if(evicted)
+ notifyChangeListeners();
+ }
+
+ private void notifyChangeListeners() {
+ for(ChangeListener l: change_listeners) {
+ try {
+ l.changed();
+ }
+ catch(Throwable t) {
+ if(log.isErrorEnabled())
+ log.error("failed notifying change listener", t);
+ }
+ }
}
@@ -231,13 +266,13 @@
private long insertion_time=System.currentTimeMillis();
/** When the value can be reaped (in ms) */
- private transient long expiration_time;
+ private transient long timeout;
private static final long serialVersionUID=-3445944261826378608L;
- public Value(V value, long expiration_time) {
+ public Value(V value, long timeout) {
this.value=value;
- this.expiration_time=expiration_time;
+ this.timeout=timeout;
}
public Value() {
@@ -245,16 +280,16 @@
public V getValue() {return value;}
public long getInsertionTime() {return insertion_time;}
- public long getExpirationTime() {return expiration_time;}
+ public long getTimeout() {return timeout;}
public void writeExternal(ObjectOutput out) throws IOException {
- out.writeLong(expiration_time);
+ out.writeLong(timeout);
out.writeObject(value);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
insertion_time=System.currentTimeMillis();
- expiration_time=in.readLong();
+ timeout=in.readLong();
value=(V)in.readObject();
}
}
@@ -267,4 +302,8 @@
}
}
+ public interface ChangeListener {
+ void changed();
+ }
+
}
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/ConnectionTable.java libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/ConnectionTable.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/ConnectionTable.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/ConnectionTable.java 1970-01-01 00:00:00.000000000 +0000
@@ -1,373 +0,0 @@
-// $Id: ConnectionTable.java,v 1.67 2008/10/22 08:51:13 belaban Exp $
-
-package org.jgroups.blocks;
-
-import org.jgroups.Address;
-import org.jgroups.util.PortsManager;
-import org.jgroups.stack.IpAddress;
-
-import java.io.IOException;
-import java.net.*;
-
-
-/**
- * Manages incoming and outgoing TCP connections. For each outgoing message to destination P, if there
- * is not yet a connection for P, one will be created. Subsequent outgoing messages will use this
- * connection. For incoming messages, one server socket is created at startup. For each new incoming
- * client connecting, a new thread from a thread pool is allocated and listens for incoming messages
- * until the socket is closed by the peer. Sockets/threads with no activity will be killed
- * after some time.
- *
- * Incoming messages from any of the sockets can be received by setting the message listener.
- * @author Bela Ban
- */
-public class ConnectionTable extends BasicConnectionTable implements Runnable {
-
- /**
- * Regular ConnectionTable without expiration of idle connections
- * @param srv_port The port on which the server will listen. If this port is reserved, the next
- * free port will be taken (incrementing srv_port).
- */
- public ConnectionTable(int srv_port) throws Exception {
- this.srv_port=srv_port;
- init();
- }
-
-
- public ConnectionTable(InetAddress bind_addr, int srv_port) throws Exception {
- this.srv_port=srv_port;
- this.bind_addr=bind_addr;
- init();
- }
-
-
- /**
- * ConnectionTable including a connection reaper. Connections that have been idle for more than conn_expire_time
- * milliseconds will be closed and removed from the connection table. On next access they will be re-created.
- * @param srv_port The port on which the server will listen
- * @param reaper_interval Number of milliseconds to wait for reaper between attepts to reap idle connections
- * @param conn_expire_time Number of milliseconds a connection can be idle (no traffic sent or received until
- * it will be reaped
- */
- public ConnectionTable(int srv_port, long reaper_interval, long conn_expire_time) throws Exception {
- this.srv_port=srv_port;
- this.reaper_interval=reaper_interval;
- this.conn_expire_time=conn_expire_time;
- use_reaper=true;
- init();
- }
-
-
- public ConnectionTable(Receiver r, InetAddress bind_addr, InetAddress external_addr,
- int srv_port, int max_port) throws Exception {
- setReceiver(r);
- this.bind_addr=bind_addr;
- this.external_addr=external_addr;
- this.srv_port=srv_port;
- this.max_port=max_port;
- init();
- }
-
-
- /**
- * Create a ConnectionTable
- * @param r A reference to a receiver of all messages received by this class. Method receive()
- * will be called.
- * @param bind_addr The host name or IP address of the interface to which the server socket will bind.
- * This is interesting only in multi-homed systems. If bind_addr is null, the
- * server socket will bind to the first available interface (e.g. /dev/hme0 on
- * Solaris or /dev/eth0 on Linux systems).
- * @param external_addr The address which will be broadcast to the group (the externally visible address
- * which this host should be contacted on). If external_addr is null, it will default to
- * the same address that the server socket is bound to.
- * @param srv_port The port to which the server socket will bind to. If this port is reserved, the next
- * free port will be taken (incrementing srv_port).
- * @param max_port The largest port number that the server socket will be bound to. If max_port < srv_port
- * then there is no limit.
- */
- public ConnectionTable(Receiver r, InetAddress bind_addr, InetAddress external_addr,
- int srv_port, int max_port, PortsManager pm) throws Exception {
- setReceiver(r);
- this.bind_addr=bind_addr;
- this.external_addr=external_addr;
- this.srv_port=srv_port;
- this.max_port=max_port;
- this.pm=pm;
- init();
- }
-
-
- public ConnectionTable(Receiver r, InetAddress bind_addr, InetAddress external_addr, int srv_port, int max_port,
- long reaper_interval, long conn_expire_time) throws Exception {
- setReceiver(r);
- this.bind_addr=bind_addr;
- this.external_addr=external_addr;
- this.srv_port=srv_port;
- this.max_port=max_port;
- this.reaper_interval=reaper_interval;
- this.conn_expire_time=conn_expire_time;
- use_reaper=true;
- init();
- }
-
- /**
- * ConnectionTable including a connection reaper. Connections that have been idle for more than conn_expire_time
- * milliseconds will be closed and removed from the connection table. On next access they will be re-created.
- *
- * @param r The Receiver
- * @param bind_addr The host name or IP address of the interface to which the server socket will bind.
- * This is interesting only in multi-homed systems. If bind_addr is null, the
- * server socket will bind to the first available interface (e.g. /dev/hme0 on
- * Solaris or /dev/eth0 on Linux systems).
- * @param external_addr The address which will be broadcast to the group (the externally visible address
- * which this host should be contacted on). If external_addr is null, it will default to
- * the same address that the server socket is bound to.
- * @param srv_port The port to which the server socket will bind to. If this port is reserved, the next
- * free port will be taken (incrementing srv_port).
- * @param max_port The largest port number that the server socket will be bound to. If max_port < srv_port
- * then there is no limit.
- * @param reaper_interval Number of milliseconds to wait for reaper between attepts to reap idle connections
- * @param conn_expire_time Number of milliseconds a connection can be idle (no traffic sent or received until
- * it will be reaped
- */
- public ConnectionTable(Receiver r, InetAddress bind_addr, InetAddress external_addr, int srv_port, int max_port,
- long reaper_interval, long conn_expire_time, PortsManager pm) throws Exception {
- setReceiver(r);
- this.bind_addr=bind_addr;
- this.external_addr=external_addr;
- this.srv_port=srv_port;
- this.max_port=max_port;
- this.pm=pm;
- this.reaper_interval=reaper_interval;
- this.conn_expire_time=conn_expire_time;
- use_reaper=true;
- init();
- }
-
-
-
- /** Try to obtain correct Connection (or create one if not yet existent) */
- Connection getConnection(Address dest) throws Exception {
- Connection conn=null;
- Socket sock;
-
- synchronized(conns) {
- conn=conns.get(dest);
- if(conn == null) {
- // changed by bela Jan 18 2004: use the bind address for the client sockets as well
- SocketAddress tmpBindAddr=new InetSocketAddress(bind_addr, 0);
- InetAddress tmpDest=((IpAddress)dest).getIpAddress();
- SocketAddress destAddr=new InetSocketAddress(tmpDest, ((IpAddress)dest).getPort());
- sock=new Socket();
- sock.bind(tmpBindAddr);
- sock.setKeepAlive(true);
- sock.setTcpNoDelay(tcp_nodelay);
- if(linger > 0)
- sock.setSoLinger(true, linger);
- else
- sock.setSoLinger(false, -1);
- sock.connect(destAddr, sock_conn_timeout);
-
- try {
- sock.setSendBufferSize(send_buf_size);
- }
- catch(IllegalArgumentException ex) {
- if(log.isErrorEnabled()) log.error("exception setting send buffer size to " +
- send_buf_size + " bytes", ex);
- }
- try {
- sock.setReceiveBufferSize(recv_buf_size);
- }
- catch(IllegalArgumentException ex) {
- if(log.isErrorEnabled()) log.error("exception setting receive buffer size to " +
- send_buf_size + " bytes", ex);
- }
- conn=new Connection(sock, dest);
- conn.sendLocalAddress(local_addr);
- notifyConnectionOpened(dest);
- addConnection(dest, conn);
- conn.init();
- if(log.isTraceEnabled()) log.trace("created socket to " + dest);
- }
- return conn;
- }
- }
-
-
- public final void start() throws Exception {
- acceptor=getThreadFactory().newThread(thread_group,this, "ConnectionTable.AcceptorThread");
- acceptor.start();
-
- // start the connection reaper - will periodically remove unused connections
- if(use_reaper && reaper == null) {
- reaper=new Reaper();
- reaper.start();
- }
- super.start();
- }
-
- protected void init() throws Exception {
-
- srv_sock=createServerSocket(srv_port, max_port);
-
- if (external_addr!=null)
- local_addr=new IpAddress(external_addr, srv_sock.getLocalPort());
- else if (bind_addr != null)
- local_addr=new IpAddress(bind_addr, srv_sock.getLocalPort());
- else
- local_addr=new IpAddress(srv_sock.getLocalPort());
-
- if(log.isDebugEnabled()) log.debug("server socket listening on " + local_addr);
- }
-
-
-
-
- /**
- * Acceptor thread. Continuously accept new connections. Create a new thread for each new
- * connection and put it in conns. When the thread should stop, it is
- * interrupted by the thread creator.
- */
- public void run() {
- Socket client_sock=null;
- Connection conn=null;
- Address peer_addr;
-
- while(srv_sock != null) {
- try {
- conn=null;
- client_sock=srv_sock.accept();
- if(!running) {
- if(log.isWarnEnabled())
- log.warn("cannot accept connection from " + client_sock.getRemoteSocketAddress() + " as I'm closed");
- break;
- }
- if(log.isTraceEnabled())
- log.trace("[" +local_addr + "] accepted connection from " + client_sock.getInetAddress() + ":" + client_sock.getPort());
- try {
- client_sock.setSendBufferSize(send_buf_size);
- }
- catch(IllegalArgumentException ex) {
- if(log.isErrorEnabled()) log.error("exception setting send buffer size to " + send_buf_size + " bytes", ex);
- }
- try {
- client_sock.setReceiveBufferSize(recv_buf_size);
- }
- catch(IllegalArgumentException ex) {
- if(log.isErrorEnabled()) log.error("exception setting receive buffer size to " + send_buf_size + " bytes", ex);
- }
-
- client_sock.setKeepAlive(true);
- client_sock.setTcpNoDelay(tcp_nodelay);
- if(linger > 0)
- client_sock.setSoLinger(true, linger);
- else
- client_sock.setSoLinger(false, -1);
-
- // create new thread and add to conn table
- conn=new Connection(client_sock, null); // will call receive(msg)
- // get peer's address
- peer_addr=conn.readPeerAddress(client_sock);
-
- // client_addr=new IpAddress(client_sock.getInetAddress(), client_port);
- conn.setPeerAddress(peer_addr);
-
- synchronized(conns) {
- Connection tmp=conns.get(peer_addr);
- //Vladimir Nov, 5th, 2007
- //we might have a connection to peer but is that
- //connection still open?
- boolean connectionOpen = tmp != null && !tmp.isSocketClosed();
- if(connectionOpen) {
- if(peer_addr.compareTo(local_addr) > 0) {
- if(log.isTraceEnabled())
- log.trace("peer's address (" + peer_addr + ") is greater than our local address (" +
- local_addr + "), replacing our existing connection");
- // peer's address is greater, add peer's connection to ConnectionTable, destroy existing connection
- removeConnection(peer_addr);
- addConnection(peer_addr, conn);
- notifyConnectionOpened(peer_addr);
- }
- else {
- if(log.isTraceEnabled())
- log.trace("peer's address (" + peer_addr + ") is smaller than our local address (" +
- local_addr + "), rejecting peer connection request");
- conn.destroy();
- continue;
- }
- }
- else {
- addConnection(peer_addr, conn);
- notifyConnectionOpened(peer_addr);
- }
- }
-
- conn.init(); // starts handler thread on this socket
- }
- catch(SocketTimeoutException timeout_ex) {
- if(log.isWarnEnabled()) log.warn("timed out waiting for peer address, closing connection " + conn + ": " + timeout_ex);
- if(conn != null)
- conn.destroy();
- if(srv_sock == null)
- break; // socket was closed, therefore stop
- }
- catch(SocketException sock_ex) {
- if(log.isWarnEnabled() && srv_sock != null) log.warn("Could not read accept connection from peer " + sock_ex);
- if(conn != null)
- conn.destroy();
- if(srv_sock == null)
- break; // socket was closed, therefore stop
- }
- catch(Throwable ex) {
- if(log.isWarnEnabled()) log.warn("Could not read accept connection from peer " + ex);
- if(srv_sock == null)
- break; // socket was closed, therefore stop
- }
- }
- if(client_sock != null)
- try {client_sock.close();} catch(IOException e) {}
- if(log.isTraceEnabled())
- log.trace(Thread.currentThread().getName() + " terminated");
- }
-
-
- /** Finds first available port starting at start_port and returns server socket.
- * Will not bind to port >end_port. Sets srv_port */
- protected ServerSocket createServerSocket(int start_port, int end_port) throws Exception {
- ServerSocket ret=null;
-
- while(true) {
- try {
- if(start_port > 0 && pm != null)
- start_port=pm.getNextAvailablePort(start_port);
- if(bind_addr == null)
- ret=new ServerSocket(start_port);
- else {
- // changed (bela Sept 7 2007): we accept connections on all NICs
- ret=new ServerSocket(start_port, backlog, null);
- }
- }
- catch(BindException bind_ex) {
- if (start_port==end_port) throw new BindException("No available port to bind to");
- if(bind_addr != null && !bind_addr.isLoopbackAddress()) {
- NetworkInterface nic=NetworkInterface.getByInetAddress(bind_addr);
- if(nic == null)
- throw new BindException("bind_addr " + bind_addr + " is not a valid interface");
- }
- start_port++;
- continue;
- }
- catch(IOException io_ex) {
- if(log.isErrorEnabled()) log.error("exception is " + io_ex);
- }
- srv_port=start_port;
- break;
- }
- return ret;
- }
-
-
-
-
-}
-
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/ConnectionTableNIO.java libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/ConnectionTableNIO.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/ConnectionTableNIO.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/ConnectionTableNIO.java 2011-10-18 11:22:35.000000000 +0000
@@ -1,12 +1,10 @@
-// $Id: ConnectionTableNIO.java,v 1.41 2008/09/25 14:20:51 belaban Exp $
package org.jgroups.blocks;
-import org.apache.commons.logging.Log;
+import org.jgroups.logging.Log;
import org.jgroups.Address;
import org.jgroups.Global;
import org.jgroups.stack.IpAddress;
-import org.jgroups.util.PortsManager;
import org.jgroups.util.ShutdownRejectedExecutionHandler;
import java.io.IOException;
@@ -120,21 +118,6 @@
start();
}
- public ConnectionTableNIO(Receiver r, InetAddress bind_addr, InetAddress external_addr,
- int srv_port, int max_port, PortsManager pm,
- boolean doStart)
- throws Exception
- {
- setReceiver(r);
- this.external_addr=external_addr;
- this.bind_addr=bind_addr;
- this.srv_port=srv_port;
- this.max_port=max_port;
- this.pm=pm;
- use_reaper=true;
- if(doStart)
- start();
- }
/**
@@ -180,25 +163,6 @@
start();
}
- public ConnectionTableNIO(Receiver r, InetAddress bind_addr, InetAddress external_addr,
- int srv_port, int max_port, PortsManager pm,
- long reaper_interval, long conn_expire_time, boolean doStart
- ) throws Exception
- {
- setReceiver(r);
- this.bind_addr=bind_addr;
- this.external_addr=external_addr;
- this.srv_port=srv_port;
- this.max_port=max_port;
- this.pm=pm;
- this.reaper_interval=reaper_interval;
- this.conn_expire_time=conn_expire_time;
- use_reaper=true;
- if(doStart)
- start();
- }
-
-
public int getReaderThreads() { return m_reader_threads; }
@@ -246,7 +210,7 @@
/**
* Try to obtain correct Connection (or create one if not yet existent)
*/
- ConnectionTable.Connection getConnection(Address dest) throws Exception
+ BasicConnectionTable.Connection getConnection(Address dest) throws Exception
{
Connection conn;
SocketChannel sock_ch;
@@ -623,9 +587,6 @@
m_serverSocketChannel = ServerSocketChannel.open();
m_serverSocketChannel.configureBlocking(false);
- if(start_port > 0 && pm != null)
- start_port=pm.getNextAvailablePort(start_port);
-
while (true)
{
try
@@ -697,7 +658,7 @@
return Selector.open();
} catch (IOException e)
{
- if (log.isErrorEnabled()) log.error(e);
+ if (log.isErrorEnabled()) log.error(e.toString());
throw new IllegalStateException(e.getMessage());
}
@@ -991,7 +952,7 @@
}
}
- class Connection extends ConnectionTable.Connection {
+ class Connection extends BasicConnectionTable.Connection {
private SocketChannel sock_ch = null;
private WriteHandler m_writeHandler;
private SelectorWriteHandler m_selectorWriteHandler;
@@ -1043,7 +1004,7 @@
return sock_ch;
}
- void closeSocket()
+ synchronized void closeSocket()
{
if (sock_ch != null)
@@ -1102,7 +1063,7 @@
}
catch (IOException e)
{
- if (log.isErrorEnabled()) log.error(e);
+ if (log.isErrorEnabled()) log.error(e.toString());
throw new IllegalStateException(e.getMessage());
}
}
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/DistributedHashtable.java libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/DistributedHashtable.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/DistributedHashtable.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/DistributedHashtable.java 1970-01-01 00:00:00.000000000 +0000
@@ -1,703 +0,0 @@
-// $Id: DistributedHashtable.java,v 1.35 2008/04/08 14:41:22 belaban Exp $
-
-package org.jgroups.blocks;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jgroups.*;
-import org.jgroups.annotations.Unsupported;
-import org.jgroups.persistence.CannotPersistException;
-import org.jgroups.persistence.CannotRemoveException;
-import org.jgroups.persistence.PersistenceFactory;
-import org.jgroups.persistence.PersistenceManager;
-import org.jgroups.util.Promise;
-import org.jgroups.util.Util;
-
-import java.io.*;
-import java.util.*;
-
-
-/**
- * Provides the abstraction of a java.util.Hashtable that is replicated at several
- * locations. Any change to the hashtable (clear, put, remove etc) will transparently be
- * propagated to all replicas in the group. All read-only methods will always access the
- * local replica.
- * Both keys and values added to the hashtable must be serializable, the reason
- * being that they will be sent across the network to all replicas of the group. Having said
- * this, it is now for example possible to add RMI remote objects to the hashtable as they
- * are derived from java.rmi.server.RemoteObject which in turn is serializable.
- * This allows to lookup shared distributed objects by their name and invoke methods on them,
- * regardless of one's onw location. A DistributedHashtable thus allows to
- * implement a distributed naming service in just a couple of lines.
- * An instance of this class will contact an existing member of the group to fetch its
- * initial state (using the state exchange funclet StateExchangeFunclet.
- * @author Bela Ban
- * @author Alfonso Olias-Sanz
- * @version $Id: DistributedHashtable.java,v 1.35 2008/04/08 14:41:22 belaban Exp $
- * @deprecated Use {@link org.jgroups.blocks.ReplicatedHashMap} instead
- */
-@Unsupported
-public class DistributedHashtable extends Hashtable implements ExtendedMessageListener, ExtendedMembershipListener {
- private static final long serialVersionUID=7910133360803785134L;
-
-
- public interface Notification {
- void entrySet(Object key, Object value);
- void entryRemoved(Object key);
- void viewChange(Vector new_mbrs, Vector old_mbrs);
- void contentsSet(Map new_entries);
- void contentsCleared();
- }
-
-
- private transient Channel channel;
- protected transient RpcDispatcher disp=null;
- private String groupname=null;
- private final transient Vector notifs=new Vector(); // to be notified when mbrship changes
- private final Vector members=new Vector(); // keeps track of all DHTs
- private transient Class[] put_signature=null;
- private transient Class[] putAll_signature=null;
- private transient Class[] clear_signature=null;
- private transient Class[] remove_signature=null;
- private transient boolean persistent=false; // whether to use PersistenceManager to save state
- private transient PersistenceManager persistence_mgr=null;
-
- /** Determines when the updates have to be sent across the network, avoids sending unnecessary
- * messages when there are no member in the group */
- private transient boolean send_message = false;
-
- protected final transient Promise state_promise=new Promise();
-
- protected final Log log=LogFactory.getLog(this.getClass());
-
-
-
-
- /**
- * Creates a DistributedHashtable
- * @param groupname The name of the group to join
- * @param factory The ChannelFactory which will be used to create a channel
- * @param properties The property string to be used to define the channel. This will override the properties of
- * the factory. If null, then the factory properties will be used
- * @param state_timeout The time to wait until state is retrieved in milliseconds. A value of 0 means wait forever.
- */
- public DistributedHashtable(String groupname, ChannelFactory factory,
- String properties, long state_timeout)
- throws ChannelException {
- this.groupname=groupname;
- initSignatures();
- if(factory != null) {
- channel=properties != null? factory.createChannel((Object)properties) : factory.createChannel();
- }
- else {
- channel=new JChannel(properties);
- }
- disp=new RpcDispatcher(channel, this, this, this);
- channel.connect(groupname);
- start(state_timeout);
- }
-
- /**
- * Creates a DisttributedHashtable. Optionally the contents can be saved to
- * persistemt storage using the {@link PersistenceManager}.
- * @param groupname Name of the group to join
- * @param factory Instance of a ChannelFactory to create the channel
- * @param properties Protocol stack properties. This will override the properties of the factory. If
- * null, then the factory properties will be used
- * @param persistent Whether the contents should be persisted
- * @param state_timeout Max number of milliseconds to wait until state is
- * retrieved
- */
- public DistributedHashtable(String groupname, ChannelFactory factory, String properties,
- boolean persistent, long state_timeout)
- throws ChannelException {
- this.groupname=groupname;
- this.persistent=persistent;
- initSignatures();
- if(factory != null) {
- channel=properties != null? factory.createChannel((Object)properties) : factory.createChannel();
- }
- else {
- channel=new JChannel(properties);
- }
- disp=new RpcDispatcher(channel, this, this, this);
- channel.connect(groupname);
- start(state_timeout);
- }
-
-
- public DistributedHashtable(Channel channel, long state_timeout) {
- this(channel, false, state_timeout);
- }
-
-
- public DistributedHashtable(Channel channel, boolean persistent, long state_timeout) {
- this.groupname = channel.getClusterName();
- this.channel = channel;
- this.persistent=persistent;
- init(state_timeout);
- }
-
- /**
- * Uses a user-provided PullPushAdapter to create the dispatcher rather than a Channel. If id is non-null, it will be
- * used to register under that id. This is typically used when another building block is already using
- * PullPushAdapter, and we want to add this building block in addition. The id is the used to discriminate
- * between messages for the various blocks on top of PullPushAdapter. If null, we will assume we are the
- * first block created on PullPushAdapter.
- * @param adapter The PullPushAdapter which to use as underlying transport
- * @param id A serializable object (e.g. an Integer) used to discriminate (multiplex/demultiplex) between
- * requests/responses for different building blocks on top of PullPushAdapter.
- * @param state_timeout Max number of milliseconds to wait until state is
- * retrieved
- */
- public DistributedHashtable(PullPushAdapter adapter, Serializable id, long state_timeout)
- throws ChannelNotConnectedException, ChannelClosedException {
- initSignatures();
- this.channel = (Channel)adapter.getTransport();
- this.groupname = this.channel.getClusterName();
- disp=new RpcDispatcher(adapter, id, this, this, this);
- start(state_timeout);
- }
-
- public DistributedHashtable(PullPushAdapter adapter, Serializable id) {
- initSignatures();
- this.channel = (Channel)adapter.getTransport();
- this.groupname = this.channel.getClusterName();
- disp=new RpcDispatcher(adapter, id, this, this, this);
- }
-
- protected final void init(long state_timeout) {
- initSignatures();
- disp = new RpcDispatcher(channel, this, this, this);
-
- // Changed by bela (jan 20 2003): start() has to be called by user (only when providing
- // own channel). First, Channel.connect() has to be called, then start().
- // start(state_timeout);
- }
-
-
- /**
- * Fetches the state
- * @param state_timeout
- * @throws ChannelClosedException
- * @throws ChannelNotConnectedException
- */
- public final void start(long state_timeout) throws ChannelClosedException, ChannelNotConnectedException {
- boolean rc;
- if(persistent) {
- if(log.isInfoEnabled()) log.info("fetching state from database");
- try {
- persistence_mgr=PersistenceFactory.getInstance().createManager();
- }
- catch(Throwable ex) {
- if(log.isErrorEnabled()) log.error("failed creating PersistenceManager, " +
- "turning persistency off. Exception: " + Util.printStackTrace(ex));
- persistent=false;
- }
- }
-
- state_promise.reset();
- rc=channel.getState(null, state_timeout);
- if(rc) {
- if(log.isInfoEnabled()) log.info("state was retrieved successfully, waiting for setState()");
- Boolean result=state_promise.getResult(state_timeout);
- if(result == null) {
- if(log.isErrorEnabled()) log.error("setState() never got called");
- }
- else {
- if(log.isInfoEnabled()) log.info("setState() was called");
- }
- }
- else {
- if(log.isInfoEnabled()) log.info("state could not be retrieved (first member)");
- if(persistent) {
- if(log.isInfoEnabled()) log.info("fetching state from database");
- try {
- Map m=persistence_mgr.retrieveAll();
- if(m != null) {
- Map.Entry entry;
- Object key, val;
- for(Iterator it=m.entrySet().iterator(); it.hasNext();) {
- entry=(Map.Entry)it.next();
- key=entry.getKey();
- val=entry.getValue();
- if(log.isInfoEnabled()) log.info("inserting " + key + " --> " + val);
- put(key, val); // will replicate key and value
- }
- }
- }
- catch(Throwable ex) {
- if(log.isErrorEnabled()) log.error("failed creating PersistenceManager, " +
- "turning persistency off. Exception: " + Util.printStackTrace(ex));
- persistent=false;
- }
- }
- }
- }
-
-
- public Address getLocalAddress() {return channel != null ? channel.getLocalAddress() : null;}
- public String getGroupName() {return groupname;}
- public Channel getChannel() {return channel;}
- public boolean getPersistent() {return persistent;}
- public void setPersistent(boolean p) {persistent=p;}
-
-
- public void setDeadlockDetection(boolean flag) {
- if(disp != null)
- disp.setDeadlockDetection(flag);
- }
-
- public void addNotifier(Notification n) {
- if(!notifs.contains(n))
- notifs.addElement(n);
- }
-
- public void removeNotifier(Notification n) {
- if(notifs.contains(n))
- notifs.removeElement(n);
- }
-
- public void stop() {
- if(disp != null) {
- disp.stop();
- disp=null;
- }
- if(channel != null) {
- channel.close();
- channel=null;
- }
- }
-
-
- /**
- * Maps the specified key to the specified value in the hashtable. Neither of both parameters can be null
- * @param key - the hashtable key
- * @param value - the value
- * @return the previous value of the specified key in this hashtable, or null if it did not have one
- */
- public Object put(Object key, Object value) {
- Object prev_val=get(key);
-
- //Changes done by
- //if true, propagate action to the group
- if(send_message == true) {
- try {
- disp.callRemoteMethods(
- null, "_put", new Object[]{key,value},
- put_signature,
- GroupRequest.GET_ALL,
- 0);
- }
- catch(Exception e) {
- //return null;
- }
- }
- else {
- _put(key, value);
- //don't have to do prev_val = super.put(..) as is done at the beginning
- }
- return prev_val;
- }
-
- /**
- * Copies all of the mappings from the specified Map to this Hashtable These mappings will replace any mappings that this Hashtable had for any of the keys currently in the specified Map.
- * @param m - Mappings to be stored in this map
- */
- public void putAll(Map m) {
- //Changes done by
- //if true, propagate action to the group
- if(send_message == true) {
- try {
- disp.callRemoteMethods(
- null, "_putAll", new Object[]{m},
- putAll_signature,
- GroupRequest.GET_ALL,
- 0);
- }
- catch(Throwable t) {
- }
- }
- else {
- _putAll(m);
- }
- }
-
- /**
- * Clears this hashtable so that it contains no keys
- */
- public void clear() {
- //Changes done by
- //if true, propagate action to the group
- if(send_message == true) {
- try {
- disp.callRemoteMethods(
- null, "_clear", null,
- clear_signature,
- GroupRequest.GET_ALL,
- 0);
- }
- catch(Exception e) {
- if(log.isErrorEnabled()) log.error("exception=" + e);
- }
- }
- else {
- _clear();
- }
- }
-
- /**
- * Removes the key (and its corresponding value) from the Hashtable.
- * @param key - the key to be removed.
- * @return the value to which the key had been mapped in this hashtable, or null if the key did not have a mapping.
- */
- public Object remove(Object key) {
- Object retval = get(key);
-
- //Changes done by
- //if true, propagate action to the group
- if(send_message == true) {
- try {
- disp.callRemoteMethods(
- null, "_remove", new Object[]{key},
- remove_signature,
- GroupRequest.GET_ALL,
- 0);
- //return retval;
- }
- catch(Exception e) {
- //return null;
- }
- }
- else {
- _remove(key);
- //don't have to do retval = super.remove(..) as is done at the beginning
- }
- return retval;
- }
-
-
-
- /*------------------------ Callbacks -----------------------*/
-
- public Object _put(Object key, Object value) {
- Object retval=super.put(key, value);
- if(persistent) {
- try {
- persistence_mgr.save((Serializable)key, (Serializable)value);
- }
- catch(CannotPersistException cannot_persist_ex) {
- if(log.isErrorEnabled()) log.error("failed persisting " + key + " + " +
- value + ", exception=" + cannot_persist_ex);
- }
- catch(Throwable t) {
- if(log.isErrorEnabled()) log.error("failed persisting " + key + " + " +
- value + ", exception=" + Util.printStackTrace(t));
- }
- }
- for(int i=0; i < notifs.size(); i++)
- ((Notification)notifs.elementAt(i)).entrySet(key, value);
- return retval;
- }
-
-
- /**
- * @see java.util.Map#putAll(java.util.Map)
- */
- public void _putAll(Map m) {
- if (m == null)
- return;
-
- // Calling the method below seems okay, but would result in ... deadlock !
- // The reason is that Map.putAll() calls put(), which we override, which results in
- // lock contention for the map.
-
- // ---> super.putAll(m); <--- CULPRIT !!!@#$%$
-
- // That said let's do it the stupid way:
- Map.Entry entry;
- for(Iterator it=m.entrySet().iterator(); it.hasNext();) {
- entry=(Map.Entry)it.next();
- super.put(entry.getKey(), entry.getValue());
- }
-
- if (persistent) {
- try {
- persistence_mgr.saveAll(m);
- }
- catch (CannotPersistException persist_ex) {
- if(log.isErrorEnabled()) log.error("failed persisting contents: " + persist_ex);
- }
- catch (Throwable t) {
- if(log.isErrorEnabled()) log.error("failed persisting contents: " + t);
- }
- }
- for(int i=0; i < notifs.size(); i++)
- ((Notification)notifs.elementAt(i)).contentsSet(m);
- }
-
-
- public void _clear() {
- super.clear();
- if(persistent) {
- try {
- persistence_mgr.clear();
- }
- catch(CannotRemoveException cannot_remove_ex) {
- if(log.isErrorEnabled()) log.error("failed clearing contents, exception=" + cannot_remove_ex);
- }
- catch(Throwable t) {
- if(log.isErrorEnabled()) log.error("failed clearing contents, exception=" + t);
- }
- }
- for(int i=0; i < notifs.size(); i++)
- ((Notification)notifs.elementAt(i)).contentsCleared();
- }
-
-
- public Object _remove(Object key) {
- Object retval=super.remove(key);
- if(persistent) {
- try {
- persistence_mgr.remove((Serializable)key);
- }
- catch(CannotRemoveException cannot_remove_ex) {
- if(log.isErrorEnabled()) log.error("failed clearing contents, exception=" + cannot_remove_ex);
- }
- catch(Throwable t) {
- if(log.isErrorEnabled()) log.error("failed clearing contents, exception=" + t);
- }
- }
- for(int i=0; i < notifs.size(); i++)
- ((Notification)notifs.elementAt(i)).entryRemoved(key);
-
- return retval;
- }
-
- /*----------------------------------------------------------*/
-
-
-
- /*-------------------- State Exchange ----------------------*/
-
- public void receive(Message msg) { }
-
- public byte[] getState() {
- Object key, val;
- Hashtable copy=new Hashtable();
-
- for(Enumeration e=keys(); e.hasMoreElements();) {
- key=e.nextElement();
- val=get(key);
- copy.put(key, val);
- }
- try {
- return Util.objectToByteBuffer(copy);
- }
- catch(Throwable ex) {
- if(log.isErrorEnabled()) log.error("exception marshalling state: " + ex);
- return null;
- }
- }
-
-
- public void setState(byte[] new_state) {
- Hashtable new_copy;
-
- try {
- new_copy=(Hashtable)Util.objectFromByteBuffer(new_state);
- if(new_copy == null)
- return;
- }
- catch(Throwable ex) {
- if(log.isErrorEnabled()) log.error("exception unmarshalling state: " + ex);
- return;
- }
- _putAll(new_copy);
- state_promise.setResult(Boolean.TRUE);
- }
-
-
-
- /*------------------- Membership Changes ----------------------*/
-
- public void viewAccepted(View new_view) {
- Vector new_mbrs=new_view.getMembers();
-
- if(new_mbrs != null) {
- sendViewChangeNotifications(new_mbrs, members); // notifies observers (joined, left)
- members.removeAllElements();
- for(int i=0; i < new_mbrs.size(); i++)
- members.addElement(new_mbrs.elementAt(i));
- }
- //if size is bigger than one, there are more peers in the group
- //otherwise there is only one server.
- send_message=members.size() > 1;
- }
-
-
- /** Called when a member is suspected */
- public void suspect(Address suspected_mbr) {
- ;
- }
-
-
- /** Block sending and receiving of messages until ViewAccepted is called */
- public void block() {}
-
-
-
- void sendViewChangeNotifications(Vector new_mbrs, Vector old_mbrs) {
- Vector joined, left;
- Object mbr;
- Notification n;
-
- if(notifs.size() == 0 || old_mbrs == null || new_mbrs == null ||
- old_mbrs.size() == 0 || new_mbrs.size() == 0)
- return;
-
-
- // 1. Compute set of members that joined: all that are in new_mbrs, but not in old_mbrs
- joined=new Vector();
- for(int i=0; i < new_mbrs.size(); i++) {
- mbr=new_mbrs.elementAt(i);
- if(!old_mbrs.contains(mbr))
- joined.addElement(mbr);
- }
-
-
- // 2. Compute set of members that left: all that were in old_mbrs, but not in new_mbrs
- left=new Vector();
- for(int i=0; i < old_mbrs.size(); i++) {
- mbr=old_mbrs.elementAt(i);
- if(!new_mbrs.contains(mbr)) {
- left.addElement(mbr);
- }
- }
-
- for(int i=0; i < notifs.size(); i++) {
- n=(Notification)notifs.elementAt(i);
- n.viewChange(joined, left);
- }
- }
-
-
- final void initSignatures() {
- try {
- if(put_signature == null) {
- put_signature=new Class[] {Object.class,Object.class};
- }
-
- if(putAll_signature == null) {
- putAll_signature=new Class[] {Map.class};
- }
-
- if(clear_signature == null)
- clear_signature=new Class[0];
-
- if(remove_signature == null) {
- remove_signature=new Class[] {Object.class};
- }
- }
- catch(Throwable ex) {
- if(log.isErrorEnabled()) log.error("exception=" + ex);
- }
- }
-
- public static void main(String[] args) {
- try {
- // The setup here is kind of weird:
- // 1. Create a channel
- // 2. Create a DistributedHashtable (on the channel)
- // 3. Connect the channel (so the HT gets a VIEW_CHANGE)
- // 4. Start the HT
- //
- // A simpler setup is
- // DistributedHashtable ht = new DistributedHashtable("demo", null,
- // "file://c:/JGroups-2.0/conf/state_transfer.xml", 5000);
-
- JChannel c = new JChannel("file:/c:/JGroups-2.0/conf/state_transfer.xml");
- DistributedHashtable ht = new DistributedHashtable(c, false, 5000);
- c.connect("demo");
- ht.start(5000);
-
-
-
- ht.put("name", "Michelle Ban");
- Object old_key = ht.remove("name");
- System.out.println("old key was " + old_key);
- ht.put("newkey", "newvalue");
-
- Map m = new HashMap();
- m.put("k1", "v1");
- m.put("k2", "v2");
-
- ht.putAll(m);
-
- System.out.println("hashmap is " + ht);
- }
- catch (Throwable t) {
- t.printStackTrace();
- }
- }
-
- public byte[] getState(String state_id) {
- // not implemented
- return null;
- }
-
- public void getState(OutputStream ostream) {
- Object key, val;
- Hashtable copy=new Hashtable();
- ObjectOutputStream oos = null;
-
- for(Enumeration e=keys(); e.hasMoreElements();) {
- key=e.nextElement();
- val=get(key);
- copy.put(key, val);
- }
- try {
- oos = new ObjectOutputStream(ostream);
- oos.writeObject(copy);
- }
- catch(Throwable ex) {
- if(log.isErrorEnabled()) log.error("exception marshalling state: " + ex);
- }
- finally{
- Util.close(oos);
- }
- }
-
- public void getState(String state_id, OutputStream ostream) {
- }
-
- public void setState(String state_id, byte[] state) {
- }
-
- public void setState(InputStream istream) {
- Hashtable new_copy = null;
- ObjectInputStream ois = null;
- try{
- ois = new ObjectInputStream(istream);
- new_copy = (Hashtable) ois.readObject();
- ois.close();
- }catch(Throwable e){
- e.printStackTrace();
- if(log.isErrorEnabled()) log.error("exception marshalling state: " + e);
- }finally{
- Util.close(ois);
- }
- if(new_copy != null)
- _putAll(new_copy);
-
- state_promise.setResult(Boolean.TRUE);
- }
-
- public void setState(String state_id, InputStream istream) {
- }
-
- public void unblock() {
- }
-
-}
-
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/DistributedLockManager.java libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/DistributedLockManager.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/DistributedLockManager.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/DistributedLockManager.java 2011-10-18 11:22:35.000000000 +0000
@@ -1,7 +1,7 @@
package org.jgroups.blocks;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.jgroups.logging.Log;
+import org.jgroups.logging.LogFactory;
import org.jgroups.ChannelException;
import org.jgroups.MembershipListener;
import org.jgroups.View;
@@ -21,9 +21,10 @@
*
* @author Roman Rokytskyy (rrokytskyy@acm.org)
* @author Robert Schaffar-Taurok (robert@fusion.at)
- * @version $Id: DistributedLockManager.java,v 1.12 2008/05/22 09:50:22 belaban Exp $
+ * @deprecated Succeessor is {@link org.jgroups.blocks.locking.LockService}.
*/
@Unsupported
+@Deprecated
public class DistributedLockManager implements TwoPhaseVotingListener, LockManager, VoteResponseProcessor, MembershipListener {
/**
* Definitions for the implementation of the VoteResponseProcessor
@@ -224,7 +225,7 @@
throws LockNotGrantedException, ChannelException
{
if (!(lockId instanceof Serializable) || !(owner instanceof Serializable))
- throw new ClassCastException("DistributedLockManager works only with serializable objects.");
+ throw new IllegalArgumentException("DistributedLockManager works only with serializable objects.");
boolean acquired = votingAdapter.vote(
new AcquireLockDecree(lockId, owner, id), timeout);
@@ -702,6 +703,10 @@
*/
public Object getKey() { return lockId; }
+ public Object getRequester() {
+ return requester;
+ }
+
/**
* This is a place-holder for future lock expiration code.
*/
@@ -729,9 +734,12 @@
}
public boolean equals(Object other) {
-
return other instanceof LockDecree && ((LockDecree)other).lockId.equals(this.lockId);
}
+
+ public String toString() {
+ return "lockId=" + lockId + ", requester=" + requester + ", managerId=" + managerId + ", committed=" + commited;
+ }
}
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/DistributedQueue.java libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/DistributedQueue.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/DistributedQueue.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/DistributedQueue.java 2011-10-18 11:22:35.000000000 +0000
@@ -1,8 +1,7 @@
-// $Id: DistributedQueue.java,v 1.21 2008/04/08 14:41:22 belaban Exp $
package org.jgroups.blocks;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.jgroups.logging.Log;
+import org.jgroups.logging.LogFactory;
import org.jgroups.*;
import org.jgroups.annotations.Unsupported;
import org.jgroups.util.RspList;
@@ -142,7 +141,7 @@
public Address getLocalAddress()
{
- return (channel != null) ? channel.getLocalAddress() : null;
+ return (channel != null) ? channel.getAddress() : null;
}
public Channel getChannel()
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/DistributedTree.java libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/DistributedTree.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/DistributedTree.java 2009-01-05 12:42:12.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/DistributedTree.java 2011-10-18 11:22:35.000000000 +0000
@@ -1,10 +1,9 @@
-// $Id: DistributedTree.java,v 1.19 2008/06/10 10:25:49 belaban Exp $
package org.jgroups.blocks;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.jgroups.logging.Log;
+import org.jgroups.logging.LogFactory;
import org.jgroups.*;
import org.jgroups.annotations.Unsupported;
import org.jgroups.util.Util;
@@ -43,8 +42,7 @@
"UNICAST(timeout=5000):" +
"FRAG(down_thread=false;up_thread=false):" +
"pbcast.GMS(join_timeout=5000;" +
- "shun=false;print_local_addr=true):" +
- // trace=true is not supported anymore
+ "print_local_addr=true):" +
"pbcast.STATE_TRANSFER()";
static final long state_timeout=5000; // wait 5 secs max to obtain state
@@ -108,7 +106,7 @@
}
public Object getLocalAddress() {
- return channel != null? channel.getLocalAddress() : null;
+ return channel != null? channel.getAddress() : null;
}
public void setDeadlockDetection(boolean flag) {
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/executor/ExecutionCompletionService.java libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/executor/ExecutionCompletionService.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/executor/ExecutionCompletionService.java 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/executor/ExecutionCompletionService.java 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,163 @@
+package org.jgroups.blocks.executor;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletionService;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.jgroups.util.FutureListener;
+import org.jgroups.util.NotifyingFuture;
+
+/**
+ * A {@link CompletionService} that uses a supplied {@link ExecutionService}
+ * to execute tasks. This class arranges that submitted tasks are,
+ * upon completion, placed on a queue accessible using take.
+ * The class is lightweight enough to be suitable for transient use
+ * when processing groups of tasks.
+ *
+ * This class must be used instead of a {@link ExecutorCompletionService}
+ * provided from java.util.concurrent package. The
+ * {@link ExecutorCompletionService} may not be used since it requires the use
+ * of a non serializable RunnableFuture object. Since a ExecutionService
+ * may only be used with serializable request objects, this class must be used
+ * instead.
+ */
+public class ExecutionCompletionService implements CompletionService {
+ protected final ExecutionService executor;
+ protected final BlockingQueue> completionQueue;
+ protected final QueueingListener listener;
+
+ protected class QueueingListener implements FutureListener {
+ @Override
+ public void futureDone(Future future) {
+ // This is a safe cast since this listener should only used
+ // in this class
+ completionQueue.add((NotifyingFuture)future);
+ }
+
+ }
+
+ /**
+ * Creates an ExecutorCompletionService using the supplied
+ * executor for base task execution and a
+ * {@link LinkedBlockingQueue} as a completion queue.
+ *
+ * @param executor the executor to use
+ * @throws NullPointerException if executor is null
+ */
+ public ExecutionCompletionService(ExecutionService executor) {
+ this(executor, null, null);
+ }
+
+ /**
+ * Creates an ExecutorCompletionService using the supplied
+ * executor for base task execution and the supplied queue as its
+ * completion queue.
+ *
+ * @param executor the executor to use
+ * @param completionQueue the queue to use as the completion queue
+ * normally one dedicated for use by this service
+ * @throws NullPointerException if executor is null
+ */
+ public ExecutionCompletionService(ExecutionService executor,
+ BlockingQueue> completionQueue) {
+ this(executor, completionQueue, null);
+ }
+
+ /**
+ * This constructor is here if someone wants to override this class and
+ * provide their own QueueingListener to possibly listen in on futures
+ * being finished
+ * @param executor the executor to use
+ * @param completionQueue the queue to use as the completion queue
+ * normally one dedicated for use by this service
+ * @param listener the listener to notify. To work properly this listner
+ * should at minimum call the super.futureDone or else this
+ * completion service may not work correctly.
+ * @throws NullPointerException if executor is null
+ */
+ protected ExecutionCompletionService(ExecutionService executor,
+ BlockingQueue> completionQueue,
+ QueueingListener listener) {
+ if (executor == null)
+ throw new NullPointerException();
+ this.executor = executor;
+
+ if (completionQueue == null) {
+ this.completionQueue = new LinkedBlockingQueue>();
+ }
+ else {
+ this.completionQueue = completionQueue;
+ }
+
+ if (listener == null) {
+ this.listener = new QueueingListener();
+ }
+ else {
+ this.listener = listener;
+ }
+ }
+
+ /**
+ * {@inheritDoc CompletionService}
+ *
+ * This future object may not be used as a NotifyingFuture. That is because
+ * internally this class sets the listener to provide ability to add to the queue.
+ */
+ public Future submit(Callable task) {
+ if (task == null) throw new NullPointerException();
+ NotifyingFuture f = executor.submit(task);
+ f.setListener(listener);
+ return f;
+ }
+
+ /**
+ * {@inheritDoc CompletionService}
+ *
+ * This future object may not be used as a NotifyingFuture. That is because
+ * internally this class sets the listener to provide ability to add to the queue.
+ */
+ public Future submit(Runnable task, V result) {
+ if (task == null) throw new NullPointerException();
+ NotifyingFuture f = executor.submit(task, result);
+ f.setListener(listener);
+ return f;
+ }
+
+ /**
+ * {@inheritDoc CompletionService}
+ *
+ * This future may safely be used as a NotifyingFuture if desired. This
+ * is because if it tries to set a listener it will be called immediately
+ * since the task has already been completed.
+ */
+ public NotifyingFuture take() throws InterruptedException {
+ return completionQueue.take();
+ }
+
+ /**
+ * {@inheritDoc CompletionService}
+ *
+ * This future may safely be used as a NotifyingFuture if desired. This
+ * is because if it tries to set a listener it will be called immediately
+ * since the task has already been completed.
+ */
+ public NotifyingFuture poll() {
+ return completionQueue.poll();
+ }
+
+ /**
+ * {@inheritDoc CompletionService}
+ *
+ * This future may safely be used as a NotifyingFuture if desired. This
+ * is because if it tries to set a listener it will be called immediately
+ * since the task has already been completed.
+ */
+ public NotifyingFuture poll(long timeout, TimeUnit unit) throws InterruptedException {
+ return completionQueue.poll(timeout, unit);
+ }
+
+}
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/executor/ExecutionRunner.java libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/executor/ExecutionRunner.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/executor/ExecutionRunner.java 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/executor/ExecutionRunner.java 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,92 @@
+package org.jgroups.blocks.executor;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.jgroups.JChannel;
+import org.jgroups.logging.Log;
+import org.jgroups.logging.LogFactory;
+import org.jgroups.protocols.Executing;
+
+/**
+ * This class is to be used to pick up execution requests and actually run
+ * them. A single instance can be used across any number of threads.
+ *
+ * @author wburns
+ */
+public class ExecutionRunner implements Runnable {
+ protected JChannel ch;
+ protected Executing _execProt;
+
+ public ExecutionRunner(JChannel channel) {
+ setChannel(channel);
+ }
+
+ public void setChannel(JChannel ch) {
+ this.ch=ch;
+ _execProt=(Executing)ch.getProtocolStack().findProtocol(Executing.class);
+ if(_execProt == null)
+ throw new IllegalStateException("Channel configuration must include a executing protocol " +
+ "(subclass of " + Executing.class.getName() + ")");
+ }
+
+ // @see java.lang.Runnable#run()
+ @Override
+ public void run() {
+ final AtomicBoolean shutdown = new AtomicBoolean();
+ // This thread is only spawned so that we can differentiate between
+ // an interrupt of a task and an interrupt causing a shutdown of
+ // runner itself.
+ Thread executionThread = new Thread() {
+
+ // @see java.lang.Thread#run()
+ @Override
+ public void run() {
+ Runnable runnable = null;
+ // This task exits by being interrupted when the task isn't running
+ while (!shutdown.get()) {
+ runnable = (Runnable)ch.downcall(new ExecutorEvent(
+ ExecutorEvent.CONSUMER_READY, null));
+ if (Thread.interrupted()) {
+ if (runnable != null) {
+ // We assume that if an interrupt occurs here that
+ // it is trying to close down the task. Since the
+ // window is so small. Therefore if we get a
+ // task we need to reject it so it can be passed
+ // off to a different consumer
+ ch.down(new ExecutorEvent(ExecutorEvent.TASK_COMPLETE,
+ new Object[]{runnable, new InterruptedException()}));
+ }
+ continue;
+ }
+ Throwable throwable = null;
+ try {
+ runnable.run();
+ }
+ // This can only happen if user is directly doing an execute(Runnable)
+ catch (Throwable t) {
+ _logger.error("Unexpected Runtime Error encountered in Runnable request", t);
+ throwable = t;
+ }
+ ch.down(new ExecutorEvent(ExecutorEvent.TASK_COMPLETE,
+ throwable != null ? new Object[]{runnable, throwable} : runnable));
+ }
+ }
+ };
+
+ executionThread.setName(Thread.currentThread().getName() + "- Task Runner");
+ executionThread.start();
+
+ try {
+ executionThread.join();
+ }
+ catch (InterruptedException e) {
+ shutdown.set(true);
+ executionThread.interrupt();
+ if (_logger.isTraceEnabled()) {
+ _logger.trace("Shutting down Execution Runner");
+ }
+ }
+ }
+
+ protected static final Log _logger = LogFactory.getLog(ExecutionRunner.class);
+}
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/executor/ExecutionService.java libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/executor/ExecutionService.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/executor/ExecutionService.java 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/executor/ExecutionService.java 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,805 @@
+package org.jgroups.blocks.executor;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.AbstractExecutorService;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletionService;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.RunnableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.jgroups.JChannel;
+import org.jgroups.protocols.Executing;
+import org.jgroups.util.FutureListener;
+import org.jgroups.util.NotifyingFuture;
+import org.jgroups.util.Streamable;
+import org.jgroups.util.Util;
+
+/**
+ * This is a jgroups implementation of an ExecutorService, where the consumers
+ * are running on any number of nodes. The nodes should run
+ * {@link ExecutionRunner} to start picking up requests.
+ *
+ * Every future object returned will be a {@link NotifyingFuture} which
+ * allows for not having to query the future and have a callback instead. This
+ * can then be used as a workflow to submit other tasks sequentially or also to
+ * query the future for the value at that time.
+ *
+ * Every callable or runnable submitted must be either {@link Serializable} or
+ * {@link Streamable}. Also the value returned from
+ * a callable must {@link Serializable} or
+ * {@link Streamable}. Unfortunately if the value returned is not serializable
+ * then a {@link NotSerializableException} will be thrown as the cause.
+ * @author wburns
+ * @since 2.12.0
+ */
+public class ExecutionService extends AbstractExecutorService {
+ protected JChannel ch;
+ protected Executing _execProt;
+
+ protected Lock _unfinishedLock = new ReentrantLock();
+ protected Condition _unfinishedCondition = _unfinishedLock.newCondition();
+
+ protected Set> _unfinishedFutures = new HashSet>();
+
+ protected AtomicBoolean _shutdown = new AtomicBoolean(false);
+
+ public ExecutionService() {
+
+ }
+
+ public ExecutionService(JChannel ch) {
+ setChannel(ch);
+ }
+
+ public void setChannel(JChannel ch) {
+ this.ch=ch;
+ _execProt=(Executing)ch.getProtocolStack().findProtocol(Executing.class);
+ if(_execProt == null)
+ throw new IllegalStateException("Channel configuration must include a executing protocol " +
+ "(subclass of " + Executing.class.getName() + ")");
+ }
+
+ // @see java.util.concurrent.AbstractExecutorService#submit(java.lang.Runnable, java.lang.Object)
+ @Override
+ public NotifyingFuture submit(Runnable task, T result) {
+ // This cast is okay cause we control creation of the task
+ return (NotifyingFuture)super.submit(task, result);
+ }
+
+ // @see java.util.concurrent.AbstractExecutorService#submit(java.util.concurrent.Callable)
+ @Override
+ public NotifyingFuture submit(Callable task) {
+ // This cast is okay cause we control creation of the task
+ return (NotifyingFuture)super.submit(task);
+ }
+
+ /**
+ * This is basically a copy of the FutureTask in java.util.concurrent but
+ * added serializable to it. Also added in the NotifyingFuture
+ * so that the channel can update the future when the value is calculated.
+ *
+ * @param
+ * @author wburns
+ */
+ public static class DistributedFuture implements RunnableFuture,
+ ExecutorNotification, NotifyingFuture {
+ // @see java.lang.Object#toString()
+ @Override
+ public String toString() {
+ return "DistributedFuture [callable=" + sync.callable + "]";
+ }
+
+ /** Synchronization control for FutureTask */
+ protected final Sync sync;
+
+ /** The following values are only used on the client side */
+ private final JChannel channel;
+ private final Set> _unfinishedFutures;
+ private final Lock _unfinishedLock;
+ private final Condition _unfinishedCondition;
+ private volatile FutureListener _listener;
+
+ /**
+ * Creates a FutureTask that will upon running, execute the
+ * given Callable.
+ *
+ * @param channel The channel that messages are sent down
+ * @param unfinishedLock The lock which protects the futuresToFinish
+ * set object.
+ * @param condition The condition to signal when this future finishes
+ * @param futuresToFinish The set to remove this future from when
+ * it is finished.
+ * @param callable The callable to actually run on the server side
+ */
+ public DistributedFuture(JChannel channel, Lock unfinishedLock,
+ Condition condition,
+ Set> futuresToFinish,
+ Callable callable) {
+ if (callable == null)
+ throw new NullPointerException();
+ sync = new Sync(this, callable);
+ this.channel = channel;
+ // We keep the real copy to update the outside
+ _unfinishedFutures = futuresToFinish;
+ _unfinishedLock = unfinishedLock;
+ _unfinishedCondition = condition;
+ }
+
+ /**
+ * Creates a FutureTask that will upon running, execute the
+ * given Runnable, and arrange that get will return the
+ * given result on successful completion.
+ *
+ * @param channel The channel that messages are sent down
+ * @param unfinishedLock The lock which protects the futuresToFinish
+ * set object.
+ * @param condition The condition to signal when this future finishes
+ * @param futuresToFinish The set to remove this future from when
+ * it is finished.
+ * @param runnable the runnable task
+ * @param result the result to return on successful completion. If
+ * you don't need a particular result, consider using
+ * constructions of the form:
+ * Future<?> f = new FutureTask<Object>(runnable, null)
+ * @throws NullPointerException if runnable is null
+ */
+ public DistributedFuture(JChannel channel, Lock unfinishedLock,
+ Condition condition, Set> futuresToFinish,
+ Runnable runnable, V result) {
+ sync = new Sync(this, new RunnableAdapter(runnable, result));
+ this.channel = channel;
+ // We keep the real copy to update the outside
+ _unfinishedFutures = futuresToFinish;
+ _unfinishedLock = unfinishedLock;
+ _unfinishedCondition = condition;
+ }
+
+ public Callable getCallable() {
+ return sync.callable;
+ }
+
+ public boolean isCancelled() {
+ return sync.innerIsCancelled();
+ }
+
+ public boolean isDone() {
+ return sync.innerIsDone();
+ }
+
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ if (sync.innerIsDone()) {
+ return false;
+ }
+ // This will only happen on calling side since it is transient
+ if (channel != null) {
+ return (Boolean)channel.downcall(new ExecutorEvent(
+ ExecutorEvent.TASK_CANCEL, new Object[] {this, mayInterruptIfRunning}));
+ }
+ return sync.innerCancel(mayInterruptIfRunning);
+ }
+
+ /**
+ * @throws CancellationException {@inheritDoc}
+ */
+ public V get() throws InterruptedException, ExecutionException {
+ return sync.innerGet();
+ }
+
+ /**
+ * @throws CancellationException {@inheritDoc}
+ */
+ public V get(long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ return sync.innerGet(unit.toNanos(timeout));
+ }
+
+ /**
+ * Protected method invoked when this task transitions to state
+ * isDone (whether normally or via cancellation). The
+ * default implementation does nothing. Subclasses may override
+ * this method to invoke completion callbacks or perform
+ * bookkeeping. Note that you can query status inside the
+ * implementation of this method to determine whether this task
+ * has been cancelled.
+ */
+ protected void done() {
+ _unfinishedLock.lock();
+ try {
+ _unfinishedFutures.remove(this);
+ _unfinishedCondition.signalAll();
+ }
+ finally {
+ _unfinishedLock.unlock();
+ }
+ // We assign the listener to a local variable so we don't have to
+ // worry about it becoming null inside the if
+ FutureListener listener = _listener;
+ // We don't want this to run on server
+ if (listener != null) {
+ listener.futureDone(this);
+ }
+ }
+
+ @Override
+ public NotifyingFuture setListener(FutureListener listener) {
+ _listener = listener;
+ if (sync.innerIsDone()) {
+ _listener.futureDone(this);
+ }
+ return this;
+ }
+
+ /**
+ * Sets the result of this Future to the given value unless
+ * this future has already been set or has been cancelled.
+ * This method is invoked internally by the run method
+ * upon successful completion of the computation.
+ * @param v the value
+ */
+ protected void set(V v) {
+ sync.innerSet(v);
+ }
+
+ /**
+ * Causes this future to report an ExecutionException
+ * with the given throwable as its cause, unless this Future has
+ * already been set or has been cancelled.
+ * This method is invoked internally by the run method
+ * upon failure of the computation.
+ * @param t the cause of failure
+ */
+ protected void setException(Throwable t) {
+ sync.innerSetException(t);
+ }
+
+ // The following (duplicated) doc comment can be removed once
+ //
+ // 6270645: Javadoc comments should be inherited from most derived
+ // superinterface or superclass
+ // is fixed.
+ /**
+ * Sets this Future to the result of its computation
+ * unless it has been cancelled.
+ */
+ public void run() {
+ sync.innerRun();
+ }
+
+ /**
+ * Synchronization control for FutureTask. Note that this must be
+ * a non-static inner class in order to invoke the protected
+ * done method. For clarity, all inner class support
+ * methods are same as outer, prefixed with "inner".
+ *
+ * Uses AQS sync state to represent run status
+ */
+ protected static final class Sync extends AbstractQueuedSynchronizer {
+ private static final long serialVersionUID = -7828117401763700385L;
+
+ /** State value representing that task is running */
+ protected static final int RUNNING = 1;
+ /** State value representing that task ran */
+ protected static final int RAN = 2;
+ /** State value representing that task was cancelled */
+ protected static final int CANCELLED = 4;
+
+ /** The containing future */
+ protected final DistributedFuture future;
+ /** The underlying callable */
+ protected final Callable callable;
+ /** The result to return from get() */
+ protected V result;
+ /** The exception to throw from get() */
+ protected Throwable exception;
+
+ /**
+ * The thread running task. When nulled after set/cancel, this
+ * indicates that the results are accessible. Must be
+ * volatile, to ensure visibility upon completion.
+ */
+ protected transient volatile Thread runner;
+
+ public Sync(DistributedFuture future, Callable callable) {
+ this.future = future;
+ this.callable = callable;
+ }
+
+ private static boolean ranOrCancelled(int state) {
+ return (state & (RAN | CANCELLED)) != 0;
+ }
+
+ /**
+ * Implements AQS base acquire to succeed if ran or cancelled
+ */
+ protected int tryAcquireShared(int ignore) {
+ return innerIsDone()? 1 : -1;
+ }
+
+ /**
+ * Implements AQS base release to always signal after setting
+ * final done status by nulling runner thread.
+ */
+ protected boolean tryReleaseShared(int ignore) {
+ runner = null;
+ return true;
+ }
+
+ boolean innerIsCancelled() {
+ return getState() == CANCELLED;
+ }
+
+ boolean innerIsDone() {
+ return ranOrCancelled(getState()) && runner == null;
+ }
+
+ V innerGet() throws InterruptedException, ExecutionException {
+ acquireSharedInterruptibly(0);
+ if (getState() == CANCELLED)
+ throw new CancellationException();
+ if (exception != null)
+ throw new ExecutionException(exception);
+ return result;
+ }
+
+ V innerGet(long nanosTimeout) throws InterruptedException, ExecutionException, TimeoutException {
+ if (!tryAcquireSharedNanos(0, nanosTimeout))
+ throw new TimeoutException();
+ if (getState() == CANCELLED)
+ throw new CancellationException();
+ if (exception != null)
+ throw new ExecutionException(exception);
+ return result;
+ }
+
+ void innerSet(V v) {
+ for (;;) {
+ int s = getState();
+ if (s == RAN)
+ return;
+ if (s == CANCELLED) {
+ // aggressively release to set runner to null,
+ // in case we are racing with a cancel request
+ // that will try to interrupt runner
+ releaseShared(0);
+ return;
+ }
+ if (compareAndSetState(s, RAN)) {
+ result = v;
+ releaseShared(0);
+ future.done();
+ return;
+ }
+ }
+ }
+
+ void innerSetException(Throwable t) {
+ for (;;) {
+ int s = getState();
+ if (s == RAN)
+ return;
+ if (s == CANCELLED) {
+ // aggressively release to set runner to null,
+ // in case we are racing with a cancel request
+ // that will try to interrupt runner
+ releaseShared(0);
+ return;
+ }
+ if (compareAndSetState(s, RAN)) {
+ exception = t;
+ result = null;
+ releaseShared(0);
+ future.done();
+ return;
+ }
+ }
+ }
+
+ boolean innerCancel(boolean mayInterruptIfRunning) {
+ for (;;) {
+ int s = getState();
+ if (ranOrCancelled(s))
+ return false;
+ if (compareAndSetState(s, CANCELLED))
+ break;
+ }
+ if (mayInterruptIfRunning) {
+ Thread r = runner;
+ if (r != null)
+ r.interrupt();
+ }
+ releaseShared(0);
+ future.done();
+ return true;
+ }
+
+ void innerRun() {
+ if (!compareAndSetState(0, RUNNING))
+ return;
+ try {
+ runner = Thread.currentThread();
+ if (getState() == RUNNING) // recheck after setting thread
+ innerSet(callable.call());
+ else
+ releaseShared(0); // cancel
+ } catch (Throwable ex) {
+ innerSetException(ex);
+ }
+ }
+
+ boolean innerRunAndReset() {
+ if (!compareAndSetState(0, RUNNING))
+ return false;
+ try {
+ runner = Thread.currentThread();
+ if (getState() == RUNNING)
+ callable.call(); // don't set result
+ runner = null;
+ return compareAndSetState(RUNNING, 0);
+ } catch (Throwable ex) {
+ innerSetException(ex);
+ return false;
+ }
+ }
+ }
+
+ // @see org.jgroups.blocks.executor.ExecutorNotification#resultReturned(java.lang.Object)
+ @SuppressWarnings("unchecked")
+ @Override
+ public void resultReturned(Object obj) {
+ set((V)obj);
+ }
+
+ // @see org.jgroups.blocks.executor.ExecutorNotification#throwableEncountered(java.lang.Throwable)
+ @Override
+ public void throwableEncountered(Throwable t) {
+ setException(t);
+ }
+
+ @Override
+ public void interrupted(Runnable runnable) {
+ _unfinishedLock.lock();
+ try {
+ _unfinishedFutures.remove(this);
+ _unfinishedCondition.signalAll();
+ }
+ finally {
+ _unfinishedLock.unlock();
+ }
+
+ // We assign the listener to a local variable so we don't have to
+ // worry about it becoming null inside the if
+ FutureListener listener = _listener;
+ // We don't want this to run on server
+ if (listener != null) {
+ listener.futureDone(this);
+ }
+ }
+ }
+
+ // @see java.util.concurrent.ExecutorService#shutdown()
+ @Override
+ public void shutdown() {
+ _realShutdown(false);
+ }
+
+ @SuppressWarnings("unchecked")
+ private List _realShutdown(boolean interrupt) {
+ _shutdown.set(true);
+ _unfinishedLock.lock();
+ Set> futures;
+ try {
+ futures = new HashSet>(_unfinishedFutures);
+ }
+ finally {
+ _unfinishedLock.unlock();
+ }
+ return (List)ch.downcall(new ExecutorEvent(
+ ExecutorEvent.ALL_TASK_CANCEL, new Object[]{futures, interrupt}));
+ }
+
+ // @see java.util.concurrent.ExecutorService#shutdownNow()
+ @Override
+ public List shutdownNow() {
+ return _realShutdown(true);
+ }
+
+ // @see java.util.concurrent.ExecutorService#isShutdown()
+ @Override
+ public boolean isShutdown() {
+ return _shutdown.get();
+ }
+
+ // @see java.util.concurrent.ExecutorService#isTerminated()
+ @Override
+ public boolean isTerminated() {
+ if (_shutdown.get()) {
+ _unfinishedLock.lock();
+ try {
+ return _unfinishedFutures.isEmpty();
+ }
+ finally {
+ _unfinishedLock.unlock();
+ }
+ }
+ return false;
+ }
+
+ // @see java.util.concurrent.ExecutorService#awaitTermination(long, java.util.concurrent.TimeUnit)
+ @Override
+ public boolean awaitTermination(long timeout, TimeUnit unit)
+ throws InterruptedException {
+ long nanoTimeWait = unit.toNanos(timeout);
+ _unfinishedLock.lock();
+ try {
+ while (!_unfinishedFutures.isEmpty()) {
+ if ((nanoTimeWait = _unfinishedCondition.awaitNanos(
+ nanoTimeWait)) <= 0) {
+ return false;
+ }
+ }
+ }
+ finally {
+ _unfinishedLock.unlock();
+ }
+
+ return true;
+ }
+
+ // @see java.util.concurrent.AbstractExecutorService#invokeAny(java.util.Collection)
+ @Override
+ public T invokeAny(Collection extends Callable> tasks)
+ throws InterruptedException, ExecutionException {
+ try {
+ return doInvokeAny(tasks, false, 0);
+ } catch (TimeoutException cannotHappen) {
+ assert false;
+ return null;
+ }
+ }
+
+ // @see java.util.concurrent.AbstractExecutorService#invokeAny(java.util.Collection, long, java.util.concurrent.TimeUnit)
+ @Override
+ public T invokeAny(Collection extends Callable> tasks,
+ long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ return doInvokeAny(tasks, true, unit.toNanos(timeout));
+ }
+
+ /**
+ * the main mechanics of invokeAny.
+ * This was essentially copied from {@link AbstractExecutorService}
+ * doInvokeAny except that we replaced the {@link ExecutorCompletionService}
+ * with an {@link ExecutionCompletionService}.
+ */
+ private T doInvokeAny(Collection extends Callable> tasks,
+ boolean timed, long nanos)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ if (tasks == null)
+ throw new NullPointerException();
+ int ntasks = tasks.size();
+ if (ntasks == 0)
+ throw new IllegalArgumentException();
+ List> futures= new ArrayList>(ntasks);
+ CompletionService ecs =
+ new ExecutionCompletionService(this);
+
+ // For efficiency, especially in executors with limited
+ // parallelism, check to see if previously submitted tasks are
+ // done before submitting more of them. This interleaving
+ // plus the exception mechanics account for messiness of main
+ // loop.
+
+ try {
+ // Record exceptions so that if we fail to obtain any
+ // result, we can throw the last exception we got.
+ ExecutionException ee = null;
+ long lastTime = (timed)? System.nanoTime() : 0;
+ Iterator extends Callable> it = tasks.iterator();
+
+ // Start one task for sure; the rest incrementally
+ futures.add(ecs.submit(it.next()));
+ --ntasks;
+ int active = 1;
+
+ for (;;) {
+ Future f = ecs.poll();
+ if (f == null) {
+ if (ntasks > 0) {
+ --ntasks;
+ futures.add(ecs.submit(it.next()));
+ ++active;
+ }
+ else if (active == 0)
+ break;
+ else if (timed) {
+ f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
+ if (f == null)
+ throw new TimeoutException();
+ long now = System.nanoTime();
+ nanos -= now - lastTime;
+ lastTime = now;
+ }
+ else
+ f = ecs.take();
+ }
+ if (f != null) {
+ --active;
+ try {
+ return f.get();
+ } catch (InterruptedException ie) {
+ throw ie;
+ } catch (ExecutionException eex) {
+ ee = eex;
+ } catch (RuntimeException rex) {
+ ee = new ExecutionException(rex);
+ }
+ }
+ }
+
+ if (ee == null)
+ ee = new ExecutionException() {
+ private static final long serialVersionUID = 200818694545553992L;
+ };
+ throw ee;
+
+ } finally {
+ for (Future f : futures)
+ f.cancel(true);
+ }
+ }
+
+ // @see java.util.concurrent.Executor#execute(java.lang.Runnable)
+ @Override
+ public void execute(Runnable command) {
+ if (!_shutdown.get()) {
+ Object serializeCheck;
+ // If it is wrapped by our future, then we have to make sure to
+ // check the actual callable/runnable given to us for serialization
+ if (command instanceof DistributedFuture) {
+ serializeCheck = ((DistributedFuture>)command).getCallable();
+ if (serializeCheck instanceof RunnableAdapter) {
+ serializeCheck = ((RunnableAdapter>)serializeCheck).task;
+ }
+ }
+ else {
+ serializeCheck = command;
+ }
+
+ if (serializeCheck instanceof Serializable ||
+ serializeCheck instanceof Streamable) {
+ ch.down(new ExecutorEvent(ExecutorEvent.TASK_SUBMIT, command));
+ }
+ else {
+ throw new IllegalArgumentException(
+ "Command was not Serializable or Streamable - "
+ + serializeCheck);
+ }
+ }
+ else {
+ throw new RejectedExecutionException();
+ }
+ }
+
+ /**
+ * This is copied from {@see java.util.concurrent.Executors} class which
+ * contains RunnableAdapter. However that adapter isn't serializable, and
+ * is final and package level so we can' reference.
+ */
+ protected static final class RunnableAdapter implements Callable, Streamable {
+ protected Runnable task;
+ protected T result;
+
+ protected RunnableAdapter() {
+
+ }
+ protected RunnableAdapter(Runnable task, T result) {
+ this.task = task;
+ this.result = result;
+ }
+ public T call() {
+ task.run();
+ return result;
+ }
+ @Override
+ public void writeTo(DataOutputStream out) throws IOException {
+ try {
+ Util.writeObject(task, out);
+ }
+ catch (IOException e) {
+ throw e;
+ }
+ catch (Exception e) {
+ throw new IOException("Exception encountered while writing execution runnable", e);
+ }
+
+ try {
+ Util.writeObject(result, out);
+ }
+ catch (IOException e) {
+ throw e;
+ }
+ catch (Exception e) {
+ throw new IOException("Exception encountered while writing execution result", e);
+ }
+ }
+ @SuppressWarnings("unchecked")
+ @Override
+ public void readFrom(DataInputStream in) throws IOException,
+ IllegalAccessException, InstantiationException {
+ // We can't use Util.readObject since it's size is limited to 2^15-1
+ // The runner could be larger than that possibly
+ try {
+ task = (Runnable)Util.readObject(in);
+ }
+ catch (IOException e) {
+ throw e;
+ }
+ catch (Exception e) {
+ throw new IOException("Exception encountered while reading execution runnable", e);
+ }
+
+ try {
+ result = (T)Util.readObject(in);
+ }
+ catch (IOException e) {
+ throw e;
+ }
+ catch (Exception e) {
+ throw new IOException("Exception encountered while reading execution result", e);
+ }
+ }
+ }
+
+ // @see java.util.concurrent.AbstractExecutorService#newTaskFor(java.lang.Runnable, java.lang.Object)
+ @Override
+ protected RunnableFuture newTaskFor(Runnable runnable, T value) {
+ DistributedFuture future = new DistributedFuture(ch, _unfinishedLock,
+ _unfinishedCondition, _unfinishedFutures, runnable, value);
+ _execProt.addExecutorListener(future, future);
+ _unfinishedLock.lock();
+ try {
+ _unfinishedFutures.add(future);
+ }
+ finally {
+ _unfinishedLock.unlock();
+ }
+ return future;
+ }
+
+ // @see java.util.concurrent.AbstractExecutorService#newTaskFor(java.util.concurrent.Callable)
+ @Override
+ protected RunnableFuture newTaskFor(Callable callable) {
+ DistributedFuture future = new DistributedFuture(ch, _unfinishedLock,
+ _unfinishedCondition, _unfinishedFutures, callable);
+ _execProt.addExecutorListener(future, future);
+ _unfinishedLock.lock();
+ try {
+ _unfinishedFutures.add(future);
+ }
+ finally {
+ _unfinishedLock.unlock();
+ }
+ return future;
+ }
+}
diff -Nru libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/executor/Executions.java libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/executor/Executions.java
--- libjgroups-java-2.7.0.GA/src/org/jgroups/blocks/executor/Executions.java 1970-01-01 00:00:00.000000000 +0000
+++ libjgroups-java-2.12.2.Final/src/org/jgroups/blocks/executor/Executions.java 2011-10-18 11:22:35.000000000 +0000
@@ -0,0 +1,177 @@
+package org.jgroups.blocks.executor;
+
+import org.jgroups.util.Streamable;
+import org.jgroups.util.Util;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.util.Arrays;
+import java.util.concurrent.Callable;
+
+public class Executions {
+ /**
+ * This method should be used to convert a callable that would not normally
+ * be serializable, externalizable or streamable but has serializable,
+ * externalizable or streamable arguments to a constructor to construct it.
+ *
+ * When the call method is called on the callable it will call the provided
+ * constructor passing in the given arguments. It will then invoke the call
+ * method on resulting callable that was created.
+ *
+ * The amount of arguments cannot exceed {@link Byte#MAX_VALUE}. Also the
+ * constructor cannot exceed {@link Byte#MAX_VALUE} position in the
+ * constructor array returned from {@link Class#getConstructors()}
+ *
+ * The amount of arguments must match the amount of arguments required
+ * by the constructor. Also the arguments must be compatibile with the
+ * types required of the constructor.
+ *
+ * Unfortunately it isn't easy to pass a Constructor extends Callable>
+ * so we can't pass back a callable that is properly typed. Also this
+ * forces the caller to cast their callable or returned value to the correct
+ * type manually.
+ *
+ * @param constructorToUse The constructor to use when creating the callable
+ * @param args The arguments to pass to the constructor
+ * @return The callable that will upon being called will instantiate the
+ * given callable using the constructor with the provided arguments
+ * and calls the call method
+ * @throws IllegalArgumentException This is thrown if the arguments are
+ * not serializable, externalizable or streamable. It can be thrown
+ * if the constructo is not accessible. It can also be thrown
+ * if too many arguments or the constructor is to high up in the
+ * constructo array returned by the class.
+ */
+ public static Callable> serializableCallable(@SuppressWarnings("rawtypes")
+ Constructor extends Callable> constructorToUse, Object... args)
+ throws IllegalArgumentException {
+ if (args.length > (int)Byte.MAX_VALUE) {
+ throw new IllegalArgumentException(
+ "Max number of arguments exceeded: " + Byte.MAX_VALUE);
+ }
+ Class>[] params = constructorToUse.getParameterTypes();
+
+ if (params.length != args.length) {
+ throw new IllegalArgumentException("Number of arguments ["
+ + args.length + "] doesn't match number of arguments for "
+ + "constructor [" + params.length + "]");
+ }
+
+ for (int i = 0; i < args.length; ++i) {
+ Object arg = args[i];
+ if (arg instanceof Serializable ||
+ arg instanceof Streamable) {
+ Class> classArg = params[i];
+
+ if (!classArg.isInstance(arg)) {
+ throw new IllegalArgumentException("Argument [" + arg +
+ "] is not an instance of [" + classArg + "]");
+ }
+ }
+ else {
+ throw new IllegalArgumentException(
+ "Argument is not serializable, externalizable or streamable: " + arg);
+ }
+ }
+ @SuppressWarnings("unchecked")
+ Class extends Callable>> classToUse =
+ (Class extends Callable>>)constructorToUse.getDeclaringClass();
+ Constructor>[] constructors = classToUse.getConstructors();
+ byte constructorPosition = -1;
+ for (int i = 0; i < constructors.length; ++i) {
+ Constructor> constructor = constructors[i];
+ if (constructor.equals(constructorToUse)) {
+ if (i > (int)Byte.MAX_VALUE) {
+ throw new IllegalArgumentException(
+ "Constructor position in array cannot be higher than "
+ + Byte.MAX_VALUE);
+ }
+ constructorPosition = (byte)i;
+ }
+ }
+ if (constructorPosition == -1) {
+ throw new IllegalArgumentException(
+ "Constructor was not found in public constructor array on class");
+ }
+ return new StreamableCallable(classToUse, constructorPosition, args);
+ }
+
+ protected static class StreamableCallable implements Callable