/*
* Copyright 2017 LinkedIn Corp. All rights reserved.
*
* 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.
*/
package com.github.ambry.protocol;
import com.github.ambry.clustermap.ClusterMap;
import com.github.ambry.clustermap.PartitionId;
import com.github.ambry.utils.Utils;
import java.io.DataInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
/**
* Representation of an administration request. Types of requests are represented by {@link AdminRequestOrResponseType}.
*/
public class AdminRequest extends RequestOrResponse {
private static final int REQUEST_TYPE_SIZE = 2;
private static final short ADMIN_REQUEST_VERSION_V1 = 1;
private final AdminRequestOrResponseType type;
private final PartitionId partitionId;
private final long sizeInBytes;
private int sizeSent = 0;
/**
* Reads from a stream and constructs an {@link AdminRequest}.
* @param stream the {@link DataInputStream} to read from.
* @param clusterMap the {@link ClusterMap} in use.
* @return {@link AdminRequest} that is deserialized from the {@code stream}.
* @throws IOException if there is an I/O error reading from {@code stream}
*/
public static AdminRequest readFrom(DataInputStream stream, ClusterMap clusterMap) throws IOException {
Short versionId = stream.readShort();
if (!versionId.equals(ADMIN_REQUEST_VERSION_V1)) {
throw new IllegalStateException("Unrecognized version for AdminRequest: " + ADMIN_REQUEST_VERSION_V1);
}
int correlationId = stream.readInt();
String clientId = Utils.readIntString(stream);
AdminRequestOrResponseType type = AdminRequestOrResponseType.values()[stream.readShort()];
AdminRequest request;
switch (type) {
case TriggerCompaction:
PartitionId id = clusterMap.getPartitionIdFromStream(stream);
request = new AdminRequest(type, id, correlationId, clientId);
break;
default:
throw new IllegalArgumentException("Unrecognized admin request type: " + type);
}
return request;
}
/**
* Constructs an admin request with the given parameters.
* @param type the type of the request.
* @param partitionId the {@link PartitionId} that the operation should work on. {@link null} if not applicable.
* @param correlationId an ID to help match responses to requests.
* @param clientId the ID of the client.
*/
public AdminRequest(AdminRequestOrResponseType type, PartitionId partitionId, int correlationId, String clientId) {
super(RequestOrResponseType.AdminRequest, ADMIN_REQUEST_VERSION_V1, correlationId, clientId);
this.type = type;
this.partitionId = partitionId;
sizeInBytes = computeAndGetSizeInBytes();
}
@Override
public long writeTo(WritableByteChannel channel) throws IOException {
long written = 0;
if (bufferToSend == null) {
serializeIntoBuffer();
}
if (bufferToSend.remaining() > 0) {
written = channel.write(bufferToSend);
sizeSent += written;
}
return written;
}
@Override
public boolean isSendComplete() {
return sizeSent == sizeInBytes();
}
@Override
public long sizeInBytes() {
return sizeInBytes;
}
/**
* @return the type of the request
*/
public AdminRequestOrResponseType getType() {
return type;
}
/**
* @return the {@link PartitionId} that the operation will work on. {@link null} if not applicable.
*/
public PartitionId getPartitionId() {
return partitionId;
}
@Override
public String toString() {
return "AdminRequest[ClientId=" + clientId + ", CorrelationId=" + correlationId + ", Type=" + type
+ ", PartitionId=" + partitionId + "]";
}
/**
* @return the size in bytes of the serialized version of the request
*/
private long computeAndGetSizeInBytes() {
long size = super.sizeInBytes() + REQUEST_TYPE_SIZE;
switch (type) {
case TriggerCompaction:
size += partitionId.getBytes().length;
break;
default:
throw new IllegalArgumentException("Unrecognized admin request type: " + type);
}
return size;
}
/**
* Serializes the request into bytes and loads into the buffer for sending.
*/
private void serializeIntoBuffer() {
bufferToSend = ByteBuffer.allocate((int) sizeInBytes());
writeHeader();
bufferToSend.putShort((short) type.ordinal());
switch (type) {
case TriggerCompaction:
bufferToSend.put(partitionId.getBytes());
break;
}
bufferToSend.flip();
}
}