@@ -82,20 +82,20 @@ public class ChannelN extends AMQChannel implements com.rabbitmq.client.Channel
8282 /** The ConfirmListener collection. */
8383 private final Collection <ConfirmListener > confirmListeners = new CopyOnWriteArrayList <ConfirmListener >();
8484
85- /** Sequence number of next published message requiring confirmation. */
86- private long nextPublishSeqNo = 0L ;
87-
8885 /** The current default consumer, or null if there is none. */
8986 private volatile Consumer defaultConsumer = null ;
9087
9188 /** Set of currently unconfirmed messages (i.e. messages that have
92- * not been ack'd or nack'd by the server yet. */
93- private volatile SortedSet <Long > unconfirmedSet =
89+ * not been ack'd or nack'd by the server yet.
90+ * Used as monitor and protects nextPublishSeqNo and onlyAcksReceived. */
91+ private SortedSet <Long > unconfirmedSet =
9492 Collections .synchronizedSortedSet (new TreeSet <Long >());
95-
93+ /** Sequence number of next published message requiring confirmation.
94+ * 0 means no confirmations. */
95+ private long nextPublishSeqNo = 0L ;
9696 /** Whether any nacks have been received since the last
9797 * waitForConfirms(). */
98- private volatile boolean onlyAcksReceived = true ;
98+ private boolean noNacksReceived = true ;
9999
100100 /**
101101 * Construct a new channel on the given connection with the given
@@ -167,8 +167,8 @@ public boolean waitForConfirms()
167167 throw Utility .fixStackTrace (getCloseReason ());
168168 }
169169 if (unconfirmedSet .isEmpty ()) {
170- boolean aux = onlyAcksReceived ;
171- onlyAcksReceived = true ;
170+ boolean aux = noNacksReceived ;
171+ noNacksReceived = true ;
172172 return aux ;
173173 }
174174 unconfirmedSet .wait ();
@@ -182,7 +182,7 @@ public void waitForConfirmsOrDie()
182182 {
183183 if (!waitForConfirms ()) {
184184 close (AMQP .REPLY_SUCCESS , "NACKS RECEIVED" , true , null , false );
185- throw new IOException ("nacks received" );
185+ throw new IOException ("nacks received" , getCloseReason () );
186186 }
187187 }
188188
@@ -321,7 +321,7 @@ public void releaseChannelNumber() {
321321 } else if (method instanceof Basic .Nack ) {
322322 Basic .Nack nack = (Basic .Nack ) method ;
323323 callConfirmListeners (command , nack );
324- handleAckNack (nack .getDeliveryTag (), nack .getMultiple (), false );
324+ handleAckNack (nack .getDeliveryTag (), nack .getMultiple (), true );
325325 return true ;
326326 } else if (method instanceof Basic .RecoverOk ) {
327327 for (Consumer callback : _consumers .values ()) {
@@ -551,9 +551,11 @@ public void basicPublish(String exchange, String routingKey,
551551 BasicProperties props , byte [] body )
552552 throws IOException
553553 {
554- if (nextPublishSeqNo > 0 ) {
555- unconfirmedSet .add (getNextPublishSeqNo ());
556- nextPublishSeqNo ++;
554+ synchronized (unconfirmedSet ) {
555+ if (nextPublishSeqNo > 0 ) {
556+ unconfirmedSet .add (nextPublishSeqNo );
557+ nextPublishSeqNo ++;
558+ }
557559 }
558560 BasicProperties useProps = props ;
559561 if (props == null ) {
@@ -994,7 +996,9 @@ public Tx.RollbackOk txRollback()
994996 public Confirm .SelectOk confirmSelect ()
995997 throws IOException
996998 {
997- if (nextPublishSeqNo == 0 ) nextPublishSeqNo = 1 ;
999+ synchronized (unconfirmedSet ) {
1000+ if (nextPublishSeqNo == 0 ) nextPublishSeqNo = 1 ;
1001+ }
9981002 return (Confirm .SelectOk )
9991003 exnWrappingRpc (new Confirm .Select (false )).getMethod ();
10001004
@@ -1012,7 +1016,9 @@ public Channel.FlowOk getFlow() {
10121016
10131017 /** Public API - {@inheritDoc} */
10141018 public long getNextPublishSeqNo () {
1015- return nextPublishSeqNo ;
1019+ synchronized (unconfirmedSet ) {
1020+ return nextPublishSeqNo ;
1021+ }
10161022 }
10171023
10181024 public void asyncRpc (Method method ) throws IOException {
@@ -1024,13 +1030,13 @@ public AMQCommand rpc(Method method) throws IOException {
10241030 }
10251031
10261032 protected void handleAckNack (long seqNo , boolean multiple , boolean nack ) {
1027- if (multiple ) {
1028- unconfirmedSet .headSet (seqNo + 1 ).clear ();
1029- } else {
1030- unconfirmedSet .remove (seqNo );
1031- }
10321033 synchronized (unconfirmedSet ) {
1033- onlyAcksReceived = onlyAcksReceived && !nack ;
1034+ if (multiple ) {
1035+ unconfirmedSet .headSet (seqNo + 1 ).clear ();
1036+ } else {
1037+ unconfirmedSet .remove (seqNo );
1038+ }
1039+ noNacksReceived &= !nack ;
10341040 if (unconfirmedSet .isEmpty ())
10351041 unconfirmedSet .notifyAll ();
10361042 }
0 commit comments