/** * 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.messageformat; import com.github.ambry.utils.Crc32; import com.github.ambry.utils.CrcInputStream; import com.github.ambry.utils.ZeroBytesInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; /** * Represents a message that consist of just the user metadata and blob content. Additionally, these fields are * zeroed out. * This format is used to replace a put record's user metadata and blob content part as part of hard deleting it. * The usermetadata and blob record versions of the replacement stream will have to be the same as the versions in * the original put record. * * - - - - - - - - - - - - - - - - - - - * | Message Header | * - - - - - - - - - - - - - - - - - - - * | blob key | * - - - - - - - - - - - - - - - - - - - * | Blob Properties Record | * - - - - - - - - - - - - - - - - - - - * | User metadata Record (Zeroed out) | * - - - - - - - - - - - - - - - - - - - * | Blob Record (Zeroed out) | * - - - - - - - - - - - - - - - - - - - */ public class HardDeleteMessageFormatInputStream extends MessageFormatInputStream { private int hardDeleteStreamRelativeOffset; /** * Creates a hard delete stream using the given parameters to replace the usermetadata and blob record fields. * @param userMetadataRelativeOffset the relative offset of userMetadata. * @param userMetadataVersion the version of the userMetadata. * @param userMetadataSize the size of the userMetadata field. * @param blobRecordVersion the version of the blob record. * @param blobType {@link BlobType} of the blob * @param blobStreamSize the size of the blob stream. * @throws MessageFormatException * @throws IOException */ public HardDeleteMessageFormatInputStream(int userMetadataRelativeOffset, short userMetadataVersion, int userMetadataSize, short blobRecordVersion, BlobType blobType, long blobStreamSize) throws MessageFormatException, IOException { ByteBuffer userMetadata = ByteBuffer.allocate(userMetadataSize); InputStream blobStream = new ZeroBytesInputStream(blobStreamSize); hardDeleteStreamRelativeOffset = userMetadataRelativeOffset; int userMetadataRecordSize; ByteBuffer serializedUserMetadata; switch (userMetadataVersion) { case MessageFormatRecord.UserMetadata_Version_V1: userMetadataRecordSize = MessageFormatRecord.UserMetadata_Format_V1.getUserMetadataSize(userMetadata); serializedUserMetadata = ByteBuffer.allocate(userMetadataRecordSize); MessageFormatRecord.UserMetadata_Format_V1.serializeUserMetadataRecord(serializedUserMetadata, userMetadata); serializedUserMetadata.flip(); break; default: throw new MessageFormatException("Unknown version encountered when creating hard delete stream", MessageFormatErrorCodes.Unknown_Format_Version); } long blobRecordSize; ByteBuffer serializedBlobPartialRecord; switch (blobRecordVersion) { case MessageFormatRecord.Blob_Version_V1: blobRecordSize = MessageFormatRecord.Blob_Format_V1.getBlobRecordSize(blobStreamSize); serializedBlobPartialRecord = ByteBuffer.allocate((int) (blobRecordSize - blobStreamSize - MessageFormatRecord.Crc_Size)); MessageFormatRecord.Blob_Format_V1.serializePartialBlobRecord(serializedBlobPartialRecord, blobStreamSize); serializedBlobPartialRecord.flip(); break; case MessageFormatRecord.Blob_Version_V2: blobRecordSize = MessageFormatRecord.Blob_Format_V2.getBlobRecordSize(blobStreamSize); serializedBlobPartialRecord = ByteBuffer.allocate((int) (blobRecordSize - blobStreamSize - MessageFormatRecord.Crc_Size)); MessageFormatRecord.Blob_Format_V2.serializePartialBlobRecord(serializedBlobPartialRecord, blobStreamSize, blobType); serializedBlobPartialRecord.flip(); break; default: throw new MessageFormatException("Unknown version encountered when creating hard delete stream", MessageFormatErrorCodes.Unknown_Format_Version); } buffer = ByteBuffer.allocate( userMetadataRecordSize + (int) (blobRecordSize - blobStreamSize - MessageFormatRecord.Crc_Size)); buffer.put(serializedUserMetadata); int bufferBlobStart = buffer.position(); buffer.put(serializedBlobPartialRecord); Crc32 crc = new Crc32(); crc.update(buffer.array(), bufferBlobStart, buffer.position() - bufferBlobStart); stream = new CrcInputStream(crc, blobStream); streamLength = blobStreamSize; messageLength = buffer.capacity() + streamLength + MessageFormatRecord.Crc_Size; buffer.flip(); } /** * @return The relative offset of the original message that corresponds to this hard delete stream. */ public int getHardDeleteStreamRelativeOffset() { return hardDeleteStreamRelativeOffset; } }