]>
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 | ||
494da23a | 8 | import java.nio.ByteBuffer; |
7c673cae FG |
9 | import java.util.Arrays; |
10 | import java.util.List; | |
11 | import java.util.ArrayList; | |
12 | ||
13 | import org.junit.ClassRule; | |
14 | import org.junit.Rule; | |
15 | import org.junit.Test; | |
16 | import org.junit.rules.TemporaryFolder; | |
17 | ||
18 | import static org.assertj.core.api.Assertions.assertThat; | |
19 | ||
20 | public class MergeTest { | |
21 | ||
22 | @ClassRule | |
23 | public static final RocksMemoryResource rocksMemoryResource = | |
24 | new RocksMemoryResource(); | |
25 | ||
26 | @Rule | |
27 | public TemporaryFolder dbFolder = new TemporaryFolder(); | |
28 | ||
29 | @Test | |
30 | public void stringOption() | |
31 | throws InterruptedException, RocksDBException { | |
32 | try (final Options opt = new Options() | |
33 | .setCreateIfMissing(true) | |
34 | .setMergeOperatorName("stringappend"); | |
35 | final RocksDB db = RocksDB.open(opt, | |
36 | dbFolder.getRoot().getAbsolutePath())) { | |
37 | // writing aa under key | |
38 | db.put("key".getBytes(), "aa".getBytes()); | |
39 | // merge bb under key | |
40 | db.merge("key".getBytes(), "bb".getBytes()); | |
41 | ||
42 | final byte[] value = db.get("key".getBytes()); | |
43 | final String strValue = new String(value); | |
44 | assertThat(strValue).isEqualTo("aa,bb"); | |
45 | } | |
46 | } | |
47 | ||
494da23a TL |
48 | private byte[] longToByteArray(long l) { |
49 | ByteBuffer buf = ByteBuffer.allocate(Long.SIZE / Byte.SIZE); | |
50 | buf.putLong(l); | |
51 | return buf.array(); | |
52 | } | |
53 | ||
54 | private long longFromByteArray(byte[] a) { | |
55 | ByteBuffer buf = ByteBuffer.allocate(Long.SIZE / Byte.SIZE); | |
56 | buf.put(a); | |
57 | buf.flip(); | |
58 | return buf.getLong(); | |
59 | } | |
60 | ||
61 | @Test | |
62 | public void uint64AddOption() | |
63 | throws InterruptedException, RocksDBException { | |
64 | try (final Options opt = new Options() | |
65 | .setCreateIfMissing(true) | |
66 | .setMergeOperatorName("uint64add"); | |
67 | final RocksDB db = RocksDB.open(opt, | |
68 | dbFolder.getRoot().getAbsolutePath())) { | |
69 | // writing (long)100 under key | |
70 | db.put("key".getBytes(), longToByteArray(100)); | |
71 | // merge (long)1 under key | |
72 | db.merge("key".getBytes(), longToByteArray(1)); | |
73 | ||
74 | final byte[] value = db.get("key".getBytes()); | |
75 | final long longValue = longFromByteArray(value); | |
76 | assertThat(longValue).isEqualTo(101); | |
77 | } | |
78 | } | |
79 | ||
7c673cae FG |
80 | @Test |
81 | public void cFStringOption() | |
82 | throws InterruptedException, RocksDBException { | |
83 | ||
84 | try (final ColumnFamilyOptions cfOpt1 = new ColumnFamilyOptions() | |
85 | .setMergeOperatorName("stringappend"); | |
86 | final ColumnFamilyOptions cfOpt2 = new ColumnFamilyOptions() | |
87 | .setMergeOperatorName("stringappend") | |
88 | ) { | |
89 | final List<ColumnFamilyDescriptor> cfDescriptors = Arrays.asList( | |
90 | new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOpt1), | |
91 | new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOpt2) | |
92 | ); | |
93 | ||
94 | final List<ColumnFamilyHandle> columnFamilyHandleList = new ArrayList<>(); | |
95 | try (final DBOptions opt = new DBOptions() | |
96 | .setCreateIfMissing(true) | |
97 | .setCreateMissingColumnFamilies(true); | |
98 | final RocksDB db = RocksDB.open(opt, | |
99 | dbFolder.getRoot().getAbsolutePath(), cfDescriptors, | |
100 | columnFamilyHandleList)) { | |
101 | try { | |
102 | // writing aa under key | |
103 | db.put(columnFamilyHandleList.get(1), | |
104 | "cfkey".getBytes(), "aa".getBytes()); | |
105 | // merge bb under key | |
106 | db.merge(columnFamilyHandleList.get(1), | |
107 | "cfkey".getBytes(), "bb".getBytes()); | |
108 | ||
109 | byte[] value = db.get(columnFamilyHandleList.get(1), | |
110 | "cfkey".getBytes()); | |
111 | String strValue = new String(value); | |
112 | assertThat(strValue).isEqualTo("aa,bb"); | |
113 | } finally { | |
114 | for (final ColumnFamilyHandle handle : columnFamilyHandleList) { | |
115 | handle.close(); | |
116 | } | |
117 | } | |
118 | } | |
119 | } | |
120 | } | |
121 | ||
494da23a TL |
122 | @Test |
123 | public void cFUInt64AddOption() | |
124 | throws InterruptedException, RocksDBException { | |
125 | ||
126 | try (final ColumnFamilyOptions cfOpt1 = new ColumnFamilyOptions() | |
127 | .setMergeOperatorName("uint64add"); | |
128 | final ColumnFamilyOptions cfOpt2 = new ColumnFamilyOptions() | |
129 | .setMergeOperatorName("uint64add") | |
130 | ) { | |
131 | final List<ColumnFamilyDescriptor> cfDescriptors = Arrays.asList( | |
132 | new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOpt1), | |
133 | new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOpt2) | |
134 | ); | |
135 | ||
136 | final List<ColumnFamilyHandle> columnFamilyHandleList = new ArrayList<>(); | |
137 | try (final DBOptions opt = new DBOptions() | |
138 | .setCreateIfMissing(true) | |
139 | .setCreateMissingColumnFamilies(true); | |
140 | final RocksDB db = RocksDB.open(opt, | |
141 | dbFolder.getRoot().getAbsolutePath(), cfDescriptors, | |
142 | columnFamilyHandleList)) { | |
143 | try { | |
144 | // writing (long)100 under key | |
145 | db.put(columnFamilyHandleList.get(1), | |
146 | "cfkey".getBytes(), longToByteArray(100)); | |
147 | // merge (long)1 under key | |
148 | db.merge(columnFamilyHandleList.get(1), | |
149 | "cfkey".getBytes(), longToByteArray(1)); | |
150 | ||
151 | byte[] value = db.get(columnFamilyHandleList.get(1), | |
152 | "cfkey".getBytes()); | |
153 | long longValue = longFromByteArray(value); | |
154 | assertThat(longValue).isEqualTo(101); | |
155 | } finally { | |
156 | for (final ColumnFamilyHandle handle : columnFamilyHandleList) { | |
157 | handle.close(); | |
158 | } | |
159 | } | |
160 | } | |
161 | } | |
162 | } | |
163 | ||
7c673cae FG |
164 | @Test |
165 | public void operatorOption() | |
166 | throws InterruptedException, RocksDBException { | |
167 | try (final StringAppendOperator stringAppendOperator = new StringAppendOperator(); | |
168 | final Options opt = new Options() | |
169 | .setCreateIfMissing(true) | |
170 | .setMergeOperator(stringAppendOperator); | |
171 | final RocksDB db = RocksDB.open(opt, | |
172 | dbFolder.getRoot().getAbsolutePath())) { | |
173 | // Writing aa under key | |
174 | db.put("key".getBytes(), "aa".getBytes()); | |
175 | ||
176 | // Writing bb under key | |
177 | db.merge("key".getBytes(), "bb".getBytes()); | |
178 | ||
179 | final byte[] value = db.get("key".getBytes()); | |
180 | final String strValue = new String(value); | |
181 | ||
182 | assertThat(strValue).isEqualTo("aa,bb"); | |
183 | } | |
184 | } | |
185 | ||
494da23a TL |
186 | @Test |
187 | public void uint64AddOperatorOption() | |
188 | throws InterruptedException, RocksDBException { | |
189 | try (final UInt64AddOperator uint64AddOperator = new UInt64AddOperator(); | |
190 | final Options opt = new Options() | |
191 | .setCreateIfMissing(true) | |
192 | .setMergeOperator(uint64AddOperator); | |
193 | final RocksDB db = RocksDB.open(opt, | |
194 | dbFolder.getRoot().getAbsolutePath())) { | |
195 | // Writing (long)100 under key | |
196 | db.put("key".getBytes(), longToByteArray(100)); | |
197 | ||
198 | // Writing (long)1 under key | |
199 | db.merge("key".getBytes(), longToByteArray(1)); | |
200 | ||
201 | final byte[] value = db.get("key".getBytes()); | |
202 | final long longValue = longFromByteArray(value); | |
203 | ||
204 | assertThat(longValue).isEqualTo(101); | |
205 | } | |
206 | } | |
207 | ||
7c673cae FG |
208 | @Test |
209 | public void cFOperatorOption() | |
210 | throws InterruptedException, RocksDBException { | |
211 | try (final StringAppendOperator stringAppendOperator = new StringAppendOperator(); | |
212 | final ColumnFamilyOptions cfOpt1 = new ColumnFamilyOptions() | |
213 | .setMergeOperator(stringAppendOperator); | |
214 | final ColumnFamilyOptions cfOpt2 = new ColumnFamilyOptions() | |
215 | .setMergeOperator(stringAppendOperator) | |
216 | ) { | |
217 | final List<ColumnFamilyDescriptor> cfDescriptors = Arrays.asList( | |
218 | new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOpt1), | |
219 | new ColumnFamilyDescriptor("new_cf".getBytes(), cfOpt2) | |
220 | ); | |
221 | final List<ColumnFamilyHandle> columnFamilyHandleList = new ArrayList<>(); | |
222 | try (final DBOptions opt = new DBOptions() | |
223 | .setCreateIfMissing(true) | |
224 | .setCreateMissingColumnFamilies(true); | |
225 | final RocksDB db = RocksDB.open(opt, | |
226 | dbFolder.getRoot().getAbsolutePath(), cfDescriptors, | |
227 | columnFamilyHandleList) | |
228 | ) { | |
229 | try { | |
230 | // writing aa under key | |
231 | db.put(columnFamilyHandleList.get(1), | |
232 | "cfkey".getBytes(), "aa".getBytes()); | |
233 | // merge bb under key | |
234 | db.merge(columnFamilyHandleList.get(1), | |
235 | "cfkey".getBytes(), "bb".getBytes()); | |
236 | byte[] value = db.get(columnFamilyHandleList.get(1), | |
237 | "cfkey".getBytes()); | |
238 | String strValue = new String(value); | |
239 | ||
240 | // Test also with createColumnFamily | |
241 | try (final ColumnFamilyOptions cfHandleOpts = | |
242 | new ColumnFamilyOptions() | |
243 | .setMergeOperator(stringAppendOperator); | |
244 | final ColumnFamilyHandle cfHandle = | |
245 | db.createColumnFamily( | |
246 | new ColumnFamilyDescriptor("new_cf2".getBytes(), | |
247 | cfHandleOpts)) | |
248 | ) { | |
249 | // writing xx under cfkey2 | |
250 | db.put(cfHandle, "cfkey2".getBytes(), "xx".getBytes()); | |
251 | // merge yy under cfkey2 | |
252 | db.merge(cfHandle, new WriteOptions(), "cfkey2".getBytes(), | |
253 | "yy".getBytes()); | |
254 | value = db.get(cfHandle, "cfkey2".getBytes()); | |
255 | String strValueTmpCf = new String(value); | |
256 | ||
257 | assertThat(strValue).isEqualTo("aa,bb"); | |
258 | assertThat(strValueTmpCf).isEqualTo("xx,yy"); | |
259 | } | |
260 | } finally { | |
261 | for (final ColumnFamilyHandle columnFamilyHandle : | |
262 | columnFamilyHandleList) { | |
263 | columnFamilyHandle.close(); | |
264 | } | |
265 | } | |
266 | } | |
267 | } | |
268 | } | |
269 | ||
494da23a TL |
270 | @Test |
271 | public void cFUInt64AddOperatorOption() | |
272 | throws InterruptedException, RocksDBException { | |
273 | try (final UInt64AddOperator uint64AddOperator = new UInt64AddOperator(); | |
274 | final ColumnFamilyOptions cfOpt1 = new ColumnFamilyOptions() | |
275 | .setMergeOperator(uint64AddOperator); | |
276 | final ColumnFamilyOptions cfOpt2 = new ColumnFamilyOptions() | |
277 | .setMergeOperator(uint64AddOperator) | |
278 | ) { | |
279 | final List<ColumnFamilyDescriptor> cfDescriptors = Arrays.asList( | |
280 | new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOpt1), | |
281 | new ColumnFamilyDescriptor("new_cf".getBytes(), cfOpt2) | |
282 | ); | |
283 | final List<ColumnFamilyHandle> columnFamilyHandleList = new ArrayList<>(); | |
284 | try (final DBOptions opt = new DBOptions() | |
285 | .setCreateIfMissing(true) | |
286 | .setCreateMissingColumnFamilies(true); | |
287 | final RocksDB db = RocksDB.open(opt, | |
288 | dbFolder.getRoot().getAbsolutePath(), cfDescriptors, | |
289 | columnFamilyHandleList) | |
290 | ) { | |
291 | try { | |
292 | // writing (long)100 under key | |
293 | db.put(columnFamilyHandleList.get(1), | |
294 | "cfkey".getBytes(), longToByteArray(100)); | |
295 | // merge (long)1 under key | |
296 | db.merge(columnFamilyHandleList.get(1), | |
297 | "cfkey".getBytes(), longToByteArray(1)); | |
298 | byte[] value = db.get(columnFamilyHandleList.get(1), | |
299 | "cfkey".getBytes()); | |
300 | long longValue = longFromByteArray(value); | |
301 | ||
302 | // Test also with createColumnFamily | |
303 | try (final ColumnFamilyOptions cfHandleOpts = | |
304 | new ColumnFamilyOptions() | |
305 | .setMergeOperator(uint64AddOperator); | |
306 | final ColumnFamilyHandle cfHandle = | |
307 | db.createColumnFamily( | |
308 | new ColumnFamilyDescriptor("new_cf2".getBytes(), | |
309 | cfHandleOpts)) | |
310 | ) { | |
311 | // writing (long)200 under cfkey2 | |
312 | db.put(cfHandle, "cfkey2".getBytes(), longToByteArray(200)); | |
313 | // merge (long)50 under cfkey2 | |
314 | db.merge(cfHandle, new WriteOptions(), "cfkey2".getBytes(), | |
315 | longToByteArray(50)); | |
316 | value = db.get(cfHandle, "cfkey2".getBytes()); | |
317 | long longValueTmpCf = longFromByteArray(value); | |
318 | ||
319 | assertThat(longValue).isEqualTo(101); | |
320 | assertThat(longValueTmpCf).isEqualTo(250); | |
321 | } | |
322 | } finally { | |
323 | for (final ColumnFamilyHandle columnFamilyHandle : | |
324 | columnFamilyHandleList) { | |
325 | columnFamilyHandle.close(); | |
326 | } | |
327 | } | |
328 | } | |
329 | } | |
330 | } | |
331 | ||
7c673cae FG |
332 | @Test |
333 | public void operatorGcBehaviour() | |
334 | throws RocksDBException { | |
335 | try (final StringAppendOperator stringAppendOperator = new StringAppendOperator()) { | |
336 | try (final Options opt = new Options() | |
337 | .setCreateIfMissing(true) | |
338 | .setMergeOperator(stringAppendOperator); | |
339 | final RocksDB db = RocksDB.open(opt, | |
340 | dbFolder.getRoot().getAbsolutePath())) { | |
341 | //no-op | |
342 | } | |
343 | ||
7c673cae FG |
344 | // test reuse |
345 | try (final Options opt = new Options() | |
346 | .setMergeOperator(stringAppendOperator); | |
347 | final RocksDB db = RocksDB.open(opt, | |
348 | dbFolder.getRoot().getAbsolutePath())) { | |
349 | //no-op | |
350 | } | |
351 | ||
352 | // test param init | |
353 | try (final StringAppendOperator stringAppendOperator2 = new StringAppendOperator(); | |
354 | final Options opt = new Options() | |
355 | .setMergeOperator(stringAppendOperator2); | |
356 | final RocksDB db = RocksDB.open(opt, | |
357 | dbFolder.getRoot().getAbsolutePath())) { | |
358 | //no-op | |
359 | } | |
360 | ||
361 | // test replace one with another merge operator instance | |
362 | try (final Options opt = new Options() | |
363 | .setMergeOperator(stringAppendOperator); | |
364 | final StringAppendOperator newStringAppendOperator = new StringAppendOperator()) { | |
365 | opt.setMergeOperator(newStringAppendOperator); | |
366 | try (final RocksDB db = RocksDB.open(opt, | |
367 | dbFolder.getRoot().getAbsolutePath())) { | |
368 | //no-op | |
369 | } | |
370 | } | |
371 | } | |
372 | } | |
373 | ||
494da23a TL |
374 | @Test |
375 | public void uint64AddOperatorGcBehaviour() | |
376 | throws RocksDBException { | |
377 | try (final UInt64AddOperator uint64AddOperator = new UInt64AddOperator()) { | |
378 | try (final Options opt = new Options() | |
379 | .setCreateIfMissing(true) | |
380 | .setMergeOperator(uint64AddOperator); | |
381 | final RocksDB db = RocksDB.open(opt, | |
382 | dbFolder.getRoot().getAbsolutePath())) { | |
383 | //no-op | |
384 | } | |
385 | ||
386 | // test reuse | |
387 | try (final Options opt = new Options() | |
388 | .setMergeOperator(uint64AddOperator); | |
389 | final RocksDB db = RocksDB.open(opt, | |
390 | dbFolder.getRoot().getAbsolutePath())) { | |
391 | //no-op | |
392 | } | |
393 | ||
394 | // test param init | |
395 | try (final UInt64AddOperator uint64AddOperator2 = new UInt64AddOperator(); | |
396 | final Options opt = new Options() | |
397 | .setMergeOperator(uint64AddOperator2); | |
398 | final RocksDB db = RocksDB.open(opt, | |
399 | dbFolder.getRoot().getAbsolutePath())) { | |
400 | //no-op | |
401 | } | |
402 | ||
403 | // test replace one with another merge operator instance | |
404 | try (final Options opt = new Options() | |
405 | .setMergeOperator(uint64AddOperator); | |
406 | final UInt64AddOperator newUInt64AddOperator = new UInt64AddOperator()) { | |
407 | opt.setMergeOperator(newUInt64AddOperator); | |
408 | try (final RocksDB db = RocksDB.open(opt, | |
409 | dbFolder.getRoot().getAbsolutePath())) { | |
410 | //no-op | |
411 | } | |
412 | } | |
413 | } | |
414 | } | |
415 | ||
7c673cae FG |
416 | @Test |
417 | public void emptyStringInSetMergeOperatorByName() { | |
418 | try (final Options opt = new Options() | |
419 | .setMergeOperatorName(""); | |
420 | final ColumnFamilyOptions cOpt = new ColumnFamilyOptions() | |
421 | .setMergeOperatorName("")) { | |
422 | //no-op | |
423 | } | |
424 | } | |
425 | ||
426 | @Test(expected = IllegalArgumentException.class) | |
427 | public void nullStringInSetMergeOperatorByNameOptions() { | |
428 | try (final Options opt = new Options()) { | |
429 | opt.setMergeOperatorName(null); | |
430 | } | |
431 | } | |
432 | ||
433 | @Test(expected = IllegalArgumentException.class) | |
434 | public void | |
435 | nullStringInSetMergeOperatorByNameColumnFamilyOptions() { | |
436 | try (final ColumnFamilyOptions opt = new ColumnFamilyOptions()) { | |
437 | opt.setMergeOperatorName(null); | |
438 | } | |
439 | } | |
440 | } |