/** * 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.BlobId; import com.github.ambry.store.MessageInfo; import java.io.DataInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; /** * A serde for serializing and deserializing list of message info */ class MessageInfoListSerde { private final List<MessageInfo> messageInfoList; static final short MessageInfoListVersion_V1 = 1; static final short MessageInfoListVersion_V2 = 2; private final short version; private static final byte CRC_PRESENT = (byte) 1; private static final byte DELETED = (byte) 1; MessageInfoListSerde(List<MessageInfo> messageInfoList, short version) { this.messageInfoList = messageInfoList; this.version = version; } int getMessageInfoListSize() { int listcountSize = 4; if (messageInfoList == null) { return listcountSize; } int size = 0; int longfieldSize = 8; size += listcountSize; for (MessageInfo messageInfo : messageInfoList) { size += messageInfo.getStoreKey().sizeInBytes(); // message size size += longfieldSize; // expiration time size += longfieldSize; // whether deleted size += 1; if (version == MessageInfoListVersion_V2) { // whether crc is present size += 1; if (messageInfo.getCrc() != null) { // crc size += longfieldSize; } } } return size; } void serializeMessageInfoList(ByteBuffer outputBuffer) { outputBuffer.putInt(messageInfoList == null ? 0 : messageInfoList.size()); if (messageInfoList != null) { for (MessageInfo messageInfo : messageInfoList) { outputBuffer.put(messageInfo.getStoreKey().toBytes()); outputBuffer.putLong(messageInfo.getSize()); outputBuffer.putLong(messageInfo.getExpirationTimeInMs()); outputBuffer.put(messageInfo.isDeleted() ? DELETED : (byte) ~DELETED); if (version == MessageInfoListVersion_V2) { Long crc = messageInfo.getCrc(); if (crc != null) { outputBuffer.put(CRC_PRESENT); outputBuffer.putLong(crc); } else { outputBuffer.put((byte) ~CRC_PRESENT); } } } } } static List<MessageInfo> deserializeMessageInfoList(DataInputStream stream, ClusterMap map, short versionToDeserializeIn) throws IOException { int messageInfoListCount = stream.readInt(); ArrayList<MessageInfo> messageListInfo = new ArrayList<MessageInfo>(messageInfoListCount); for (int i = 0; i < messageInfoListCount; i++) { BlobId id = new BlobId(stream, map); long size = stream.readLong(); long ttl = stream.readLong(); boolean isDeleted = stream.readByte() == DELETED; Long crc = null; if (versionToDeserializeIn == MessageInfoListVersion_V2) { crc = stream.readByte() == CRC_PRESENT ? stream.readLong() : null; } messageListInfo.add(new MessageInfo(id, size, isDeleted, ttl, crc)); } return messageListInfo; } List<MessageInfo> getMessageInfoList() { return messageInfoList; } }