| // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
| // This source code is licensed under both the GPLv2 (found in the |
| // COPYING file in the root directory) and Apache 2.0 License |
| // (found in the LICENSE.Apache file in the root directory). |
| |
| package org.rocksdb; |
| |
| import java.util.List; |
| |
| /** |
| * Database with TTL support. |
| * |
| * <p><strong>Use case</strong></p> |
| * <p>This API should be used to open the db when key-values inserted are |
| * meant to be removed from the db in a non-strict 'ttl' amount of time |
| * Therefore, this guarantees that key-values inserted will remain in the |
| * db for >= ttl amount of time and the db will make efforts to remove the |
| * key-values as soon as possible after ttl seconds of their insertion. |
| * </p> |
| * |
| * <p><strong>Behaviour</strong></p> |
| * <p>TTL is accepted in seconds |
| * (int32_t)Timestamp(creation) is suffixed to values in Put internally |
| * Expired TTL values deleted in compaction only:(Timestamp+ttl<time_now) |
| * Get/Iterator may return expired entries(compaction not run on them yet) |
| * Different TTL may be used during different Opens |
| * </p> |
| * |
| * <p><strong>Example</strong></p> |
| * <ul> |
| * <li>Open1 at t=0 with ttl=4 and insert k1,k2, close at t=2</li> |
| * <li>Open2 at t=3 with ttl=5. Now k1,k2 should be deleted at t>=5</li> |
| * </ul> |
| * |
| * <p> |
| * read_only=true opens in the usual read-only mode. Compactions will not be |
| * triggered(neither manual nor automatic), so no expired entries removed |
| * </p> |
| * |
| * <p><strong>Constraints</strong></p> |
| * <p>Not specifying/passing or non-positive TTL behaves |
| * like TTL = infinity</p> |
| * |
| * <p><strong>!!!WARNING!!!</strong></p> |
| * <p>Calling DB::Open directly to re-open a db created by this API will get |
| * corrupt values(timestamp suffixed) and no ttl effect will be there |
| * during the second Open, so use this API consistently to open the db |
| * Be careful when passing ttl with a small positive value because the |
| * whole database may be deleted in a small amount of time.</p> |
| */ |
| public class TtlDB extends RocksDB { |
| |
| /** |
| * <p>Opens a TtlDB.</p> |
| * |
| * <p>Database is opened in read-write mode without default TTL.</p> |
| * |
| * @param options {@link org.rocksdb.Options} instance. |
| * @param db_path path to database. |
| * |
| * @return TtlDB instance. |
| * |
| * @throws RocksDBException thrown if an error occurs within the native |
| * part of the library. |
| */ |
| public static TtlDB open(final Options options, final String db_path) |
| throws RocksDBException { |
| return open(options, db_path, 0, false); |
| } |
| |
| /** |
| * <p>Opens a TtlDB.</p> |
| * |
| * @param options {@link org.rocksdb.Options} instance. |
| * @param db_path path to database. |
| * @param ttl time to live for new entries. |
| * @param readOnly boolean value indicating if database if db is |
| * opened read-only. |
| * |
| * @return TtlDB instance. |
| * |
| * @throws RocksDBException thrown if an error occurs within the native |
| * part of the library. |
| */ |
| public static TtlDB open(final Options options, final String db_path, |
| final int ttl, final boolean readOnly) throws RocksDBException { |
| return new TtlDB(open(options.nativeHandle_, db_path, ttl, readOnly)); |
| } |
| |
| /** |
| * <p>Opens a TtlDB.</p> |
| * |
| * @param options {@link org.rocksdb.Options} instance. |
| * @param db_path path to database. |
| * @param columnFamilyDescriptors list of column family descriptors |
| * @param columnFamilyHandles will be filled with ColumnFamilyHandle instances |
| * on open. |
| * @param ttlValues time to live values per column family handle |
| * @param readOnly boolean value indicating if database if db is |
| * opened read-only. |
| * |
| * @return TtlDB instance. |
| * |
| * @throws RocksDBException thrown if an error occurs within the native |
| * part of the library. |
| * @throws java.lang.IllegalArgumentException when there is not a ttl value |
| * per given column family handle. |
| */ |
| public static TtlDB open(final DBOptions options, final String db_path, |
| final List<ColumnFamilyDescriptor> columnFamilyDescriptors, |
| final List<ColumnFamilyHandle> columnFamilyHandles, |
| final List<Integer> ttlValues, final boolean readOnly) |
| throws RocksDBException { |
| if (columnFamilyDescriptors.size() != ttlValues.size()) { |
| throw new IllegalArgumentException("There must be a ttl value per column" |
| + "family handle."); |
| } |
| |
| final byte[][] cfNames = new byte[columnFamilyDescriptors.size()][]; |
| final long[] cfOptionHandles = new long[columnFamilyDescriptors.size()]; |
| for (int i = 0; i < columnFamilyDescriptors.size(); i++) { |
| final ColumnFamilyDescriptor cfDescriptor = |
| columnFamilyDescriptors.get(i); |
| cfNames[i] = cfDescriptor.columnFamilyName(); |
| cfOptionHandles[i] = cfDescriptor.columnFamilyOptions().nativeHandle_; |
| } |
| |
| final int ttlVals[] = new int[ttlValues.size()]; |
| for(int i = 0; i < ttlValues.size(); i++) { |
| ttlVals[i] = ttlValues.get(i); |
| } |
| final long[] handles = openCF(options.nativeHandle_, db_path, |
| cfNames, cfOptionHandles, ttlVals, readOnly); |
| |
| final TtlDB ttlDB = new TtlDB(handles[0]); |
| for (int i = 1; i < handles.length; i++) { |
| columnFamilyHandles.add(new ColumnFamilyHandle(ttlDB, handles[i])); |
| } |
| return ttlDB; |
| } |
| |
| /** |
| * <p>Creates a new ttl based column family with a name defined |
| * in given ColumnFamilyDescriptor and allocates a |
| * ColumnFamilyHandle within an internal structure.</p> |
| * |
| * <p>The ColumnFamilyHandle is automatically disposed with DB |
| * disposal.</p> |
| * |
| * @param columnFamilyDescriptor column family to be created. |
| * @param ttl TTL to set for this column family. |
| * |
| * @return {@link org.rocksdb.ColumnFamilyHandle} instance. |
| * |
| * @throws RocksDBException thrown if error happens in underlying |
| * native library. |
| */ |
| public ColumnFamilyHandle createColumnFamilyWithTtl( |
| final ColumnFamilyDescriptor columnFamilyDescriptor, |
| final int ttl) throws RocksDBException { |
| return new ColumnFamilyHandle(this, |
| createColumnFamilyWithTtl(nativeHandle_, |
| columnFamilyDescriptor.columnFamilyName(), |
| columnFamilyDescriptor.columnFamilyOptions().nativeHandle_, ttl)); |
| } |
| |
| /** |
| * <p>Close the TtlDB instance and release resource.</p> |
| * |
| * <p>Internally, TtlDB owns the {@code rocksdb::DB} pointer |
| * to its associated {@link org.rocksdb.RocksDB}. The release |
| * of that RocksDB pointer is handled in the destructor of the |
| * c++ {@code rocksdb::TtlDB} and should be transparent to |
| * Java developers.</p> |
| */ |
| @Override |
| public void close() { |
| super.close(); |
| } |
| |
| /** |
| * <p>A protected constructor that will be used in the static |
| * factory method |
| * {@link #open(Options, String, int, boolean)} |
| * and |
| * {@link #open(DBOptions, String, java.util.List, java.util.List, |
| * java.util.List, boolean)}. |
| * </p> |
| * |
| * @param nativeHandle The native handle of the C++ TtlDB object |
| */ |
| protected TtlDB(final long nativeHandle) { |
| super(nativeHandle); |
| } |
| |
| @Override protected void finalize() throws Throwable { |
| close(); //TODO(AR) revisit here when implementing AutoCloseable |
| super.finalize(); |
| } |
| |
| private native static long open(final long optionsHandle, |
| final String db_path, final int ttl, final boolean readOnly) |
| throws RocksDBException; |
| private native static long[] openCF(final long optionsHandle, |
| final String db_path, final byte[][] columnFamilyNames, |
| final long[] columnFamilyOptions, final int[] ttlValues, |
| final boolean readOnly) throws RocksDBException; |
| private native long createColumnFamilyWithTtl(final long handle, |
| final byte[] columnFamilyName, final long columnFamilyOptions, int ttl) |
| throws RocksDBException; |
| } |