/* * Copyright 2014-2017 Real Logic Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.aeron.archiver; import io.aeron.*; import io.aeron.archiver.codecs.*; import org.agrona.*; import org.agrona.concurrent.*; class ControlSessionProxy { private static final int HEADER_LENGTH = MessageHeaderEncoder.ENCODED_LENGTH; private final IdleStrategy idleStrategy; private final ExpandableArrayBuffer buffer = new ExpandableArrayBuffer(); private final MessageHeaderEncoder messageHeaderEncoder = new MessageHeaderEncoder(); private final ControlResponseEncoder responseEncoder = new ControlResponseEncoder(); private final RecordingNotFoundResponseEncoder recordingNotFoundResponseEncoder = new RecordingNotFoundResponseEncoder(); private final RecordingDescriptorEncoder recordingDescriptorEncoder = new RecordingDescriptorEncoder(); ControlSessionProxy(final IdleStrategy idleStrategy) { this.idleStrategy = idleStrategy; } void sendResponse(final ExclusivePublication reply, final String errorMessage, final long correlationId) { responseEncoder .wrapAndApplyHeader(buffer, 0, messageHeaderEncoder) .correlationId(correlationId); if (!Strings.isEmpty(errorMessage)) { responseEncoder.errorMessage(errorMessage); } final int length = HEADER_LENGTH + responseEncoder.encodedLength(); // TODO: handle dead/slow subscriber, this is not an acceptable place to get stuck send(reply, length); } private void send(final ExclusivePublication reply, final int length) { while (true) { final long result = reply.offer(buffer, 0, length); if (result > 0) { idleStrategy.reset(); break; } if (result == Publication.NOT_CONNECTED || result == Publication.CLOSED) { throw new IllegalStateException("Response channel is down: " + reply); } idleStrategy.idle(); } } void sendDescriptorNotFound( final ExclusivePublication reply, final long recordingId, final long maxRecordingId, final long correlationId) { recordingNotFoundResponseEncoder.wrapAndApplyHeader(buffer, 0, messageHeaderEncoder) .correlationId(correlationId) .recordingId(recordingId) .maxRecordingId(maxRecordingId); final int length = HEADER_LENGTH + responseEncoder.encodedLength(); // TODO: handle dead/slow subscriber, this is not an acceptable place to get stuck send(reply, length); } void sendDescriptor( final ExclusivePublication reply, final UnsafeBuffer descriptorBuffer, final long correlationId) { recordingDescriptorEncoder .wrapAndApplyHeader(descriptorBuffer, Catalog.CATALOG_FRAME_LENGTH - HEADER_LENGTH, messageHeaderEncoder) .correlationId(correlationId); final int length = descriptorBuffer.getInt(0) + HEADER_LENGTH; while (true) { final long result = reply.offer(descriptorBuffer, Catalog.CATALOG_FRAME_LENGTH - HEADER_LENGTH, length); if (result > 0) { idleStrategy.reset(); break; } if (result == Publication.NOT_CONNECTED || result == Publication.CLOSED) { throw new IllegalStateException("Response channel is down: " + reply); } idleStrategy.idle(); } } }