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 static org.assertj.core.api.Assertions.assertThat;
13 
14 public class SnapshotTest {
15 
16   @ClassRule
17   public static final RocksNativeLibraryResource ROCKS_NATIVE_LIBRARY_RESOURCE =
18       new RocksNativeLibraryResource();
19 
20   @Rule
21   public TemporaryFolder dbFolder = new TemporaryFolder();
22 
23   @Test
snapshots()24   public void snapshots() throws RocksDBException {
25     try (final Options options = new Options().setCreateIfMissing(true);
26          final RocksDB db = RocksDB.open(options,
27              dbFolder.getRoot().getAbsolutePath())) {
28       db.put("key".getBytes(), "value".getBytes());
29       // Get new Snapshot of database
30       try (final Snapshot snapshot = db.getSnapshot()) {
31         assertThat(snapshot.getSequenceNumber()).isGreaterThan(0);
32         assertThat(snapshot.getSequenceNumber()).isEqualTo(1);
33         try (final ReadOptions readOptions = new ReadOptions()) {
34           // set snapshot in ReadOptions
35           readOptions.setSnapshot(snapshot);
36 
37           // retrieve key value pair
38           assertThat(new String(db.get("key".getBytes()))).
39               isEqualTo("value");
40           // retrieve key value pair created before
41           // the snapshot was made
42           assertThat(new String(db.get(readOptions,
43               "key".getBytes()))).isEqualTo("value");
44           // add new key/value pair
45           db.put("newkey".getBytes(), "newvalue".getBytes());
46           // using no snapshot the latest db entries
47           // will be taken into account
48           assertThat(new String(db.get("newkey".getBytes()))).
49               isEqualTo("newvalue");
50           // snapshopot was created before newkey
51           assertThat(db.get(readOptions, "newkey".getBytes())).
52               isNull();
53           // Retrieve snapshot from read options
54           try (final Snapshot sameSnapshot = readOptions.snapshot()) {
55             readOptions.setSnapshot(sameSnapshot);
56             // results must be the same with new Snapshot
57             // instance using the same native pointer
58             assertThat(new String(db.get(readOptions,
59                 "key".getBytes()))).isEqualTo("value");
60             // update key value pair to newvalue
61             db.put("key".getBytes(), "newvalue".getBytes());
62             // read with previously created snapshot will
63             // read previous version of key value pair
64             assertThat(new String(db.get(readOptions,
65                 "key".getBytes()))).isEqualTo("value");
66             // read for newkey using the snapshot must be
67             // null
68             assertThat(db.get(readOptions, "newkey".getBytes())).
69                 isNull();
70             // setting null to snapshot in ReadOptions leads
71             // to no Snapshot being used.
72             readOptions.setSnapshot(null);
73             assertThat(new String(db.get(readOptions,
74                 "newkey".getBytes()))).isEqualTo("newvalue");
75             // release Snapshot
76             db.releaseSnapshot(snapshot);
77           }
78         }
79       }
80     }
81   }
82 
83   @Test
iteratorWithSnapshot()84   public void iteratorWithSnapshot() throws RocksDBException {
85     try (final Options options = new Options().setCreateIfMissing(true);
86          final RocksDB db = RocksDB.open(options,
87              dbFolder.getRoot().getAbsolutePath())) {
88       db.put("key".getBytes(), "value".getBytes());
89 
90       // Get new Snapshot of database
91       // set snapshot in ReadOptions
92       try (final Snapshot snapshot = db.getSnapshot();
93            final ReadOptions readOptions =
94                new ReadOptions().setSnapshot(snapshot)) {
95         db.put("key2".getBytes(), "value2".getBytes());
96 
97         // iterate over current state of db
98         try (final RocksIterator iterator = db.newIterator()) {
99           iterator.seekToFirst();
100           assertThat(iterator.isValid()).isTrue();
101           assertThat(iterator.key()).isEqualTo("key".getBytes());
102           iterator.next();
103           assertThat(iterator.isValid()).isTrue();
104           assertThat(iterator.key()).isEqualTo("key2".getBytes());
105           iterator.next();
106           assertThat(iterator.isValid()).isFalse();
107         }
108 
109         // iterate using a snapshot
110         try (final RocksIterator snapshotIterator =
111                  db.newIterator(readOptions)) {
112           snapshotIterator.seekToFirst();
113           assertThat(snapshotIterator.isValid()).isTrue();
114           assertThat(snapshotIterator.key()).isEqualTo("key".getBytes());
115           snapshotIterator.next();
116           assertThat(snapshotIterator.isValid()).isFalse();
117         }
118 
119         // release Snapshot
120         db.releaseSnapshot(snapshot);
121       }
122     }
123   }
124 
125   @Test
iteratorWithSnapshotOnColumnFamily()126   public void iteratorWithSnapshotOnColumnFamily() throws RocksDBException {
127     try (final Options options = new Options()
128         .setCreateIfMissing(true);
129          final RocksDB db = RocksDB.open(options,
130              dbFolder.getRoot().getAbsolutePath())) {
131 
132       db.put("key".getBytes(), "value".getBytes());
133 
134       // Get new Snapshot of database
135       // set snapshot in ReadOptions
136       try (final Snapshot snapshot = db.getSnapshot();
137            final ReadOptions readOptions = new ReadOptions()
138                .setSnapshot(snapshot)) {
139         db.put("key2".getBytes(), "value2".getBytes());
140 
141         // iterate over current state of column family
142         try (final RocksIterator iterator = db.newIterator(
143             db.getDefaultColumnFamily())) {
144           iterator.seekToFirst();
145           assertThat(iterator.isValid()).isTrue();
146           assertThat(iterator.key()).isEqualTo("key".getBytes());
147           iterator.next();
148           assertThat(iterator.isValid()).isTrue();
149           assertThat(iterator.key()).isEqualTo("key2".getBytes());
150           iterator.next();
151           assertThat(iterator.isValid()).isFalse();
152         }
153 
154         // iterate using a snapshot on default column family
155         try (final RocksIterator snapshotIterator = db.newIterator(
156             db.getDefaultColumnFamily(), readOptions)) {
157           snapshotIterator.seekToFirst();
158           assertThat(snapshotIterator.isValid()).isTrue();
159           assertThat(snapshotIterator.key()).isEqualTo("key".getBytes());
160           snapshotIterator.next();
161           assertThat(snapshotIterator.isValid()).isFalse();
162 
163           // release Snapshot
164           db.releaseSnapshot(snapshot);
165         }
166       }
167     }
168   }
169 }
170