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 package org.rocksdb;
6 
7 import org.junit.ClassRule;
8 import org.junit.Rule;
9 import org.junit.Test;
10 import org.junit.rules.TemporaryFolder;
11 
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.List;
15 
16 import static org.assertj.core.api.Assertions.assertThat;
17 
18 public class ReadOnlyTest {
19 
20   @ClassRule
21   public static final RocksNativeLibraryResource ROCKS_NATIVE_LIBRARY_RESOURCE =
22       new RocksNativeLibraryResource();
23 
24   @Rule
25   public TemporaryFolder dbFolder = new TemporaryFolder();
26 
27   @Test
readOnlyOpen()28   public void readOnlyOpen() throws RocksDBException {
29     try (final Options options = new Options()
30         .setCreateIfMissing(true);
31          final RocksDB db = RocksDB.open(options,
32              dbFolder.getRoot().getAbsolutePath())) {
33       db.put("key".getBytes(), "value".getBytes());
34       try (final RocksDB db2 = RocksDB.openReadOnly(
35           dbFolder.getRoot().getAbsolutePath())) {
36         assertThat("value").
37             isEqualTo(new String(db2.get("key".getBytes())));
38       }
39     }
40 
41     try (final ColumnFamilyOptions cfOpts = new ColumnFamilyOptions()) {
42       final List<ColumnFamilyDescriptor> cfDescriptors = new ArrayList<>();
43       cfDescriptors.add(new ColumnFamilyDescriptor(
44           RocksDB.DEFAULT_COLUMN_FAMILY, cfOpts));
45 
46       final List<ColumnFamilyHandle> columnFamilyHandleList = new ArrayList<>();
47       try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath(),
48           cfDescriptors, columnFamilyHandleList)) {
49         try (final ColumnFamilyOptions newCfOpts = new ColumnFamilyOptions();
50              final ColumnFamilyOptions newCf2Opts = new ColumnFamilyOptions()
51         ) {
52           columnFamilyHandleList.add(db.createColumnFamily(
53               new ColumnFamilyDescriptor("new_cf".getBytes(), newCfOpts)));
54           columnFamilyHandleList.add(db.createColumnFamily(
55               new ColumnFamilyDescriptor("new_cf2".getBytes(), newCf2Opts)));
56           db.put(columnFamilyHandleList.get(2), "key2".getBytes(),
57               "value2".getBytes());
58 
59           final List<ColumnFamilyHandle> readOnlyColumnFamilyHandleList =
60               new ArrayList<>();
61           try (final RocksDB db2 = RocksDB.openReadOnly(
62               dbFolder.getRoot().getAbsolutePath(), cfDescriptors,
63               readOnlyColumnFamilyHandleList)) {
64             try (final ColumnFamilyOptions newCfOpts2 =
65                      new ColumnFamilyOptions();
66                  final ColumnFamilyOptions newCf2Opts2 =
67                      new ColumnFamilyOptions()
68             ) {
69               assertThat(db2.get("key2".getBytes())).isNull();
70               assertThat(db2.get(readOnlyColumnFamilyHandleList.get(0),
71                   "key2".getBytes())).
72                   isNull();
73               cfDescriptors.clear();
74               cfDescriptors.add(
75                   new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY,
76                       newCfOpts2));
77               cfDescriptors.add(new ColumnFamilyDescriptor("new_cf2".getBytes(),
78                       newCf2Opts2));
79 
80               final List<ColumnFamilyHandle> readOnlyColumnFamilyHandleList2
81                   = new ArrayList<>();
82               try (final RocksDB db3 = RocksDB.openReadOnly(
83                   dbFolder.getRoot().getAbsolutePath(), cfDescriptors,
84                   readOnlyColumnFamilyHandleList2)) {
85                 try {
86                   assertThat(new String(db3.get(
87                       readOnlyColumnFamilyHandleList2.get(1),
88                       "key2".getBytes()))).isEqualTo("value2");
89                 } finally {
90                   for (final ColumnFamilyHandle columnFamilyHandle :
91                       readOnlyColumnFamilyHandleList2) {
92                     columnFamilyHandle.close();
93                   }
94                 }
95               }
96             } finally {
97               for (final ColumnFamilyHandle columnFamilyHandle :
98                   readOnlyColumnFamilyHandleList) {
99                 columnFamilyHandle.close();
100               }
101             }
102           }
103         } finally {
104           for (final ColumnFamilyHandle columnFamilyHandle :
105               columnFamilyHandleList) {
106             columnFamilyHandle.close();
107           }
108         }
109       }
110     }
111   }
112 
113   @Test(expected = RocksDBException.class)
failToWriteInReadOnly()114   public void failToWriteInReadOnly() throws RocksDBException {
115     try (final Options options = new Options()
116         .setCreateIfMissing(true)) {
117 
118       try (final RocksDB db = RocksDB.open(options,
119           dbFolder.getRoot().getAbsolutePath())) {
120         //no-op
121       }
122     }
123 
124     try (final ColumnFamilyOptions cfOpts = new ColumnFamilyOptions()) {
125       final List<ColumnFamilyDescriptor> cfDescriptors = Arrays.asList(
126           new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOpts)
127       );
128 
129       final List<ColumnFamilyHandle> readOnlyColumnFamilyHandleList =
130           new ArrayList<>();
131       try (final RocksDB rDb = RocksDB.openReadOnly(
132           dbFolder.getRoot().getAbsolutePath(), cfDescriptors,
133           readOnlyColumnFamilyHandleList)) {
134         try {
135           // test that put fails in readonly mode
136           rDb.put("key".getBytes(), "value".getBytes());
137         } finally {
138           for (final ColumnFamilyHandle columnFamilyHandle :
139               readOnlyColumnFamilyHandleList) {
140             columnFamilyHandle.close();
141           }
142         }
143       }
144     }
145   }
146 
147   @Test(expected = RocksDBException.class)
failToCFWriteInReadOnly()148   public void failToCFWriteInReadOnly() throws RocksDBException {
149     try (final Options options = new Options().setCreateIfMissing(true);
150          final RocksDB db = RocksDB.open(options,
151              dbFolder.getRoot().getAbsolutePath())) {
152       //no-op
153     }
154 
155     try (final ColumnFamilyOptions cfOpts = new ColumnFamilyOptions()) {
156       final List<ColumnFamilyDescriptor> cfDescriptors = Arrays.asList(
157           new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOpts)
158       );
159       final List<ColumnFamilyHandle> readOnlyColumnFamilyHandleList =
160           new ArrayList<>();
161       try (final RocksDB rDb = RocksDB.openReadOnly(
162           dbFolder.getRoot().getAbsolutePath(), cfDescriptors,
163           readOnlyColumnFamilyHandleList)) {
164         try {
165           rDb.put(readOnlyColumnFamilyHandleList.get(0),
166               "key".getBytes(), "value".getBytes());
167         } finally {
168           for (final ColumnFamilyHandle columnFamilyHandle :
169               readOnlyColumnFamilyHandleList) {
170             columnFamilyHandle.close();
171           }
172         }
173       }
174     }
175   }
176 
177   @Test(expected = RocksDBException.class)
failToRemoveInReadOnly()178   public void failToRemoveInReadOnly() throws RocksDBException {
179     try (final Options options = new Options().setCreateIfMissing(true);
180          final RocksDB db = RocksDB.open(options,
181              dbFolder.getRoot().getAbsolutePath())) {
182       //no-op
183     }
184 
185     try (final ColumnFamilyOptions cfOpts = new ColumnFamilyOptions()) {
186       final List<ColumnFamilyDescriptor> cfDescriptors = Arrays.asList(
187           new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOpts)
188       );
189 
190       final List<ColumnFamilyHandle> readOnlyColumnFamilyHandleList =
191           new ArrayList<>();
192 
193       try (final RocksDB rDb = RocksDB.openReadOnly(
194           dbFolder.getRoot().getAbsolutePath(), cfDescriptors,
195           readOnlyColumnFamilyHandleList)) {
196         try {
197           rDb.delete("key".getBytes());
198         } finally {
199           for (final ColumnFamilyHandle columnFamilyHandle :
200               readOnlyColumnFamilyHandleList) {
201             columnFamilyHandle.close();
202           }
203         }
204       }
205     }
206   }
207 
208   @Test(expected = RocksDBException.class)
failToCFRemoveInReadOnly()209   public void failToCFRemoveInReadOnly() throws RocksDBException {
210     try (final Options options = new Options().setCreateIfMissing(true);
211          final RocksDB db = RocksDB.open(options,
212              dbFolder.getRoot().getAbsolutePath())) {
213       //no-op
214     }
215 
216     try (final ColumnFamilyOptions cfOpts = new ColumnFamilyOptions()) {
217       final List<ColumnFamilyDescriptor> cfDescriptors = Arrays.asList(
218           new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOpts)
219       );
220 
221       final List<ColumnFamilyHandle> readOnlyColumnFamilyHandleList =
222           new ArrayList<>();
223       try (final RocksDB rDb = RocksDB.openReadOnly(
224           dbFolder.getRoot().getAbsolutePath(), cfDescriptors,
225           readOnlyColumnFamilyHandleList)) {
226         try {
227           rDb.delete(readOnlyColumnFamilyHandleList.get(0),
228               "key".getBytes());
229         } finally {
230           for (final ColumnFamilyHandle columnFamilyHandle :
231               readOnlyColumnFamilyHandleList) {
232             columnFamilyHandle.close();
233           }
234         }
235       }
236     }
237   }
238 
239   @Test(expected = RocksDBException.class)
failToWriteBatchReadOnly()240   public void failToWriteBatchReadOnly() throws RocksDBException {
241     try (final Options options = new Options().setCreateIfMissing(true);
242          final RocksDB db = RocksDB.open(options,
243              dbFolder.getRoot().getAbsolutePath())) {
244       //no-op
245     }
246 
247     try (final ColumnFamilyOptions cfOpts = new ColumnFamilyOptions()) {
248       final List<ColumnFamilyDescriptor> cfDescriptors = Arrays.asList(
249           new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOpts)
250       );
251 
252       final List<ColumnFamilyHandle> readOnlyColumnFamilyHandleList =
253           new ArrayList<>();
254       try (final RocksDB rDb = RocksDB.openReadOnly(
255           dbFolder.getRoot().getAbsolutePath(), cfDescriptors,
256           readOnlyColumnFamilyHandleList);
257            final WriteBatch wb = new WriteBatch();
258            final WriteOptions wOpts = new WriteOptions()) {
259         try {
260           wb.put("key".getBytes(), "value".getBytes());
261           rDb.write(wOpts, wb);
262         } finally {
263           for (final ColumnFamilyHandle columnFamilyHandle :
264               readOnlyColumnFamilyHandleList) {
265             columnFamilyHandle.close();
266           }
267         }
268       }
269     }
270   }
271 
272   @Test(expected = RocksDBException.class)
failToCFWriteBatchReadOnly()273   public void failToCFWriteBatchReadOnly() throws RocksDBException {
274     try (final Options options = new Options().setCreateIfMissing(true);
275          final RocksDB db = RocksDB.open(options,
276              dbFolder.getRoot().getAbsolutePath())) {
277       //no-op
278     }
279 
280     try (final ColumnFamilyOptions cfOpts = new ColumnFamilyOptions()) {
281       final List<ColumnFamilyDescriptor> cfDescriptors = Arrays.asList(
282           new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOpts)
283       );
284 
285       final List<ColumnFamilyHandle> readOnlyColumnFamilyHandleList =
286           new ArrayList<>();
287       try (final RocksDB rDb = RocksDB.openReadOnly(
288           dbFolder.getRoot().getAbsolutePath(), cfDescriptors,
289           readOnlyColumnFamilyHandleList);
290            final WriteBatch wb = new WriteBatch();
291            final WriteOptions wOpts = new WriteOptions()) {
292         try {
293           wb.put(readOnlyColumnFamilyHandleList.get(0), "key".getBytes(),
294               "value".getBytes());
295           rDb.write(wOpts, wb);
296         } finally {
297           for (final ColumnFamilyHandle columnFamilyHandle :
298               readOnlyColumnFamilyHandleList) {
299             columnFamilyHandle.close();
300           }
301         }
302       }
303     }
304   }
305 }
306