diff options
author | Uwe Stieber | 2014-03-13 11:40:36 +0000 |
---|---|---|
committer | Uwe Stieber | 2014-03-13 11:40:36 +0000 |
commit | 4c41b370106e65a91f2e6a2694df631d26b6f5ef (patch) | |
tree | 852c0da10feaf360ecede4b18e852359a188d4a6 | |
parent | ec7617f25922402c02cee9709a7f257ebde39ff9 (diff) | |
download | org.eclipse.tcf-4c41b370106e65a91f2e6a2694df631d26b6f5ef.tar.gz org.eclipse.tcf-4c41b370106e65a91f2e6a2694df631d26b6f5ef.tar.xz org.eclipse.tcf-4c41b370106e65a91f2e6a2694df631d26b6f5ef.zip |
Target Explorer: Fix - Not reference counted channels can bring down reference counted channels to the same peer
If a not reference counted channel got opened to a peer that has already a reference counted channel to that peer and is using value-add's for the connection, closing the not reference counted channel does bring down the reference counted channel as the value-add's are incorrectly shutdowned.
-rw-r--r-- | target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/internal/ChannelManager.java | 73 |
1 files changed, 54 insertions, 19 deletions
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/internal/ChannelManager.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/internal/ChannelManager.java index ddb63a3b5..2612f79cb 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/internal/ChannelManager.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.core/src/org/eclipse/tcf/te/tcf/core/internal/ChannelManager.java @@ -12,6 +12,7 @@ package org.eclipse.tcf.te.tcf.core.internal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; @@ -48,6 +49,8 @@ public final class ChannelManager extends PlatformObject implements IChannelMana /* default */ final Map<String, AtomicInteger> refCounters = new HashMap<String, AtomicInteger>(); // The map of channels per peer id /* default */ final Map<String, IChannel> channels = new HashMap<String, IChannel>(); + // The map of channels opened via "forceNew" flag (needed to handle the close channel correctly) + /* default */ final List<IChannel> forcedChannels = new ArrayList<IChannel>(); /** * Constructor. @@ -219,6 +222,8 @@ public final class ChannelManager extends PlatformObject implements IChannelMana // If noValueAdd == true -> forceNew has to be true as well if (noValueAdd) forceNew = true; + final boolean finForceNew = forceNew; + // Check if there is already a channel opened to this peer channel = !forceNew ? channels.get(id) : null; if (channel != null && (channel.getState() == IChannel.STATE_OPEN || channel.getState() == IChannel.STATE_OPENING)) { @@ -254,6 +259,7 @@ public final class ChannelManager extends PlatformObject implements IChannelMana if (channel != null) { if (!forceNew) channels.put(id, channel); if (!forceNew) refCounters.put(id, new AtomicInteger(1)); + if (forceNew) forcedChannels.add(channel); // Register the channel listener final IChannel finChannel = channel; @@ -278,8 +284,9 @@ public final class ChannelManager extends PlatformObject implements IChannelMana // Remove ourself as listener from the channel finChannel.removeChannelListener(this); // Clean the reference counter and the channel map - channels.remove(id); - refCounters.remove(id); + if (!finForceNew) channels.remove(id); + if (!finForceNew) refCounters.remove(id); + if (finForceNew) forcedChannels.remove(finChannel); if (CoreBundleActivator.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_CHANNEL_MANAGER)) { CoreBundleActivator.getTraceHandler().trace(NLS.bind(Messages.ChannelManager_openChannel_failed_message, id, error), @@ -490,17 +497,22 @@ public final class ChannelManager extends PlatformObject implements IChannelMana 0, ITraceIds.TRACE_CHANNEL_MANAGER, IStatus.INFO, this); } - // Get the reference counter - AtomicInteger counter = refCounters.get(id); + // Determine if the given channel is a reference counted channel + final boolean isRefCounted = !forcedChannels.contains(channel); + + // Get the reference counter (if the channel is a reference counted channel) + AtomicInteger counter = isRefCounted ? refCounters.get(id) : null; // If the counter is null or get 0 after the decrement, close the channel if (counter == null || counter.decrementAndGet() == 0) { channel.close(); - // Get the value-add's for the peer to shutdown - IValueAdd[] valueAdds = ValueAddManager.getInstance().getValueAdd(peer); - if (valueAdds != null && valueAdds.length > 0) { - internalShutdownValueAdds(peer, valueAdds); + // Get the value-add's for the peer to shutdown (if the reference counter is 0) + if (counter != null && counter.get() == 0) { + IValueAdd[] valueAdds = ValueAddManager.getInstance().getValueAdd(peer); + if (valueAdds != null && valueAdds.length > 0) { + internalShutdownValueAdds(peer, valueAdds); + } } if (CoreBundleActivator.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_CHANNEL_MANAGER)) { @@ -509,14 +521,24 @@ public final class ChannelManager extends PlatformObject implements IChannelMana } // Clean the reference counter and the channel map - refCounters.remove(id); - channels.remove(id); + if (isRefCounted) refCounters.remove(id); + if (isRefCounted) channels.remove(id); + if (!isRefCounted) forcedChannels.remove(channel); } else { if (CoreBundleActivator.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_CHANNEL_MANAGER)) { CoreBundleActivator.getTraceHandler().trace(NLS.bind(Messages.ChannelManager_closeChannel_inuse_message, id, counter.toString()), 0, ITraceIds.TRACE_CHANNEL_MANAGER, IStatus.INFO, this); } } + + // Clean up the list of forced channels. Remove all channels already been closed. + ListIterator<IChannel> iter = forcedChannels.listIterator(); + while (iter.hasNext()) { + IChannel c = iter.next(); + if (c.getState() == IChannel.STATE_CLOSED) { + iter.remove(); + } + } } /* (non-Javadoc) @@ -548,6 +570,16 @@ public final class ChannelManager extends PlatformObject implements IChannelMana // Get the peer id String id = peer.getID(); + // First, close all channels that are not reference counted + ListIterator<IChannel> iter = forcedChannels.listIterator(); + while (iter.hasNext()) { + IChannel c = iter.next(); + if (id.equals(c.getRemotePeer().getID())) { + c.close(); + iter.remove(); + } + } + // Get the channel IChannel channel = internalGetChannel(peer); if (channel != null) { @@ -556,9 +588,9 @@ public final class ChannelManager extends PlatformObject implements IChannelMana // Close the channel internalCloseChannel(channel); - } - // Get the value-add's for the peer to shutdown + + // Make sure to shutdown all value-add's for the peer IValueAdd[] valueAdds = ValueAddManager.getInstance().getValueAdd(peer); if (valueAdds != null && valueAdds.length > 0) { internalShutdownValueAdds(peer, valueAdds); @@ -711,7 +743,7 @@ public final class ChannelManager extends PlatformObject implements IChannelMana internalHandleValueAdds(peer, done); } - /* default */ final Map<IPeer, List<DoneHandleValueAdds>> inProgress = new HashMap<IPeer, List<DoneHandleValueAdds>>(); + /* default */ final Map<String, List<DoneHandleValueAdds>> inProgress = new HashMap<String, List<DoneHandleValueAdds>>(); /** * Check on the value-adds for the given peer. Launch the value-adds @@ -730,8 +762,8 @@ public final class ChannelManager extends PlatformObject implements IChannelMana // If a launch for the same value add is in progress already, attach the new done to // the list to call and drop out - if (inProgress.containsKey(peer)) { - List<DoneHandleValueAdds> dones = inProgress.get(peer); + if (inProgress.containsKey(id)) { + List<DoneHandleValueAdds> dones = inProgress.get(id); Assert.isNotNull(dones); dones.add(done); return; @@ -740,7 +772,7 @@ public final class ChannelManager extends PlatformObject implements IChannelMana // Add the done callback to a list of waiting callbacks per peer List<DoneHandleValueAdds> dones = new ArrayList<DoneHandleValueAdds>(); dones.add(done); - inProgress.put(peer, dones); + inProgress.put(id, dones); // The "myDone" callback is invoking the callbacks from the list // of waiting callbacks. @@ -749,7 +781,7 @@ public final class ChannelManager extends PlatformObject implements IChannelMana @Override public void doneHandleValueAdds(Throwable error, IValueAdd[] valueAdds) { // Get the list of the original done callbacks - List<DoneHandleValueAdds> dones = inProgress.remove(peer); + List<DoneHandleValueAdds> dones = inProgress.remove(id); for (DoneHandleValueAdds done : dones) { done.doneHandleValueAdds(error, valueAdds); } @@ -1031,6 +1063,7 @@ public final class ChannelManager extends PlatformObject implements IChannelMana if (channel != null) { if (!forceNew) channels.put(id, channel); if (!forceNew) refCounters.put(id, new AtomicInteger(1)); + if (forceNew) forcedChannels.add(channel); // Attach the channel listener to catch open/closed events final IChannel finChannel = channel; @@ -1097,8 +1130,10 @@ public final class ChannelManager extends PlatformObject implements IChannelMana } // Clean the reference counter and the channel map - channels.remove(id); - refCounters.remove(id); + if (!forceNew) channels.remove(id); + if (!forceNew) refCounters.remove(id); + if (forceNew) forcedChannels.remove(finChannel); + // Channel opening failed -> This will break everything done.doneChainValueAdd(error, finChannel); } |