/** * Copyright 2014 NetApp Inc. 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. See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.fs.nfs.stream; import java.io.IOException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class StreamBlock { private long id; private int dataLength; private int startOffset; private final int key; private final byte[] array; private final int blockSizeBits; private final AtomicBoolean ready; public static final int ARRAY_COPY_THRESHOLD = 128; public static final AtomicInteger counter; public static final Log LOG = LogFactory.getLog(StreamBlock.class); static { counter = new AtomicInteger(1); } public StreamBlock(int blockSizeBits) { assert (blockSizeBits > 0 && blockSizeBits < 25); array = new byte[(1 << blockSizeBits)]; this.blockSizeBits = blockSizeBits; this.startOffset = (1 << blockSizeBits); this.dataLength = 0; this.id = -1L; this.ready = new AtomicBoolean(false); key = counter.getAndIncrement(); } public synchronized void reset() { this.startOffset = (1 << blockSizeBits); this.dataLength = 0; } public synchronized long getBlockId() { return id; } public synchronized void setBlockId(long blockId) { this.id = blockId; } public byte[] array() { return array; } public synchronized int readFromBlock(byte[] buffer, int offsetInBuffer, int offsetInBlock, int lengthToRead) throws IOException { int length = Math.min(lengthToRead, getDataLength() - offsetInBlock); // Check for errors if (buffer == null || array == null) { throw new IOException("Buffer(s) are null"); } if (length < 0) { throw new IOException("Cannot write zero or less bytes"); } if (length > buffer.length) { throw new IOException("Cannot write longer than input buffer size"); } if (offsetInBlock < 0) { throw new IOException("Block offset is not within bounds"); } if (offsetInBuffer < 0 || offsetInBuffer >= buffer.length) { throw new IOException("Buffer offset is not in bounds"); } if (offsetInBlock >= getDataLength()) { return -1; } // Copy the data if (length <= ARRAY_COPY_THRESHOLD) { for (int i = 0; i < length; ++i) { buffer[offsetInBuffer + i] = array[offsetInBlock + i]; } } else { System.arraycopy(array, offsetInBlock, buffer, offsetInBuffer, length); } return length; } public synchronized int writeToBlock(byte[] buffer, int offsetInBuffer, int offsetInBlock, int lengthToWrite) throws IOException { int length = Math.min(lengthToWrite, getBlockSize() - offsetInBlock); // Check for errors if (buffer == null || array == null) { throw new IOException("Buffer(s) are null"); } if (length < 0) { throw new IOException("Cannot write zero or less bytes"); } if (length > buffer.length) { throw new IOException("Cannot write longer than input buffer size"); } if (offsetInBlock < 0 || offsetInBlock >= getBlockSize()) { throw new IOException("Block offset is not within bounds"); } if (buffer.length > 0 && (offsetInBuffer < 0 || offsetInBuffer >= buffer.length)) { throw new IOException("Buffer offset is not in bounds: offsetInBuffer=" + offsetInBuffer + " buffer.length=" + buffer.length + " length=" + length); } // Copy the data if (length <= ARRAY_COPY_THRESHOLD) { for (int i = 0; i < length; ++i) { array[offsetInBlock + i] = buffer[offsetInBuffer + i]; } } else { System.arraycopy(buffer, offsetInBuffer, array, offsetInBlock, length); } startOffset = Math.min(offsetInBlock, startOffset); dataLength = offsetInBlock + length - startOffset; return length; } public synchronized int getBlockSizeBits() { return blockSizeBits; } public synchronized int getBlockSize() { return (1 << blockSizeBits); } public synchronized int getDataStartOffset() { return startOffset; } public synchronized int getDataLength() { return dataLength; } public int getKey() { return key; } public boolean isReady() { return ready.get(); } public boolean setReady(boolean isReady) { return ready.getAndSet(isReady); } }