/** * writes all the entries that have changed, to the buffer which will later be written to TCP/IP * * @param modificationIterator a record of which entries have modification * @param selectionKey */ void entriesToBuffer( @NotNull final ModificationIterator modificationIterator, @NotNull final SelectionKey selectionKey) throws InterruptedException, IOException { final SocketChannel socketChannel = (SocketChannel) selectionKey.channel(); final Attached attached = (Attached) selectionKey.attachment(); // this can occur when new SHM's are added to a cluster final boolean handShakingComplete = attached.isHandShakingComplete(); for (; ; ) { final boolean wasDataRead = modificationIterator.nextEntry(entryCallback, 0); if (!wasDataRead) { // if we have no more data to write to the socket then we will // un-register OP_WRITE on the selector, until more data becomes available if (in.position() == 0 && handShakingComplete) disableWrite(socketChannel, attached); return; } // we've filled up the buffer lets give another channel a chance to send some data if (in.remaining() <= maxEntrySizeBytes) return; // if we have space in the buffer to write more data and we just wrote data into the // buffer then let try and write some more } }
/** * check to see if we have lost connection with the remote node and if we have attempts a * reconnect. * * @param key the key relating to the heartbeat that we are checking * @param approxTimeOutTime the approximate time in milliseconds * @throws ConnectException */ private void heartbeatCheckHasReceived( @NotNull final SelectionKey key, final long approxTimeOutTime) throws ConnectException { final Attached attached = (Attached) key.attachment(); // we wont attempt to reconnect the server socket if (attached.isServer || !attached.isHandShakingComplete()) return; final SocketChannel channel = (SocketChannel) key.channel(); if (approxTimeOutTime > attached.entryReader.lastHeartBeatReceived + attached.remoteHeartbeatInterval) { if (LOG.isDebugEnabled()) LOG.debug( "lost connection, attempting to reconnect. " + "missed heartbeat from identifier=" + attached.remoteIdentifier); try { channel.socket().close(); channel.close(); activeKeys.clear(attached.remoteIdentifier); closeables.remove(channel); } catch (IOException e) { LOG.debug("", e); } attached.connector.connectLater(); } }
/** * check to see if its time to send a heartbeat, and send one if required * * @param approxTime the current time ( approximately ) * @param key nio selection key */ private void sendHeartbeatIfRequired(final long approxTime, @NotNull final SelectionKey key) { final Attached attachment = (Attached) key.attachment(); if (attachment.isHandShakingComplete() && attachment.entryWriter.lastSentTime + heartBeatInterval < approxTime) { attachment.entryWriter.lastSentTime = approxTime; attachment.entryWriter.writeHeartbeatToBuffer(); enableOpWrite(key); if (LOG.isDebugEnabled()) LOG.debug("sending heartbeat"); } }
/** * removes back in the OP_WRITE from the selector, otherwise it'll spin loop. The OP_WRITE will * get added back in as soon as we have data to write * * @param socketChannel the socketChannel we wish to stop writing to * @param attached data associated with the socketChannels key */ public synchronized void disableWrite( @NotNull final SocketChannel socketChannel, @NotNull final Attached attached) { try { SelectionKey key = socketChannel.keyFor(selector); if (key != null) { if (attached.isHandShakingComplete() && selector.isOpen()) { if (LOG.isDebugEnabled()) LOG.debug( "Disabling OP_WRITE to remoteIdentifier=" + attached.remoteIdentifier + ", localIdentifier=" + localIdentifier); key.interestOps(key.interestOps() & ~OP_WRITE); } } } catch (Exception e) { LOG.error("", e); } }
/** called when the selector receives a OP_READ message */ private void onRead(final SelectionKey key, final long approxTime) throws IOException, InterruptedException { final SocketChannel socketChannel = (SocketChannel) key.channel(); final Attached attached = (Attached) key.attachment(); try { if (attached.entryReader.readSocketToBuffer(socketChannel) <= 0) return; } catch (IOException e) { if (!attached.isServer) attached.connector.connectLater(); throw e; } if (LOG.isDebugEnabled()) LOG.debug("heartbeat or data received."); attached.entryReader.lastHeartBeatReceived = approxTime; if (attached.isHandShakingComplete()) { attached.entryReader.entriesFromBuffer(); } else { doHandShaking(key); } }