/** * Copyright 2016 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.commons.ServerErrorCode; import com.github.ambry.store.FindTokenFactory; import com.github.ambry.utils.Utils; import java.io.DataInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; import java.util.ArrayList; import java.util.List; /** * The response for a ReplicaMetadataRequest. This returns the new entries found * and the new token that could be used for future searches */ public class ReplicaMetadataResponse extends Response { private List<ReplicaMetadataResponseInfo> replicaMetadataResponseInfoList; private int replicaMetadataResponseInfoListSizeInBytes; private static int Replica_Metadata_Response_Info_List_Size_In_Bytes = 4; static final short Replica_Metadata_Response_Version_V1 = 1; static final short Replica_Metadata_Response_Version_V2 = 2; // @todo change this to V2 once all cluster nodes understand V2. private static final short currentVersion = Replica_Metadata_Response_Version_V1; public ReplicaMetadataResponse(int correlationId, String clientId, ServerErrorCode error, List<ReplicaMetadataResponseInfo> replicaMetadataResponseInfoList) { super(RequestOrResponseType.ReplicaMetadataResponse, currentVersion, correlationId, clientId, error); this.replicaMetadataResponseInfoList = replicaMetadataResponseInfoList; this.replicaMetadataResponseInfoListSizeInBytes = 0; for (ReplicaMetadataResponseInfo replicaMetadataResponseInfo : replicaMetadataResponseInfoList) { this.replicaMetadataResponseInfoListSizeInBytes += replicaMetadataResponseInfo.sizeInBytes(); } } public ReplicaMetadataResponse(int correlationId, String clientId, ServerErrorCode error) { super(RequestOrResponseType.ReplicaMetadataResponse, currentVersion, correlationId, clientId, error); replicaMetadataResponseInfoList = null; replicaMetadataResponseInfoListSizeInBytes = 0; } public List<ReplicaMetadataResponseInfo> getReplicaMetadataResponseInfoList() { return replicaMetadataResponseInfoList; } public static ReplicaMetadataResponse readFrom(DataInputStream stream, FindTokenFactory factory, ClusterMap clusterMap) throws IOException { RequestOrResponseType type = RequestOrResponseType.values()[stream.readShort()]; if (type != RequestOrResponseType.ReplicaMetadataResponse) { throw new IllegalArgumentException("The type of request response is not compatible"); } Short versionId = stream.readShort(); int correlationId = stream.readInt(); String clientId = Utils.readIntString(stream); ServerErrorCode error = ServerErrorCode.values()[stream.readShort()]; int replicaMetadataResponseInfoListCount = stream.readInt(); ArrayList<ReplicaMetadataResponseInfo> replicaMetadataResponseInfoList = new ArrayList<ReplicaMetadataResponseInfo>(replicaMetadataResponseInfoListCount); for (int i = 0; i < replicaMetadataResponseInfoListCount; i++) { ReplicaMetadataResponseInfo replicaMetadataResponseInfo = ReplicaMetadataResponseInfo.readFrom(stream, factory, clusterMap, versionId); replicaMetadataResponseInfoList.add(replicaMetadataResponseInfo); } if (error != ServerErrorCode.No_Error) { return new ReplicaMetadataResponse(correlationId, clientId, error); } else { // ignore version for now return new ReplicaMetadataResponse(correlationId, clientId, error, replicaMetadataResponseInfoList); } } @Override public long writeTo(WritableByteChannel channel) throws IOException { if (bufferToSend == null) { bufferToSend = ByteBuffer.allocate((int) sizeInBytes()); writeHeader(); if (replicaMetadataResponseInfoList != null) { bufferToSend.putInt(replicaMetadataResponseInfoList.size()); for (ReplicaMetadataResponseInfo replicaMetadataResponseInfo : replicaMetadataResponseInfoList) { replicaMetadataResponseInfo.writeTo(bufferToSend); } } else { bufferToSend.putInt(0); } bufferToSend.flip(); } return bufferToSend.remaining() > 0 ? channel.write(bufferToSend) : 0; } @Override public boolean isSendComplete() { return bufferToSend != null && bufferToSend.remaining() == 0; } @Override public long sizeInBytes() { return super.sizeInBytes() + Replica_Metadata_Response_Info_List_Size_In_Bytes + replicaMetadataResponseInfoListSizeInBytes; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("ReplicaMetadataResponse["); sb.append("ServerErrorCode=").append(getError()); if (replicaMetadataResponseInfoList != null) { sb.append(" ReplicaMetadataResponseInfo "); for (ReplicaMetadataResponseInfo replicaMetadataResponseInfo : replicaMetadataResponseInfoList) { sb.append(replicaMetadataResponseInfo.toString()); } } sb.append("]"); return sb.toString(); } /** * @return the current version in which new ReplicaMetadataResponse objects are created. */ public static short getCurrentVersion() { return currentVersion; } }