/* * 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.store; import com.github.ambry.utils.Utils; import java.io.DataInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; /** * Contains all the details required for a compaction cycle. */ class CompactionDetails { private static final short VERSION_0 = 0; private static final int VERSION_SIZE = 2; private static final int REFERENCE_TIME_SIZE = 8; private static final int SEGMENT_COUNT_SIZE = 4; private static final int SEGMENT_NAME_LENGTH_SIZE = 4; private final long referenceTimeMs; private final List<String> logSegmentsUnderCompaction; /** * Construct a representation of all the details required for a compaction cycle. * @param referenceTimeMs the epoch time to use to get the same results from the {@link BlobStore} as when these * details were created. * @param logSegmentsUnderCompaction the names of the {@link LogSegment} under compaction. * @throws IllegalArgumentException if {@code referenceTimeMs} < 0 or if {@code logSegmentsUnderCompaction} has no * elements. */ CompactionDetails(long referenceTimeMs, List<String> logSegmentsUnderCompaction) { if (referenceTimeMs < 0 || logSegmentsUnderCompaction.size() == 0) { throw new IllegalArgumentException( "Illegal arguments provided. Ref time: [" + referenceTimeMs + "]. " + "Segments under compaction size: [" + logSegmentsUnderCompaction.size() + "]"); } this.referenceTimeMs = referenceTimeMs; this.logSegmentsUnderCompaction = logSegmentsUnderCompaction; } /** * @param stream the serialized version of the {@link CompactionDetails} that has to be loaded. * @return a representation of all the details required for compaction from the given {@code stream}. * @throws IllegalArgumentException if the version is not recognized * @throws IOException if there is an I/O error reading from the stream */ static CompactionDetails fromBytes(DataInputStream stream) throws IOException { CompactionDetails details; short version = stream.readShort(); switch (version) { case VERSION_0: long referenceTime = stream.readLong(); int segmentCount = stream.readInt(); List<String> logSegmentsUnderCompaction = new ArrayList<>(); for (int i = 0; i < segmentCount; i++) { logSegmentsUnderCompaction.add(Utils.readIntString(stream)); } details = new CompactionDetails(referenceTime, logSegmentsUnderCompaction); break; default: throw new IllegalArgumentException("Unrecognized version: " + version); } return details; } /** * @return the epoch time to use to get the same results from the {@link BlobStore} as when the details were created. * Guaranteed to be >= 0. */ long getReferenceTimeMs() { return referenceTimeMs; } /** * @return the names of the segments under compaction. Guaranteed to contain at least one element. */ List<String> getLogSegmentsUnderCompaction() { return logSegmentsUnderCompaction; } /** * @return serialized representation of this object. */ byte[] toBytes() { /* Description of format version referenceTimeMs size of the logSegmentsUnderCompaction list segment_1_name_length segment_1_name segment_2_name_length segment_2_name .... */ List<byte[]> segmentNameBytesList = new ArrayList<>(); int size = VERSION_SIZE + REFERENCE_TIME_SIZE + SEGMENT_COUNT_SIZE; for (String segmentName : logSegmentsUnderCompaction) { byte[] segmentNameBytes = segmentName.getBytes(); segmentNameBytesList.add(segmentNameBytes); size += SEGMENT_NAME_LENGTH_SIZE + segmentNameBytes.length; } byte[] buf = new byte[size]; ByteBuffer bufWrap = ByteBuffer.wrap(buf); // version bufWrap.putShort(VERSION_0); // reference time bufWrap.putLong(referenceTimeMs); // size of logSegmentsUnderCompaction bufWrap.putInt(logSegmentsUnderCompaction.size()); // log segments under compaction for (byte[] segmentNameBytes : segmentNameBytesList) { bufWrap.putInt(segmentNameBytes.length); bufWrap.put(segmentNameBytes); } return buf; } @Override public String toString() { return "(Delete Ref Time [" + referenceTimeMs + "] Segments to compact [" + logSegmentsUnderCompaction + "])"; } }