@Override public void fail(final ActiveMQException me, String scaleDownTargetNodeID) { synchronized (failLock) { if (destroyed) { return; } destroyed = true; } ActiveMQClientLogger.LOGGER.connectionFailureDetected(me.getMessage(), me.getType()); try { transportConnection.forceClose(); } catch (Throwable e) { ActiveMQClientLogger.LOGGER.warn(e.getMessage(), e); } // Then call the listeners callFailureListeners(me, scaleDownTargetNodeID); callClosingListeners(); internalClose(); for (Channel channel : channels.values()) { channel.returnBlocking(me); } }
private void internalClose() { // We close the underlying transport connection getTransportConnection().close(); for (Channel channel : channels.values()) { channel.close(); } }
// We flush any confirmations on the connection - this prevents idle bridges for example // sitting there with many unacked messages @Override public void flush() { synchronized (transferLock) { for (Channel channel : channels.values()) { channel.flushConfirmations(); } } }
private void doBufferReceived(final Packet packet) { if (ChannelImpl.invokeInterceptors(packet, incomingInterceptors, this) != null) { return; } synchronized (transferLock) { final Channel channel = channels.get(packet.getChannelID()); if (channel != null) { channel.handlePacket(packet); } } }
@Override public synchronized void stop() throws Exception { if (!started) { return; } // Channel may be null if there isn't a connection to a live server if (channel != null) { channel.close(); } for (ReplicatedLargeMessage largeMessage : largeMessages.values()) { largeMessage.releaseResources(); } largeMessages.clear(); for (Entry<JournalContent, Map<Long, JournalSyncFile>> entry : filesReservedForSync.entrySet()) { for (JournalSyncFile filesReserved : entry.getValue().values()) { filesReserved.close(); } } filesReservedForSync.clear(); if (journals != null) { for (Journal j : journals) { if (j instanceof FileWrapperJournal) j.stop(); } } for (ConcurrentMap<Integer, Page> map : pageIndex.values()) { for (Page page : map.values()) { try { page.sync(); page.close(); } catch (Exception e) { ActiveMQServerLogger.LOGGER.errorClosingPageOnReplication(e); } } } pageManager.stop(); pageIndex.clear(); final CountDownLatch latch = new CountDownLatch(1); executor.execute( new Runnable() { @Override public void run() { latch.countDown(); } }); latch.await(30, TimeUnit.SECONDS); // Storage needs to be the last to stop storageManager.stop(); started = false; }
private void handleCheckForFailover(CheckFailoverMessage failoverMessage) { String nodeID = failoverMessage.getNodeID(); boolean okToFailover = nodeID == null || !(server.getHAPolicy().canScaleDown() && !server.hasScaledDown(new SimpleString(nodeID))); channel1.send(new CheckFailoverReplyMessage(okToFailover)); }
public ConnectionEntry createConnectionEntry( final Acceptor acceptorUsed, final Connection connection) { final Configuration config = server.getConfiguration(); Executor connectionExecutor = server.getExecutorFactory().getExecutor(); final CoreRemotingConnection rc = new RemotingConnectionImpl( ServerPacketDecoder.INSTANCE, connection, incomingInterceptors, outgoingInterceptors, config.isAsyncConnectionExecutionEnabled() ? connectionExecutor : null, server.getNodeID()); Channel channel1 = rc.getChannel(CHANNEL_ID.SESSION.id, -1); ChannelHandler handler = new ActiveMQPacketHandler(this, server, channel1, rc); channel1.setHandler(handler); long ttl = ActiveMQClient.DEFAULT_CONNECTION_TTL; if (config.getConnectionTTLOverride() != -1) { ttl = config.getConnectionTTLOverride(); } final ConnectionEntry entry = new ConnectionEntry(rc, connectionExecutor, System.currentTimeMillis(), ttl); final Channel channel0 = rc.getChannel(ChannelImpl.CHANNEL_ID.PING.id, -1); channel0.setHandler(new LocalChannelHandler(config, entry, channel0, acceptorUsed, rc)); server .getClusterManager() .addClusterChannelHandler( rc.getChannel(CHANNEL_ID.CLUSTER.id, -1), acceptorUsed, rc, server.getActivation()); return entry; }
@Override public void handlePacket(final Packet packet) { PacketImpl response = new ReplicationResponseMessage(); final byte type = packet.getType(); try { if (!started) { return; } if (type == PacketImpl.REPLICATION_APPEND) { handleAppendAddRecord((ReplicationAddMessage) packet); } else if (type == PacketImpl.REPLICATION_APPEND_TX) { handleAppendAddTXRecord((ReplicationAddTXMessage) packet); } else if (type == PacketImpl.REPLICATION_DELETE) { handleAppendDelete((ReplicationDeleteMessage) packet); } else if (type == PacketImpl.REPLICATION_DELETE_TX) { handleAppendDeleteTX((ReplicationDeleteTXMessage) packet); } else if (type == PacketImpl.REPLICATION_PREPARE) { handlePrepare((ReplicationPrepareMessage) packet); } else if (type == PacketImpl.REPLICATION_COMMIT_ROLLBACK) { handleCommitRollback((ReplicationCommitMessage) packet); } else if (type == PacketImpl.REPLICATION_PAGE_WRITE) { handlePageWrite((ReplicationPageWriteMessage) packet); } else if (type == PacketImpl.REPLICATION_PAGE_EVENT) { handlePageEvent((ReplicationPageEventMessage) packet); } else if (type == PacketImpl.REPLICATION_LARGE_MESSAGE_BEGIN) { handleLargeMessageBegin((ReplicationLargeMessageBeginMessage) packet); } else if (type == PacketImpl.REPLICATION_LARGE_MESSAGE_WRITE) { handleLargeMessageWrite((ReplicationLargeMessageWriteMessage) packet); } else if (type == PacketImpl.REPLICATION_LARGE_MESSAGE_END) { handleLargeMessageEnd((ReplicationLargeMessageEndMessage) packet); } else if (type == PacketImpl.REPLICATION_START_FINISH_SYNC) { response = handleStartReplicationSynchronization((ReplicationStartSyncMessage) packet); } else if (type == PacketImpl.REPLICATION_SYNC_FILE) { handleReplicationSynchronization((ReplicationSyncFileMessage) packet); } else if (type == PacketImpl.REPLICATION_SCHEDULED_FAILOVER) { handleLiveStopping((ReplicationLiveIsStoppingMessage) packet); } else if (type == PacketImpl.BACKUP_REGISTRATION_FAILED) { handleFatalError((BackupReplicationStartFailedMessage) packet); } else { ActiveMQServerLogger.LOGGER.invalidPacketForReplication(packet); } } catch (ActiveMQException e) { ActiveMQServerLogger.LOGGER.errorHandlingReplicationPacket(e, packet); response = new ActiveMQExceptionMessage(e); } catch (Exception e) { ActiveMQServerLogger.LOGGER.errorHandlingReplicationPacket(e, packet); response = new ActiveMQExceptionMessage(ActiveMQMessageBundle.BUNDLE.replicationUnhandledError(e)); } channel.send(response); }
@Override public void disconnect(String scaleDownNodeID, final boolean criticalError) { Channel channel0 = getChannel(ChannelImpl.CHANNEL_ID.PING.id, -1); // And we remove all channels from the connection, this ensures no more packets will be // processed after this // method is // complete Set<Channel> allChannels = new HashSet<>(channels.values()); if (!criticalError) { removeAllChannels(); } else { // We can't hold a lock if a critical error is happening... // as other threads will be holding the lock while hanging on IO channels.clear(); } // Now we are 100% sure that no more packets will be processed we can flush then send the // disconnect if (!criticalError) { for (Channel channel : allChannels) { channel.flushConfirmations(); } } Packet disconnect; if (channel0.supports(PacketImpl.DISCONNECT_V2)) { disconnect = new DisconnectMessage_V2(nodeID, scaleDownNodeID); } else { disconnect = new DisconnectMessage(nodeID); } channel0.sendAndFlush(disconnect); }
private void handleReattachSession(final ReattachSessionMessage request) { Packet response = null; try { if (!server.isStarted()) { response = new ReattachSessionResponseMessage(-1, false); } logger.debug("Reattaching request from " + connection.getRemoteAddress()); ServerSessionPacketHandler sessionHandler = protocolManager.getSessionHandler(request.getName()); // HORNETQ-720 XXX ataylor? if ( /*!server.checkActivate() || */ sessionHandler == null) { response = new ReattachSessionResponseMessage(-1, false); } else { if (sessionHandler.getChannel().getConfirmationWindowSize() == -1) { // Even though session exists, we can't reattach since confi window size == -1, // i.e. we don't have a resend cache for commands, so we just close the old session // and let the client recreate ActiveMQServerLogger.LOGGER.reattachRequestFailed(connection.getRemoteAddress()); sessionHandler.closeListeners(); sessionHandler.close(); response = new ReattachSessionResponseMessage(-1, false); } else { // Reconnect the channel to the new connection int serverLastConfirmedCommandID = sessionHandler.transferConnection(connection, request.getLastConfirmedCommandID()); response = new ReattachSessionResponseMessage(serverLastConfirmedCommandID, true); } } } catch (Exception e) { ActiveMQServerLogger.LOGGER.failedToReattachSession(e); response = new ActiveMQExceptionMessage(new ActiveMQInternalErrorException()); } channel1.send(response); }
private void handleCreateSession(final CreateSessionMessage request) { boolean incompatibleVersion = false; Packet response; try { Version version = server.getVersion(); if (!version.isCompatible(request.getVersion())) { throw ActiveMQMessageBundle.BUNDLE.incompatibleClientServer(); } if (!server.isStarted()) { throw ActiveMQMessageBundle.BUNDLE.serverNotStarted(); } // XXX HORNETQ-720 Taylor commented out this test. Should be verified. /*if (!server.checkActivate()) { throw new ActiveMQException(ActiveMQException.SESSION_CREATION_REJECTED, "Server will not accept create session requests"); }*/ if (connection.getClientVersion() == 0) { connection.setClientVersion(request.getVersion()); } else if (connection.getClientVersion() != request.getVersion()) { ActiveMQServerLogger.LOGGER.incompatibleVersionAfterConnect( request.getVersion(), connection.getClientVersion()); } Channel channel = connection.getChannel(request.getSessionChannelID(), request.getWindowSize()); ActiveMQPrincipal activeMQPrincipal = null; if (request.getUsername() == null) { activeMQPrincipal = connection.getDefaultActiveMQPrincipal(); } ServerSession session = server.createSession( request.getName(), activeMQPrincipal == null ? request.getUsername() : activeMQPrincipal.getUserName(), activeMQPrincipal == null ? request.getPassword() : activeMQPrincipal.getPassword(), request.getMinLargeMessageSize(), connection, request.isAutoCommitSends(), request.isAutoCommitAcks(), request.isPreAcknowledge(), request.isXA(), request.getDefaultAddress(), new CoreSessionCallback(request.getName(), protocolManager, channel, connection), true); ServerSessionPacketHandler handler = new ServerSessionPacketHandler(session, server.getStorageManager(), channel); channel.setHandler(handler); // TODO - where is this removed? protocolManager.addSessionHandler(request.getName(), handler); response = new CreateSessionResponseMessage(server.getVersion().getIncrementingVersion()); } catch (ActiveMQException e) { if (e.getType() == ActiveMQExceptionType.INCOMPATIBLE_CLIENT_SERVER_VERSIONS) { incompatibleVersion = true; logger.debug("Sending ActiveMQException after Incompatible client", e); } else { ActiveMQServerLogger.LOGGER.failedToCreateSession(e); } response = new ActiveMQExceptionMessage(e); } catch (Exception e) { ActiveMQServerLogger.LOGGER.failedToCreateSession(e); response = new ActiveMQExceptionMessage(new ActiveMQInternalErrorException()); } // send the exception to the client and destroy // the connection if the client and server versions // are not compatible if (incompatibleVersion) { channel1.sendAndFlush(response); } else { channel1.send(response); } }
public void handlePacket(final Packet packet) { if (packet.getType() == PacketImpl.PING) { Ping ping = (Ping) packet; if (config.getConnectionTTLOverride() == -1) { // Allow clients to specify connection ttl entry.ttl = ping.getConnectionTTL(); } // Just send a ping back channel0.send(packet); } else if (packet.getType() == PacketImpl.SUBSCRIBE_TOPOLOGY || packet.getType() == PacketImpl.SUBSCRIBE_TOPOLOGY_V2) { SubscribeClusterTopologyUpdatesMessage msg = (SubscribeClusterTopologyUpdatesMessage) packet; if (packet.getType() == PacketImpl.SUBSCRIBE_TOPOLOGY_V2) { channel0 .getConnection() .setClientVersion( ((SubscribeClusterTopologyUpdatesMessageV2) msg).getClientVersion()); } final ClusterTopologyListener listener = new ClusterTopologyListener() { @Override public void nodeUP(final TopologyMember topologyMember, final boolean last) { try { final Pair<TransportConfiguration, TransportConfiguration> connectorPair = BackwardsCompatibilityUtils.getTCPair( channel0.getConnection().getClientVersion(), topologyMember); final String nodeID = topologyMember.getNodeId(); // Using an executor as most of the notifications on the Topology // may come from a channel itself // What could cause deadlocks entry.connectionExecutor.execute( new Runnable() { public void run() { if (channel0.supports(PacketImpl.CLUSTER_TOPOLOGY_V3)) { channel0.send( new ClusterTopologyChangeMessage_V3( topologyMember.getUniqueEventID(), nodeID, topologyMember.getBackupGroupName(), topologyMember.getScaleDownGroupName(), connectorPair, last)); } else if (channel0.supports(PacketImpl.CLUSTER_TOPOLOGY_V2)) { channel0.send( new ClusterTopologyChangeMessage_V2( topologyMember.getUniqueEventID(), nodeID, topologyMember.getBackupGroupName(), connectorPair, last)); } else { channel0.send( new ClusterTopologyChangeMessage(nodeID, connectorPair, last)); } } }); } catch (RejectedExecutionException ignored) { // this could happen during a shutdown and we don't care, if we lost a nodeDown // during a shutdown // what can we do anyways? } } @Override public void nodeDown(final long uniqueEventID, final String nodeID) { // Using an executor as most of the notifications on the Topology // may come from a channel itself // What could cause deadlocks try { entry.connectionExecutor.execute( new Runnable() { public void run() { if (channel0.supports(PacketImpl.CLUSTER_TOPOLOGY_V2)) { channel0.send( new ClusterTopologyChangeMessage_V2(uniqueEventID, nodeID)); } else { channel0.send(new ClusterTopologyChangeMessage(nodeID)); } } }); } catch (RejectedExecutionException ignored) { // this could happen during a shutdown and we don't care, if we lost a nodeDown // during a shutdown // what can we do anyways? } } @Override public String toString() { return "Remote Proxy on channel " + Integer.toHexString(System.identityHashCode(this)); } }; if (acceptorUsed.getClusterConnection() != null) { acceptorUsed.getClusterConnection().addClusterTopologyListener(listener); rc.addCloseListener( new CloseListener() { public void connectionClosed() { acceptorUsed.getClusterConnection().removeClusterTopologyListener(listener); } }); } else { // if not clustered, we send a single notification to the client containing the node-id // where the server is connected to // This is done this way so Recovery discovery could also use the node-id for // non-clustered setups entry.connectionExecutor.execute( new Runnable() { public void run() { String nodeId = server.getNodeID().toString(); Pair<TransportConfiguration, TransportConfiguration> emptyConfig = new Pair<TransportConfiguration, TransportConfiguration>(null, null); if (channel0.supports(PacketImpl.CLUSTER_TOPOLOGY_V2)) { channel0.send( new ClusterTopologyChangeMessage_V2( System.currentTimeMillis(), nodeId, null, emptyConfig, true)); } else { channel0.send(new ClusterTopologyChangeMessage(nodeId, emptyConfig, true)); } } }); } } }