package io.eguan.nrs;
/*
* #%L
* Project eguan
* %%
* Copyright (C) 2012 - 2017 Oodrive
* %%
* 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.
* #L%
*/
import io.eguan.proto.nrs.NrsRemote.NrsFileUpdate.NrsKey;
import io.eguan.utils.mapper.FileMapper;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
/**
* A NrsFile stores a key associated to a block of data corresponding to the contents of a <i>large</i> file. It is
* optimized for sparse files.
*
* @author oodrive
* @author llambert
* @author pwehrle
* @author ebredzinski
*
*/
public final class NrsFile extends NrsAbstractFile<byte[], NrsFile> {
/** Value returned by read() when a hash have been trimmed */
public static final byte[] HASH_TRIMMED = new byte[0];
/**
* Constructs an instance from the given builder.
*
* @param fileMapper
* file mapper handling that file
* @param header
* read header of the file
* @param postOffice
* optional notification of some remote peers.
*/
NrsFile(final FileMapper fileMapper, final NrsFileHeader<NrsFile> header, final NrsMsgPostOffice postOffice) {
super(header.getHashSize(), fileMapper, header, postOffice, HASH_TRIMMED);
}
/**
* Writes the given block in the {@link NrsFileBlock} associated to this {@link NrsFile}.
*
* @param blockIndex
* index of the block
* @param block
* block to write
* @throws IOException
* if the write fails
*/
public final void writeBlock(final long blockIndex, final ByteBuffer block) throws IOException {
final NrsFileBlock nrsFileBlock = getFileBlock();
nrsFileBlock.write(blockIndex, block);
}
/**
* Fills block with the contents of the block.
*
* @param blockIndex
* @param block
* block to fill with the block found in the associated {@link NrsFileBlock}.
* @throws IOException
* @throws IndexOutOfBoundsException
*/
public final void readBlock(long blockIndex, ByteBuffer block) throws IndexOutOfBoundsException, IOException {
final NrsFileBlock nrsFileBlock = getFileBlock();
nrsFileBlock.read(blockIndex, block);
}
@Override
final byte[] newElement() {
return new byte[getElementSize()];
}
@Override
final void checkValueLength(final byte[] value) throws NullPointerException, IllegalArgumentException {
final int elementSize = getElementSize();
if (value.length != elementSize) {
throw new IllegalArgumentException("Invalid hash size=" + value.length + " instead of " + elementSize);
}
}
@Override
final void appendDebugString(final StringBuilder dst, final byte[] value) {
dst.append(value[0]).append(value[1]).append(value[2]).append(value[3]);
}
@Override
final byte[] decodeValue(final NrsKey value) {
return value.getKey().toByteArray();
}
@Override
final void readFully(final MappedByteBuffer src, final byte[] result) {
assert result.length == getElementSize();
src.get(result);
}
@Override
final void readFully(final FileChannel src, final byte[] result) throws IOException {
final int elementSize = getElementSize();
assert result.length == elementSize;
final ByteBuffer dst = ByteBuffer.wrap(result);
int readLen = 0;
while (readLen < elementSize) {
final int read = src.read(dst);
if (read == -1) {
throw new IOException("Unexpected end of file '" + getFile() + "' readOffset=" + src.position());
}
readLen += read;
}
}
@Override
final void writeFully(final FileChannel dst, final byte[] value) throws IOException {
final int elementSize = getElementSize();
assert value.length == elementSize;
final ByteBuffer src = ByteBuffer.wrap(value);
int writeLen = 0;
while (writeLen < elementSize) {
writeLen += dst.write(src);
}
}
}