package io.eguan.ibs;
/*
* #%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 java.io.Closeable;
import java.io.File;
import java.nio.ByteBuffer;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.protobuf.ByteString;
/**
* Java wrapper to access to an Immutable Block System (IBS). Call the builder {@link IbsFactory#createIbs(File)} or
* {@link IbsFactory#openIbs(File)} to create a new IBS instance and call {@link #close()} to release the native
* resources.
*
* @author oodrive
* @author llambert
* @author jmcaba
*
*/
public interface Ibs extends Closeable {
/**
* Header to set in {@link Ibs} path name to enable unit tests with {@link IbsFake}. If set, the {@link IbsFake}
* causes errors during <code>put()</code> and <code>replace()</code>.
*/
public static final String UNIT_TEST_IBS_HEADER = "_+_UnitTest_-_";
static final Logger logger = LoggerFactory.getLogger(Ibs.class);
/**
* Starts the IBS. The IBS can be accessed only when it is started.
*
* @throws IllegalStateException
* if the IBS is already started or is closed
* @throws IbsException
* If the IBS fails to start
*/
public void start() throws IllegalStateException, IbsException;
/**
* Stops the IBS. All the pending transactions are rolled back. Does nothing if the IBS is already stopped or
* closed.
*
* @throws IbsException
* If the IBS fails to stop
*/
public void stop() throws IbsException;
/**
* Tells if the IBS is started.
*
* @return <code>true</code> if the IBS is started.
*/
public boolean isStarted();
/**
* Close the IBS. Once closed, the IBS can not be started anymore. Does nothing if the IBS is already closed.
*/
@Override
public void close();
/**
* Tells if the IBS is closed.
*
* @return <code>true</code> if the IBS is closed.
*/
public boolean isClosed();
/**
* Destroys the IBS. Deletes everything: the configuration file, the directories. Does it even if the IBS is
* started. Before the destroy, the IBS is stopped and closed.
* <p>
* Note: this call is blocking and may take some time if the IBS stores a lot of datas.
*
* @throws IbsIOException
*/
public void destroy() throws IbsIOException;
/**
* Tells if the hot data management is enabled for the IBS. If <code>false</code>,
* {@link #replace(long, long, byte[], byte[], ByteBuffer)} (
* {@link #replace(long, long, byte[], byte[], ByteBuffer, int, int)}) have the same behavior as
* {@link #put(long, long, byte[], ByteBuffer)} (respectively {@link #put(long, long, byte[], ByteBuffer, int, int)}
* ).
*
* @return <code>true</code> if the hot data management is enabled.
* @throws IbsException
*/
public boolean isHotDataEnabled() throws IbsException;
/**
* Gets the data associated with the given key. A new {@link ByteBuffer} of the given length is allocated.
*
* @param key
* key of the data
* @param length
* length of the buffer to allocate. The length of the data associated to the key should be smaller or
* equal to <code>length</code>
* @param allocateDirect
* <code>true</code> if the allocated buffer should be a direct {@link ByteBuffer}.
* @return a newly allocated {@link ByteBuffer} containing the data associated to <code>key</code>
* @throws IbsException
* if the IBS is not available (not started or closed)
* @throws IbsIOException
* if the data load failed
* @throws IbsBufferTooSmallException
* if <code>length</code> is smaller than the length of the data to read
* @throws NullPointerException
* if <code>key</code> is <code>null</code>
*/
public ByteBuffer get(@Nonnull final byte[] key, @Nonnegative final int length, final boolean allocateDirect)
throws IbsException, IbsIOException, IbsBufferTooSmallException, NullPointerException;
/**
* Gets the data associated to the given key. The given buffer is filled, starting at the current position. The data
* to load must fit in the remaining size of the buffer. The position of the buffer is incremented by data length.
*
* @param key
* key of the data
* @param data
* buffer to fill
* @throws IbsException
* if the IBS is not available (not started or closed)
* @throws IbsIOException
* if the data load failed
* @throws IbsBufferTooSmallException
* if the data length exceeds the remaining buffer size
* @throws NullPointerException
* if <code>key</code> or <code>data</code> is <code>null</code>
*/
public void get(@Nonnull final byte[] key, @Nonnull final ByteBuffer data) throws IbsException, IbsIOException,
IbsBufferTooSmallException, NullPointerException;
/**
* Gets the data associated to the given key. The given buffer is filled, starting from the given offset. The
* position of the buffer is not changed.
*
* @param key
* key of the data
* @param data
* buffer to fill
* @param offset
* offset to write to in <code>data</code>
* @param length
* maximum length of the data associated to the key
* @return the data length written in <code>data</code>
* @throws IbsException
* if the IBS is not available (not started or closed)
* @throws IbsIOException
* if the data load failed
* @throws IbsBufferTooSmallException
* if <code>length</code> is smaller than the length of the data to read
* @throws IllegalArgumentException
* if <code>offset</code> is negative or <code>length</code> smaller than 1
* @throws IndexOutOfBoundsException
* if <code>offset</code> and <code>length</code> does not fit into <code>data</code>
* @throws NullPointerException
* if <code>key</code> or <code>data</code> is <code>null</code>
*/
public int get(@Nonnull final byte[] key, @Nonnull final ByteBuffer data, @Nonnegative final int offset,
@Nonnegative final int length) throws IbsException, IbsIOException, IbsBufferTooSmallException,
IllegalArgumentException, IndexOutOfBoundsException, NullPointerException;
/**
* Removes from the IBS the data associated to the given key.
*
* @param key
* key of the data
* @throws IbsException
* if the IBS is not available (not started or closed)
* @throws IbsIOException
* if the data write failed
* @throws NullPointerException
* if <code>key</code> is <code>null</code>
*/
public void del(@Nonnull final byte[] key) throws IbsException, IbsIOException, NullPointerException;
/**
* Associates the key to the given the data in the IBS. The data written is the remaining in the given source
* buffer, starting at the current position. The position of the buffer is incremented by data length.
*
* @param key
* key of the data
* @param data
* buffer to read from the current position. May be <code>null</code> to notify that a new put() of this
* known <code>key</code> has been made.
* @return <code>true</code> if the key/data pair have been added, <code>false</code> if the key/data pair was
* already present in the map
* @throws IbsException
* if the IBS is not available (not started or closed)
* @throws IbsIOException
* if the data write failed
* @throws NullPointerException
* if <code>key</code> is <code>null</code>
*/
public boolean put(@Nonnull final byte[] key, final ByteBuffer data) throws IbsException, IbsIOException,
NullPointerException;
/**
* Associates the key to the given the data in the IBS. The given buffer is written, starting from the given offset
* and for the given size. The position of the buffer is not changed.
*
* @param key
* key of the data
* @param data
* buffer to read
* @param offset
* offset to read from in <code>data</code>
* @param length
* length of the data associated to the key
* @return <code>true</code> if the key/data pair have been added, <code>false</code> if the key/data pair was
* already present in the map
* @throws IbsException
* if the IBS is not available (not started or closed)
* @throws IbsIOException
* if the data write failed
* @throws IllegalArgumentException
* if <code>offset</code> is negative or <code>length</code> smaller than 1
* @throws IndexOutOfBoundsException
* if (<code>offset</code>, <code>length</code>) does not fit into <code>data</code>
* @throws NullPointerException
* if <code>key</code> or <code>data</code> is <code>null</code>
*/
public boolean put(@Nonnull final byte[] key, @Nonnull final ByteBuffer data, @Nonnegative final int offset,
@Nonnegative final int length) throws IbsException, IbsIOException, IllegalArgumentException,
IndexOutOfBoundsException, NullPointerException;
/**
* Associates the key to the given the data in the IBS.
*
* @param key
* key of the data
* @param data
* buffer to read, the whole contents of the buffer will be read.
* @return <code>true</code> if the key/data pair have been added, <code>false</code> if the key/data pair was
* already present in the map
* @throws IbsException
* if the IBS is not available (not started or closed)
* @throws IbsIOException
* if the data write failed
* @throws NullPointerException
* if <code>key</code> or <code>data</code> is <code>null</code>
*/
public boolean put(@Nonnull final byte[] key, @Nonnull final ByteString data) throws IbsException, IbsIOException,
NullPointerException;
/**
* Issue a replace request.
*
* A replace request is an enriched put request that warns the underlying storage that a record has been replaced by
* a new one. The main purpose of this request is to properly handle short-lived records.
*
* The data written is the remaining in the given source buffer, starting at the current position. The position of
* the buffer is incremented by data length.
*
* @param oldKey
* The oldKey is the key associated to the the record that is being (on client side) overwritten by the
* new one.
* @param newKey
* The new key associated to the new record.
* @param data
* buffer to read from the current position. May be <code>null</code> to notify that a new replace() of
* this known <code>newKey</code> has been made.
* @return <code>true</code> if the newKey/data pair have been added, <code>false</code> if the newKey/data pair was
* already present in the map
* @throws IbsException
* if the IBS is not available (not started or closed)
* @throws IbsIOException
* if the data write failed
* @throws NullPointerException
* if <code>oldKey</code>, <code>newKey</code> or <code>data</code> is <code>null</code>
*/
public boolean replace(@Nonnull final byte[] oldKey, @Nonnull final byte[] newKey, final ByteBuffer data)
throws IbsException, IbsIOException;
/**
* Issue a replace request.
*
* A replace request is an enriched put request that warns the underlying storage that a record has been replaced by
* a new one. The main purpose of this request is to properly handle short-lived records.
*
* @param oldKey
* The oldKey is the key associated to the the record that is being (on client side) overwritten by the
* new one.
* @param newKey
* The new key associated to the new record.
* @param data
* buffer to read
* @param offset
* offset to read from in <code>data</code>
* @param length
* length of the data associated to the key
* @return <code>true</code> if the newKey/data pair have been added, <code>false</code> if the newKey/data pair was
* already present in the map
* @throws IbsException
* if the IBS is not available (not started or closed)
* @throws IbsIOException
* if the data write failed
* @throws IllegalArgumentException
* if <code>offset</code> is negative or <code>length</code> smaller than 1
* @throws IndexOutOfBoundsException
* if (<code>offset</code>, <code>length</code>) does not fit into <code>data</code>
* @throws NullPointerException
* if <code>oldKey</code>, <code>newKey</code> or <code>data</code> is <code>null</code>
*/
public boolean replace(@Nonnull final byte[] oldKey, @Nonnull final byte[] newKey, @Nonnull final ByteBuffer data,
@Nonnegative final int offset, @Nonnegative final int length) throws IbsException,
IllegalArgumentException, IbsIOException, IndexOutOfBoundsException, NullPointerException;
/**
* Create a transaction to modify the {@link Ibs}.
*
* @return the transaction ID.
*/
public int createTransaction() throws IbsException, IllegalArgumentException, IbsIOException;
/**
* Associates the key to the given the data in the IBS. The given buffer is written, starting from the given offset
* and for the given size. The position of the buffer is not changed.
* <p>
* Will not be applied before the commit of the transaction.
*
* @param txId
* Id of a valid transaction
* @see #put(byte[], ByteBuffer, int, int)
*/
public boolean put(@Nonnegative final int txId, @Nonnull final byte[] key, @Nonnull final ByteBuffer data,
@Nonnegative final int offset, @Nonnegative final int length) throws IbsException, IbsIOException,
IllegalArgumentException, IndexOutOfBoundsException, NullPointerException;
/**
* Issue a replace request. Will not be applied before the commit of the transaction.
*
* @param txId
* Id of a valid transaction
* @see #replace(byte[], byte[], ByteBuffer, int, int)
*/
public boolean replace(@Nonnegative final int txId, @Nonnull final byte[] oldKey, @Nonnull final byte[] newKey,
@Nonnull final ByteBuffer data, @Nonnegative final int offset, @Nonnegative final int length)
throws IbsException, IllegalArgumentException, IbsIOException, IndexOutOfBoundsException,
NullPointerException;
/**
* Commits the given transaction. All the modifications are applied.
*
* @param txId
* Id of a valid transaction
*/
public void commit(@Nonnegative final int txId) throws IbsException, IllegalArgumentException, IbsIOException;
/**
* Rolls back the given transaction. All the modifications are discarded.
*
* @param txId
* Id of a valid transaction
*/
public void rollback(@Nonnegative final int txId) throws IbsException, IllegalArgumentException, IbsIOException;
}