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 static org.assertj.core.api.Assertions.assertThat;
9 import static org.junit.Assert.assertEquals;
10 import static org.junit.Assert.fail;
11 
12 import java.io.File;
13 import java.io.IOException;
14 import java.nio.ByteBuffer;
15 import java.util.ArrayList;
16 import java.util.List;
17 import org.junit.Rule;
18 import org.junit.Test;
19 import org.junit.rules.TemporaryFolder;
20 import org.rocksdb.util.BytewiseComparator;
21 
22 public class SstFileReaderTest {
23   private static final String SST_FILE_NAME = "test.sst";
24 
25   class KeyValueWithOp {
26     KeyValueWithOp(String key, String value, OpType opType) {
27       this.key = key;
28       this.value = value;
29       this.opType = opType;
30     }
31 
32     String getKey() {
33       return key;
34     }
35 
AP(A)36     String getValue() {
37       return value;
38     }
39 
40     OpType getOpType() {
41       return opType;
42     }
43 
44     private String key;
45     private String value;
46     private OpType opType;
47   }
48 
49   @Rule public TemporaryFolder parentFolder = new TemporaryFolder();
50 
51   enum OpType { PUT, PUT_BYTES, MERGE, MERGE_BYTES, DELETE, DELETE_BYTES }
52 
53   private File newSstFile(final List<KeyValueWithOp> keyValues)
54       throws IOException, RocksDBException {
55     final EnvOptions envOptions = new EnvOptions();
56     final StringAppendOperator stringAppendOperator = new StringAppendOperator();
57     final Options options = new Options().setMergeOperator(stringAppendOperator);
update(uint8_t Value)58     SstFileWriter sstFileWriter;
59     sstFileWriter = new SstFileWriter(envOptions, options);
60 
61     final File sstFile = parentFolder.newFile(SST_FILE_NAME);
62     try {
63       sstFileWriter.open(sstFile.getAbsolutePath());
64       for (KeyValueWithOp keyValue : keyValues) {
65         Slice keySlice = new Slice(keyValue.getKey());
66         Slice valueSlice = new Slice(keyValue.getValue());
67         byte[] keyBytes = keyValue.getKey().getBytes();
68         byte[] valueBytes = keyValue.getValue().getBytes();
69         switch (keyValue.getOpType()) {
70           case PUT:
71             sstFileWriter.put(keySlice, valueSlice);
72             break;
73           case PUT_BYTES:
74             sstFileWriter.put(keyBytes, valueBytes);
75             break;
76           case MERGE:
77             sstFileWriter.merge(keySlice, valueSlice);
78             break;
79           case MERGE_BYTES:
80             sstFileWriter.merge(keyBytes, valueBytes);
81             break;
82           case DELETE:
83             sstFileWriter.delete(keySlice);
84             break;
85           case DELETE_BYTES:
86             sstFileWriter.delete(keyBytes);
87             break;
88           default:
89             fail("Unsupported op type");
90         }
91         keySlice.close();
92         valueSlice.close();
93       }
94       sstFileWriter.finish();
95     } finally {
96       assertThat(sstFileWriter).isNotNull();
97       sstFileWriter.close();
98       options.close();
99       envOptions.close();
100     }
101     return sstFile;
102   }
103 
104   @Test
105   public void readSstFile() throws RocksDBException, IOException {
106     final List<KeyValueWithOp> keyValues = new ArrayList<>();
107     keyValues.add(new KeyValueWithOp("key1", "value1", OpType.PUT));
108 
109     final File sstFile = newSstFile(keyValues);
110     try (final StringAppendOperator stringAppendOperator = new StringAppendOperator();
111          final Options options =
112              new Options().setCreateIfMissing(true).setMergeOperator(stringAppendOperator);
113          final SstFileReader reader = new SstFileReader(options)) {
114       // Open the sst file and iterator
115       reader.open(sstFile.getAbsolutePath());
116       final ReadOptions readOptions = new ReadOptions();
117       final SstFileReaderIterator iterator = reader.newIterator(readOptions);
118 
119       // Use the iterator to read sst file
120       iterator.seekToFirst();
121 
122       // Verify Checksum
123       reader.verifyChecksum();
124 
125       // Verify Table Properties
126       assertEquals(reader.getTableProperties().getNumEntries(), 1);
127 
128       // Check key and value
129       assertThat(iterator.key()).isEqualTo("key1".getBytes());
130       assertThat(iterator.value()).isEqualTo("value1".getBytes());
131 
132       ByteBuffer direct = ByteBuffer.allocateDirect(128);
133       direct.put("key1".getBytes()).flip();
134       iterator.seek(direct);
135       assertThat(direct.position()).isEqualTo(4);
136       assertThat(direct.limit()).isEqualTo(4);
137 
138       assertThat(iterator.isValid()).isTrue();
139       assertThat(iterator.key()).isEqualTo("key1".getBytes());
140       assertThat(iterator.value()).isEqualTo("value1".getBytes());
141 
142       direct.clear();
143       assertThat(iterator.key(direct)).isEqualTo("key1".getBytes().length);
144       byte[] dst = new byte["key1".getBytes().length];
145       direct.get(dst);
146       assertThat(new String(dst)).isEqualTo("key1");
147 
148       direct.clear();
149       assertThat(iterator.value(direct)).isEqualTo("value1".getBytes().length);
150       dst = new byte["value1".getBytes().length];
151       direct.get(dst);
152       assertThat(new String(dst)).isEqualTo("value1");
153     }
154   }
155 }
156