1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
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).
10 import java
.util
.ArrayList
;
11 import java
.util
.Arrays
;
12 import java
.util
.List
;
14 import static java
.nio
.charset
.StandardCharsets
.UTF_8
;
15 import static org
.assertj
.core
.api
.Assertions
.assertThat
;
16 import static org
.assertj
.core
.api
.Assertions
.fail
;
18 public class TransactionTest
extends AbstractTransactionTest
{
21 public void getForUpdate_cf_conflict() throws RocksDBException
{
22 final byte k1
[] = "key1".getBytes(UTF_8
);
23 final byte v1
[] = "value1".getBytes(UTF_8
);
24 final byte v12
[] = "value12".getBytes(UTF_8
);
25 try(final DBContainer dbContainer
= startDb();
26 final ReadOptions readOptions
= new ReadOptions()) {
27 final ColumnFamilyHandle testCf
= dbContainer
.getTestColumnFamily();
29 try(final Transaction txn
= dbContainer
.beginTransaction()) {
30 txn
.put(testCf
, k1
, v1
);
31 assertThat(txn
.getForUpdate(readOptions
, testCf
, k1
, true)).isEqualTo(v1
);
35 try(final Transaction txn2
= dbContainer
.beginTransaction()) {
36 try(final Transaction txn3
= dbContainer
.beginTransaction()) {
37 assertThat(txn3
.getForUpdate(readOptions
, testCf
, k1
, true)).isEqualTo(v1
);
39 // NOTE: txn2 updates k1, during txn3
41 txn2
.put(testCf
, k1
, v12
); // should cause an exception!
42 } catch(final RocksDBException e
) {
43 assertThat(e
.getStatus().getCode()).isSameAs(Status
.Code
.TimedOut
);
49 fail("Expected an exception for put after getForUpdate from conflicting" +
55 public void getForUpdate_conflict() throws RocksDBException
{
56 final byte k1
[] = "key1".getBytes(UTF_8
);
57 final byte v1
[] = "value1".getBytes(UTF_8
);
58 final byte v12
[] = "value12".getBytes(UTF_8
);
59 try(final DBContainer dbContainer
= startDb();
60 final ReadOptions readOptions
= new ReadOptions()) {
62 try(final Transaction txn
= dbContainer
.beginTransaction()) {
64 assertThat(txn
.getForUpdate(readOptions
, k1
, true)).isEqualTo(v1
);
68 try(final Transaction txn2
= dbContainer
.beginTransaction()) {
69 try(final Transaction txn3
= dbContainer
.beginTransaction()) {
70 assertThat(txn3
.getForUpdate(readOptions
, k1
, true)).isEqualTo(v1
);
72 // NOTE: txn2 updates k1, during txn3
74 txn2
.put(k1
, v12
); // should cause an exception!
75 } catch(final RocksDBException e
) {
76 assertThat(e
.getStatus().getCode()).isSameAs(Status
.Code
.TimedOut
);
82 fail("Expected an exception for put after getForUpdate from conflicting" +
88 public void multiGetForUpdate_cf_conflict() throws RocksDBException
{
89 final byte keys
[][] = new byte[][] {
90 "key1".getBytes(UTF_8
),
91 "key2".getBytes(UTF_8
)};
92 final byte values
[][] = new byte[][] {
93 "value1".getBytes(UTF_8
),
94 "value2".getBytes(UTF_8
)};
95 final byte[] otherValue
= "otherValue".getBytes(UTF_8
);
97 try(final DBContainer dbContainer
= startDb();
98 final ReadOptions readOptions
= new ReadOptions()) {
99 final ColumnFamilyHandle testCf
= dbContainer
.getTestColumnFamily();
100 final List
<ColumnFamilyHandle
> cfList
= Arrays
.asList(testCf
, testCf
);
102 try(final Transaction txn
= dbContainer
.beginTransaction()) {
103 txn
.put(testCf
, keys
[0], values
[0]);
104 txn
.put(testCf
, keys
[1], values
[1]);
105 assertThat(txn
.multiGet(readOptions
, cfList
, keys
)).isEqualTo(values
);
109 try(final Transaction txn2
= dbContainer
.beginTransaction()) {
110 try(final Transaction txn3
= dbContainer
.beginTransaction()) {
111 assertThat(txn3
.multiGetForUpdate(readOptions
, cfList
, keys
))
114 // NOTE: txn2 updates k1, during txn3
116 txn2
.put(testCf
, keys
[0], otherValue
); // should cause an exception!
117 } catch(final RocksDBException e
) {
118 assertThat(e
.getStatus().getCode()).isSameAs(Status
.Code
.TimedOut
);
124 fail("Expected an exception for put after getForUpdate from conflicting" +
130 public void multiGetForUpdate_conflict() throws RocksDBException
{
131 final byte keys
[][] = new byte[][] {
132 "key1".getBytes(UTF_8
),
133 "key2".getBytes(UTF_8
)};
134 final byte values
[][] = new byte[][] {
135 "value1".getBytes(UTF_8
),
136 "value2".getBytes(UTF_8
)};
137 final byte[] otherValue
= "otherValue".getBytes(UTF_8
);
139 try(final DBContainer dbContainer
= startDb();
140 final ReadOptions readOptions
= new ReadOptions()) {
141 try(final Transaction txn
= dbContainer
.beginTransaction()) {
142 txn
.put(keys
[0], values
[0]);
143 txn
.put(keys
[1], values
[1]);
144 assertThat(txn
.multiGet(readOptions
, keys
)).isEqualTo(values
);
148 try(final Transaction txn2
= dbContainer
.beginTransaction()) {
149 try(final Transaction txn3
= dbContainer
.beginTransaction()) {
150 assertThat(txn3
.multiGetForUpdate(readOptions
, keys
))
153 // NOTE: txn2 updates k1, during txn3
155 txn2
.put(keys
[0], otherValue
); // should cause an exception!
156 } catch(final RocksDBException e
) {
157 assertThat(e
.getStatus().getCode()).isSameAs(Status
.Code
.TimedOut
);
163 fail("Expected an exception for put after getForUpdate from conflicting" +
169 public void name() throws RocksDBException
{
170 try(final DBContainer dbContainer
= startDb();
171 final Transaction txn
= dbContainer
.beginTransaction()) {
172 assertThat(txn
.getName()).isEmpty();
173 final String name
= "my-transaction-" + rand
.nextLong();
175 assertThat(txn
.getName()).isEqualTo(name
);
180 public void ID() throws RocksDBException
{
181 try(final DBContainer dbContainer
= startDb();
182 final Transaction txn
= dbContainer
.beginTransaction()) {
183 assertThat(txn
.getID()).isGreaterThan(0);
188 public void deadlockDetect() throws RocksDBException
{
189 try(final DBContainer dbContainer
= startDb();
190 final Transaction txn
= dbContainer
.beginTransaction()) {
191 assertThat(txn
.isDeadlockDetect()).isFalse();
196 public void waitingTxns() throws RocksDBException
{
197 try(final DBContainer dbContainer
= startDb();
198 final Transaction txn
= dbContainer
.beginTransaction()) {
199 assertThat(txn
.getWaitingTxns().getTransactionIds().length
).isEqualTo(0);
204 public void state() throws RocksDBException
{
205 try(final DBContainer dbContainer
= startDb()) {
207 try(final Transaction txn
= dbContainer
.beginTransaction()) {
208 assertThat(txn
.getState())
209 .isSameAs(Transaction
.TransactionState
.STARTED
);
211 assertThat(txn
.getState())
212 .isSameAs(Transaction
.TransactionState
.COMMITTED
);
215 try(final Transaction txn
= dbContainer
.beginTransaction()) {
216 assertThat(txn
.getState())
217 .isSameAs(Transaction
.TransactionState
.STARTED
);
219 assertThat(txn
.getState())
220 .isSameAs(Transaction
.TransactionState
.STARTED
);
226 public void Id() throws RocksDBException
{
227 try(final DBContainer dbContainer
= startDb();
228 final Transaction txn
= dbContainer
.beginTransaction()) {
229 assertThat(txn
.getId()).isNotNull();
234 public TransactionDBContainer
startDb() throws RocksDBException
{
235 final DBOptions options
= new DBOptions()
236 .setCreateIfMissing(true)
237 .setCreateMissingColumnFamilies(true);
238 final TransactionDBOptions txnDbOptions
= new TransactionDBOptions();
239 final ColumnFamilyOptions columnFamilyOptions
= new ColumnFamilyOptions();
240 final List
<ColumnFamilyDescriptor
> columnFamilyDescriptors
=
242 new ColumnFamilyDescriptor(RocksDB
.DEFAULT_COLUMN_FAMILY
),
243 new ColumnFamilyDescriptor(TXN_TEST_COLUMN_FAMILY
,
244 columnFamilyOptions
));
245 final List
<ColumnFamilyHandle
> columnFamilyHandles
= new ArrayList
<>();
247 final TransactionDB txnDb
;
249 txnDb
= TransactionDB
.open(options
, txnDbOptions
,
250 dbFolder
.getRoot().getAbsolutePath(), columnFamilyDescriptors
,
251 columnFamilyHandles
);
252 } catch(final RocksDBException e
) {
253 columnFamilyOptions
.close();
254 txnDbOptions
.close();
259 final WriteOptions writeOptions
= new WriteOptions();
260 final TransactionOptions txnOptions
= new TransactionOptions();
262 return new TransactionDBContainer(txnOptions
, writeOptions
,
263 columnFamilyHandles
, txnDb
, txnDbOptions
, columnFamilyOptions
, options
);
266 private static class TransactionDBContainer
267 extends DBContainer
{
268 private final TransactionOptions txnOptions
;
269 private final TransactionDB txnDb
;
270 private final TransactionDBOptions txnDbOptions
;
272 public TransactionDBContainer(
273 final TransactionOptions txnOptions
, final WriteOptions writeOptions
,
274 final List
<ColumnFamilyHandle
> columnFamilyHandles
,
275 final TransactionDB txnDb
, final TransactionDBOptions txnDbOptions
,
276 final ColumnFamilyOptions columnFamilyOptions
,
277 final DBOptions options
) {
278 super(writeOptions
, columnFamilyHandles
, columnFamilyOptions
,
280 this.txnOptions
= txnOptions
;
282 this.txnDbOptions
= txnDbOptions
;
286 public Transaction
beginTransaction() {
287 return txnDb
.beginTransaction(writeOptions
, txnOptions
);
291 public Transaction
beginTransaction(final WriteOptions writeOptions
) {
292 return txnDb
.beginTransaction(writeOptions
, txnOptions
);
296 public void close() {
298 writeOptions
.close();
299 for(final ColumnFamilyHandle columnFamilyHandle
: columnFamilyHandles
) {
300 columnFamilyHandle
.close();
303 txnDbOptions
.close();