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