]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
11fdf7f2 TL |
2 | // This source code is licensed under both the GPLv2 (found in the |
3 | // COPYING file in the root directory) and Apache 2.0 License | |
4 | // (found in the LICENSE.Apache file in the root directory). | |
7c673cae FG |
5 | |
6 | package org.rocksdb; | |
7 | ||
8 | import java.util.List; | |
9 | ||
10 | /** | |
11 | * Database with TTL support. | |
12 | * | |
13 | * <p><strong>Use case</strong></p> | |
14 | * <p>This API should be used to open the db when key-values inserted are | |
15 | * meant to be removed from the db in a non-strict 'ttl' amount of time | |
16 | * Therefore, this guarantees that key-values inserted will remain in the | |
17 | * db for >= ttl amount of time and the db will make efforts to remove the | |
18 | * key-values as soon as possible after ttl seconds of their insertion. | |
19 | * </p> | |
20 | * | |
21 | * <p><strong>Behaviour</strong></p> | |
22 | * <p>TTL is accepted in seconds | |
23 | * (int32_t)Timestamp(creation) is suffixed to values in Put internally | |
24 | * Expired TTL values deleted in compaction only:(Timestamp+ttl<time_now) | |
25 | * Get/Iterator may return expired entries(compaction not run on them yet) | |
26 | * Different TTL may be used during different Opens | |
27 | * </p> | |
28 | * | |
29 | * <p><strong>Example</strong></p> | |
30 | * <ul> | |
31 | * <li>Open1 at t=0 with ttl=4 and insert k1,k2, close at t=2</li> | |
32 | * <li>Open2 at t=3 with ttl=5. Now k1,k2 should be deleted at t>=5</li> | |
33 | * </ul> | |
34 | * | |
35 | * <p> | |
36 | * read_only=true opens in the usual read-only mode. Compactions will not be | |
37 | * triggered(neither manual nor automatic), so no expired entries removed | |
38 | * </p> | |
39 | * | |
40 | * <p><strong>Constraints</strong></p> | |
41 | * <p>Not specifying/passing or non-positive TTL behaves | |
42 | * like TTL = infinity</p> | |
43 | * | |
44 | * <p><strong>!!!WARNING!!!</strong></p> | |
45 | * <p>Calling DB::Open directly to re-open a db created by this API will get | |
46 | * corrupt values(timestamp suffixed) and no ttl effect will be there | |
47 | * during the second Open, so use this API consistently to open the db | |
48 | * Be careful when passing ttl with a small positive value because the | |
49 | * whole database may be deleted in a small amount of time.</p> | |
50 | */ | |
51 | public class TtlDB extends RocksDB { | |
52 | ||
53 | /** | |
54 | * <p>Opens a TtlDB.</p> | |
55 | * | |
56 | * <p>Database is opened in read-write mode without default TTL.</p> | |
57 | * | |
58 | * @param options {@link org.rocksdb.Options} instance. | |
59 | * @param db_path path to database. | |
60 | * | |
61 | * @return TtlDB instance. | |
62 | * | |
63 | * @throws RocksDBException thrown if an error occurs within the native | |
64 | * part of the library. | |
65 | */ | |
66 | public static TtlDB open(final Options options, final String db_path) | |
67 | throws RocksDBException { | |
68 | return open(options, db_path, 0, false); | |
69 | } | |
70 | ||
71 | /** | |
72 | * <p>Opens a TtlDB.</p> | |
73 | * | |
74 | * @param options {@link org.rocksdb.Options} instance. | |
75 | * @param db_path path to database. | |
76 | * @param ttl time to live for new entries. | |
77 | * @param readOnly boolean value indicating if database if db is | |
78 | * opened read-only. | |
79 | * | |
80 | * @return TtlDB instance. | |
81 | * | |
82 | * @throws RocksDBException thrown if an error occurs within the native | |
83 | * part of the library. | |
84 | */ | |
85 | public static TtlDB open(final Options options, final String db_path, | |
86 | final int ttl, final boolean readOnly) throws RocksDBException { | |
87 | return new TtlDB(open(options.nativeHandle_, db_path, ttl, readOnly)); | |
88 | } | |
89 | ||
90 | /** | |
91 | * <p>Opens a TtlDB.</p> | |
92 | * | |
93 | * @param options {@link org.rocksdb.Options} instance. | |
94 | * @param db_path path to database. | |
95 | * @param columnFamilyDescriptors list of column family descriptors | |
96 | * @param columnFamilyHandles will be filled with ColumnFamilyHandle instances | |
97 | * on open. | |
98 | * @param ttlValues time to live values per column family handle | |
99 | * @param readOnly boolean value indicating if database if db is | |
100 | * opened read-only. | |
101 | * | |
102 | * @return TtlDB instance. | |
103 | * | |
104 | * @throws RocksDBException thrown if an error occurs within the native | |
105 | * part of the library. | |
106 | * @throws java.lang.IllegalArgumentException when there is not a ttl value | |
107 | * per given column family handle. | |
108 | */ | |
109 | public static TtlDB open(final DBOptions options, final String db_path, | |
110 | final List<ColumnFamilyDescriptor> columnFamilyDescriptors, | |
111 | final List<ColumnFamilyHandle> columnFamilyHandles, | |
112 | final List<Integer> ttlValues, final boolean readOnly) | |
113 | throws RocksDBException { | |
114 | if (columnFamilyDescriptors.size() != ttlValues.size()) { | |
115 | throw new IllegalArgumentException("There must be a ttl value per column" | |
1e59de90 | 116 | + " family handle."); |
7c673cae FG |
117 | } |
118 | ||
119 | final byte[][] cfNames = new byte[columnFamilyDescriptors.size()][]; | |
120 | final long[] cfOptionHandles = new long[columnFamilyDescriptors.size()]; | |
121 | for (int i = 0; i < columnFamilyDescriptors.size(); i++) { | |
122 | final ColumnFamilyDescriptor cfDescriptor = | |
123 | columnFamilyDescriptors.get(i); | |
f67539c2 TL |
124 | cfNames[i] = cfDescriptor.getName(); |
125 | cfOptionHandles[i] = cfDescriptor.getOptions().nativeHandle_; | |
7c673cae FG |
126 | } |
127 | ||
128 | final int ttlVals[] = new int[ttlValues.size()]; | |
129 | for(int i = 0; i < ttlValues.size(); i++) { | |
130 | ttlVals[i] = ttlValues.get(i); | |
131 | } | |
132 | final long[] handles = openCF(options.nativeHandle_, db_path, | |
133 | cfNames, cfOptionHandles, ttlVals, readOnly); | |
134 | ||
135 | final TtlDB ttlDB = new TtlDB(handles[0]); | |
136 | for (int i = 1; i < handles.length; i++) { | |
137 | columnFamilyHandles.add(new ColumnFamilyHandle(ttlDB, handles[i])); | |
138 | } | |
139 | return ttlDB; | |
140 | } | |
141 | ||
494da23a TL |
142 | /** |
143 | * <p>Close the TtlDB instance and release resource.</p> | |
144 | * | |
145 | * This is similar to {@link #close()} except that it | |
146 | * throws an exception if any error occurs. | |
147 | * | |
148 | * This will not fsync the WAL files. | |
149 | * If syncing is required, the caller must first call {@link #syncWal()} | |
150 | * or {@link #write(WriteOptions, WriteBatch)} using an empty write batch | |
151 | * with {@link WriteOptions#setSync(boolean)} set to true. | |
152 | * | |
153 | * See also {@link #close()}. | |
154 | * | |
155 | * @throws RocksDBException if an error occurs whilst closing. | |
156 | */ | |
157 | public void closeE() throws RocksDBException { | |
158 | if (owningHandle_.compareAndSet(true, false)) { | |
159 | try { | |
160 | closeDatabase(nativeHandle_); | |
161 | } finally { | |
162 | disposeInternal(); | |
163 | } | |
164 | } | |
165 | } | |
166 | ||
167 | /** | |
168 | * <p>Close the TtlDB instance and release resource.</p> | |
169 | * | |
170 | * | |
171 | * This will not fsync the WAL files. | |
172 | * If syncing is required, the caller must first call {@link #syncWal()} | |
173 | * or {@link #write(WriteOptions, WriteBatch)} using an empty write batch | |
174 | * with {@link WriteOptions#setSync(boolean)} set to true. | |
175 | * | |
176 | * See also {@link #close()}. | |
177 | */ | |
178 | @Override | |
179 | public void close() { | |
180 | if (owningHandle_.compareAndSet(true, false)) { | |
181 | try { | |
182 | closeDatabase(nativeHandle_); | |
183 | } catch (final RocksDBException e) { | |
184 | // silently ignore the error report | |
185 | } finally { | |
186 | disposeInternal(); | |
187 | } | |
188 | } | |
189 | } | |
190 | ||
7c673cae FG |
191 | /** |
192 | * <p>Creates a new ttl based column family with a name defined | |
193 | * in given ColumnFamilyDescriptor and allocates a | |
194 | * ColumnFamilyHandle within an internal structure.</p> | |
195 | * | |
196 | * <p>The ColumnFamilyHandle is automatically disposed with DB | |
197 | * disposal.</p> | |
198 | * | |
199 | * @param columnFamilyDescriptor column family to be created. | |
200 | * @param ttl TTL to set for this column family. | |
201 | * | |
202 | * @return {@link org.rocksdb.ColumnFamilyHandle} instance. | |
203 | * | |
204 | * @throws RocksDBException thrown if error happens in underlying | |
205 | * native library. | |
206 | */ | |
207 | public ColumnFamilyHandle createColumnFamilyWithTtl( | |
208 | final ColumnFamilyDescriptor columnFamilyDescriptor, | |
209 | final int ttl) throws RocksDBException { | |
210 | return new ColumnFamilyHandle(this, | |
211 | createColumnFamilyWithTtl(nativeHandle_, | |
494da23a TL |
212 | columnFamilyDescriptor.getName(), |
213 | columnFamilyDescriptor.getOptions().nativeHandle_, ttl)); | |
7c673cae FG |
214 | } |
215 | ||
216 | /** | |
217 | * <p>A protected constructor that will be used in the static | |
218 | * factory method | |
219 | * {@link #open(Options, String, int, boolean)} | |
220 | * and | |
221 | * {@link #open(DBOptions, String, java.util.List, java.util.List, | |
222 | * java.util.List, boolean)}. | |
223 | * </p> | |
224 | * | |
225 | * @param nativeHandle The native handle of the C++ TtlDB object | |
226 | */ | |
227 | protected TtlDB(final long nativeHandle) { | |
228 | super(nativeHandle); | |
229 | } | |
230 | ||
494da23a | 231 | @Override protected native void disposeInternal(final long handle); |
7c673cae FG |
232 | |
233 | private native static long open(final long optionsHandle, | |
234 | final String db_path, final int ttl, final boolean readOnly) | |
235 | throws RocksDBException; | |
236 | private native static long[] openCF(final long optionsHandle, | |
237 | final String db_path, final byte[][] columnFamilyNames, | |
238 | final long[] columnFamilyOptions, final int[] ttlValues, | |
239 | final boolean readOnly) throws RocksDBException; | |
240 | private native long createColumnFamilyWithTtl(final long handle, | |
241 | final byte[] columnFamilyName, final long columnFamilyOptions, int ttl) | |
242 | throws RocksDBException; | |
494da23a TL |
243 | private native static void closeDatabase(final long handle) |
244 | throws RocksDBException; | |
7c673cae | 245 | } |