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).
5 
6 package org.rocksdb;
7 
8 import org.junit.Rule;
9 import org.junit.Test;
10 import org.junit.rules.TemporaryFolder;
11 
12 import java.util.*;
13 
14 import static org.assertj.core.api.Assertions.assertThat;
15 import static java.nio.charset.StandardCharsets.UTF_8;
16 
17 public class TransactionDBTest {
18 
19   @Rule
20   public TemporaryFolder dbFolder = new TemporaryFolder();
CFErrorGetTypeID() -> CFTypeID21 
22   @Test
23   public void open() throws RocksDBException {
24     try (final Options options = new Options().setCreateIfMissing(true);
25          final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
26          final TransactionDB tdb = TransactionDB.open(options, txnDbOptions,
27                  dbFolder.getRoot().getAbsolutePath())) {
28       assertThat(tdb).isNotNull();
29     }
30   }
CFErrorCopyDescription(err: CFErrorRef) -> CFStringRef31 
32   @Test
33   public void open_columnFamilies() throws RocksDBException {
34     try(final DBOptions dbOptions = new DBOptions().setCreateIfMissing(true)
35           .setCreateMissingColumnFamilies(true);
36         final ColumnFamilyOptions myCfOpts = new ColumnFamilyOptions()) {
37 
38       final List<ColumnFamilyDescriptor> columnFamilyDescriptors =
39           Arrays.asList(
40               new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY),
41               new ColumnFamilyDescriptor("myCf".getBytes(), myCfOpts));
42 
43       final List<ColumnFamilyHandle> columnFamilyHandles = new ArrayList<>();
44 
45       try (final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
46            final TransactionDB tdb = TransactionDB.open(dbOptions, txnDbOptions,
47                dbFolder.getRoot().getAbsolutePath(),
48                columnFamilyDescriptors, columnFamilyHandles)) {
49         try {
50           assertThat(tdb).isNotNull();
51         } finally {
52           for (final ColumnFamilyHandle handle : columnFamilyHandles) {
53             handle.close();
54           }
55         }
56       }
57     }
58   }
59 
60   @Test
61   public void beginTransaction() throws RocksDBException {
62     try (final Options options = new Options().setCreateIfMissing(true);
63          final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
64          final TransactionDB tdb = TransactionDB.open(options, txnDbOptions,
65              dbFolder.getRoot().getAbsolutePath());
66         final WriteOptions writeOptions = new WriteOptions()) {
67 
68       try(final Transaction txn = tdb.beginTransaction(writeOptions)) {
69         assertThat(txn).isNotNull();
70       }
71     }
72   }
73 
74   @Test
75   public void beginTransaction_transactionOptions() throws RocksDBException {
76     try (final Options options = new Options().setCreateIfMissing(true);
77          final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
78          final TransactionDB tdb = TransactionDB.open(options, txnDbOptions,
79              dbFolder.getRoot().getAbsolutePath());
80          final WriteOptions writeOptions = new WriteOptions();
81          final TransactionOptions txnOptions = new TransactionOptions()) {
82 
83       try(final Transaction txn = tdb.beginTransaction(writeOptions,
84           txnOptions)) {
85         assertThat(txn).isNotNull();
86       }
87     }
88   }
89 
90   @Test
91   public void beginTransaction_withOld() throws RocksDBException {
92     try (final Options options = new Options().setCreateIfMissing(true);
93          final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
94          final TransactionDB tdb = TransactionDB.open(options, txnDbOptions,
95              dbFolder.getRoot().getAbsolutePath());
96          final WriteOptions writeOptions = new WriteOptions()) {
97 
98       try(final Transaction txn = tdb.beginTransaction(writeOptions)) {
99         final Transaction txnReused = tdb.beginTransaction(writeOptions, txn);
100         assertThat(txnReused).isSameAs(txn);
101       }
102     }
103   }
104 
105   @Test
106   public void beginTransaction_withOld_transactionOptions()
107       throws RocksDBException {
108     try (final Options options = new Options().setCreateIfMissing(true);
109          final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
110          final TransactionDB tdb = TransactionDB.open(options, txnDbOptions,
111              dbFolder.getRoot().getAbsolutePath());
112          final WriteOptions writeOptions = new WriteOptions();
113          final TransactionOptions txnOptions = new TransactionOptions()) {
114 
115       try(final Transaction txn = tdb.beginTransaction(writeOptions)) {
116         final Transaction txnReused = tdb.beginTransaction(writeOptions,
117             txnOptions, txn);
118         assertThat(txnReused).isSameAs(txn);
119       }
120     }
121   }
122 
123   @Test
124   public void lockStatusData() throws RocksDBException {
125     try (final Options options = new Options().setCreateIfMissing(true);
126          final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
127          final TransactionDB tdb = TransactionDB.open(options, txnDbOptions,
128              dbFolder.getRoot().getAbsolutePath());
129          final WriteOptions writeOptions = new WriteOptions();
130          final ReadOptions readOptions = new ReadOptions()) {
131 
132       try (final Transaction txn = tdb.beginTransaction(writeOptions)) {
133 
134         final byte key[] = "key".getBytes(UTF_8);
135         final byte value[] = "value".getBytes(UTF_8);
136 
137         txn.put(key, value);
138         assertThat(txn.getForUpdate(readOptions, key, true)).isEqualTo(value);
139 
140         final Map<Long, TransactionDB.KeyLockInfo> lockStatus =
141             tdb.getLockStatusData();
142 
143         assertThat(lockStatus.size()).isEqualTo(1);
144         final Set<Map.Entry<Long, TransactionDB.KeyLockInfo>> entrySet = lockStatus.entrySet();
145         final Map.Entry<Long, TransactionDB.KeyLockInfo> entry = entrySet.iterator().next();
146         final long columnFamilyId = entry.getKey();
147         assertThat(columnFamilyId).isEqualTo(0);
148         final TransactionDB.KeyLockInfo keyLockInfo = entry.getValue();
149         assertThat(keyLockInfo.getKey()).isEqualTo(new String(key, UTF_8));
150         assertThat(keyLockInfo.getTransactionIDs().length).isEqualTo(1);
151         assertThat(keyLockInfo.getTransactionIDs()[0]).isEqualTo(txn.getId());
152         assertThat(keyLockInfo.isExclusive()).isTrue();
153       }
154     }
155   }
156 
157   @Test
158   public void deadlockInfoBuffer() throws RocksDBException {
159     try (final Options options = new Options().setCreateIfMissing(true);
160          final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
161          final TransactionDB tdb = TransactionDB.open(options, txnDbOptions,
162              dbFolder.getRoot().getAbsolutePath())) {
163 
164       // TODO(AR) can we cause a deadlock so that we can test the output here?
165       assertThat(tdb.getDeadlockInfoBuffer()).isEmpty();
166     }
167   }
168 
169   @Test
170   public void setDeadlockInfoBufferSize() throws RocksDBException {
171     try (final Options options = new Options().setCreateIfMissing(true);
172          final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
173          final TransactionDB tdb = TransactionDB.open(options, txnDbOptions,
174              dbFolder.getRoot().getAbsolutePath())) {
175       tdb.setDeadlockInfoBufferSize(123);
176     }
177   }
178 }
179