Skip to content

Commit e5dfc80

Browse files
author
David R. MacIver
committed
adopt the game theoretically sound 'shrug and let the user get away with it' strategy instead
1 parent 713069b commit e5dfc80

File tree

1 file changed

+29
-6
lines changed

1 file changed

+29
-6
lines changed

src/com/rabbitmq/client/impl/ChannelManager.java

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,36 @@ private void addChannel(ChannelN chan) {
126126
_channelMap.put(chan.getChannelNumber(), chan);
127127
}
128128

129+
/**
130+
* Remove the argument channel from the channel map.
131+
* This method must be safe to call multiple times on the same channel. If
132+
* it is not then things go badly wrong.
133+
*/
129134
public synchronized void disconnectChannel(ChannelN channel) {
130135
int channelNumber = channel.getChannelNumber();
131-
if (_channelMap.remove(channelNumber) != channel)
132-
throw new IllegalStateException(
133-
"We have attempted to "
134-
+ "create a disconnect a channel that's no longer in "
135-
+ "use. This should never happen. Please report this as a bug.");
136-
channelNumberAllocator.free(channelNumber);
136+
137+
// Warning, here be dragons. Not great big ones, but little baby ones
138+
// which will nibble on your toes and occasionally trip you up when
139+
// you least expect it.
140+
// Basically, there's a race that can end us up here. It almost never
141+
// happens, but it's easier to repair it when it does than prevent it
142+
// from happening in the first place.
143+
// If we end up doing a Channel.close in one thread and a Channel.open
144+
// with the same channel number in another, the two can overlap in such
145+
// a way as to cause disconnectChannel on the old channel to try to
146+
// remove the new one. Ideally we would fix this race at the source,
147+
// but it's much easier to just catch it here.
148+
synchronized(_channelMap){
149+
ChannelN existing = _channelMap.remove(channelNumber);
150+
// Nothing to do here. Move along.
151+
if(existing == null) return;
152+
// Oops, we've gone and stomped on someone else's channel. Put it back
153+
// and pretend we didn't touch it.
154+
else if(existing != channel){
155+
_channelMap.put(channelNumber, existing);
156+
return;
157+
}
158+
channelNumberAllocator.free(channelNumber);
159+
}
137160
}
138161
}

0 commit comments

Comments
 (0)