0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 package org.apache.spark.util.kvstore;
0019
0020 import java.io.File;
0021 import java.util.Arrays;
0022 import java.util.List;
0023 import java.util.NoSuchElementException;
0024 import java.util.stream.Collectors;
0025 import java.util.stream.StreamSupport;
0026
0027 import com.google.common.collect.ImmutableSet;
0028 import org.apache.commons.io.FileUtils;
0029 import org.iq80.leveldb.DBIterator;
0030 import org.junit.After;
0031 import org.junit.Before;
0032 import org.junit.Test;
0033 import static org.junit.Assert.*;
0034
0035 public class LevelDBSuite {
0036
0037 private LevelDB db;
0038 private File dbpath;
0039
0040 @After
0041 public void cleanup() throws Exception {
0042 if (db != null) {
0043 db.close();
0044 }
0045 if (dbpath != null) {
0046 FileUtils.deleteQuietly(dbpath);
0047 }
0048 }
0049
0050 @Before
0051 public void setup() throws Exception {
0052 dbpath = File.createTempFile("test.", ".ldb");
0053 dbpath.delete();
0054 db = new LevelDB(dbpath);
0055 }
0056
0057 @Test
0058 public void testReopenAndVersionCheckDb() throws Exception {
0059 db.close();
0060 db = null;
0061 assertTrue(dbpath.exists());
0062
0063 db = new LevelDB(dbpath);
0064 assertEquals(LevelDB.STORE_VERSION,
0065 db.serializer.deserializeLong(db.db().get(LevelDB.STORE_VERSION_KEY)));
0066 db.db().put(LevelDB.STORE_VERSION_KEY, db.serializer.serialize(LevelDB.STORE_VERSION + 1));
0067 db.close();
0068 db = null;
0069
0070 try {
0071 db = new LevelDB(dbpath);
0072 fail("Should have failed version check.");
0073 } catch (UnsupportedStoreVersionException e) {
0074
0075 }
0076 }
0077
0078 @Test
0079 public void testObjectWriteReadDelete() throws Exception {
0080 CustomType1 t = createCustomType1(1);
0081
0082 try {
0083 db.read(CustomType1.class, t.key);
0084 fail("Expected exception for non-existent object.");
0085 } catch (NoSuchElementException nsee) {
0086
0087 }
0088
0089 db.write(t);
0090 assertEquals(t, db.read(t.getClass(), t.key));
0091 assertEquals(1L, db.count(t.getClass()));
0092
0093 db.delete(t.getClass(), t.key);
0094 try {
0095 db.read(t.getClass(), t.key);
0096 fail("Expected exception for deleted object.");
0097 } catch (NoSuchElementException nsee) {
0098
0099 }
0100
0101
0102
0103 assertEquals(0, countKeys(t.getClass()));
0104 }
0105
0106 @Test
0107 public void testMultipleObjectWriteReadDelete() throws Exception {
0108 CustomType1 t1 = createCustomType1(1);
0109 CustomType1 t2 = createCustomType1(2);
0110 t2.id = t1.id;
0111
0112 db.write(t1);
0113 db.write(t2);
0114
0115 assertEquals(t1, db.read(t1.getClass(), t1.key));
0116 assertEquals(t2, db.read(t2.getClass(), t2.key));
0117 assertEquals(2L, db.count(t1.getClass()));
0118
0119
0120 assertEquals(2, db.count(t1.getClass(), "id", t1.id));
0121
0122
0123
0124 db.delete(t1.getClass(), t1.key);
0125
0126
0127 assertEquals(1, db.count(t2.getClass(), "id", t2.id));
0128
0129
0130 db.delete(t2.getClass(), t2.key);
0131 assertEquals(0, countKeys(t2.getClass()));
0132 }
0133
0134 @Test
0135 public void testMultipleTypesWriteReadDelete() throws Exception {
0136 CustomType1 t1 = createCustomType1(1);
0137
0138 IntKeyType t2 = new IntKeyType();
0139 t2.key = 2;
0140 t2.id = "2";
0141 t2.values = Arrays.asList("value1", "value2");
0142
0143 ArrayKeyIndexType t3 = new ArrayKeyIndexType();
0144 t3.key = new int[] { 42, 84 };
0145 t3.id = new String[] { "id1", "id2" };
0146
0147 db.write(t1);
0148 db.write(t2);
0149 db.write(t3);
0150
0151 assertEquals(t1, db.read(t1.getClass(), t1.key));
0152 assertEquals(t2, db.read(t2.getClass(), t2.key));
0153 assertEquals(t3, db.read(t3.getClass(), t3.key));
0154
0155
0156 assertEquals(1, db.count(t1.getClass(), "id", t1.id));
0157 assertEquals(1, db.count(t2.getClass(), "id", t2.id));
0158 assertEquals(1, db.count(t3.getClass(), "id", t3.id));
0159
0160
0161 db.delete(t1.getClass(), t1.key);
0162 assertEquals(0, countKeys(t1.getClass()));
0163 assertEquals(1, db.count(t2.getClass(), "id", t2.id));
0164 assertEquals(1, db.count(t3.getClass(), "id", t3.id));
0165
0166
0167 db.delete(t2.getClass(), t2.key);
0168 assertEquals(0, countKeys(t2.getClass()));
0169
0170 db.delete(t3.getClass(), t3.key);
0171 assertEquals(0, countKeys(t3.getClass()));
0172 }
0173
0174 @Test
0175 public void testMetadata() throws Exception {
0176 assertNull(db.getMetadata(CustomType1.class));
0177
0178 CustomType1 t = createCustomType1(1);
0179
0180 db.setMetadata(t);
0181 assertEquals(t, db.getMetadata(CustomType1.class));
0182
0183 db.setMetadata(null);
0184 assertNull(db.getMetadata(CustomType1.class));
0185 }
0186
0187 @Test
0188 public void testUpdate() throws Exception {
0189 CustomType1 t = createCustomType1(1);
0190
0191 db.write(t);
0192
0193 t.name = "anotherName";
0194
0195 db.write(t);
0196
0197 assertEquals(1, db.count(t.getClass()));
0198 assertEquals(1, db.count(t.getClass(), "name", "anotherName"));
0199 assertEquals(0, db.count(t.getClass(), "name", "name"));
0200 }
0201
0202 @Test
0203 public void testRemoveAll() throws Exception {
0204 for (int i = 0; i < 2; i++) {
0205 for (int j = 0; j < 2; j++) {
0206 ArrayKeyIndexType o = new ArrayKeyIndexType();
0207 o.key = new int[] { i, j, 0 };
0208 o.id = new String[] { "things" };
0209 db.write(o);
0210
0211 o = new ArrayKeyIndexType();
0212 o.key = new int[] { i, j, 1 };
0213 o.id = new String[] { "more things" };
0214 db.write(o);
0215 }
0216 }
0217
0218 ArrayKeyIndexType o = new ArrayKeyIndexType();
0219 o.key = new int[] { 2, 2, 2 };
0220 o.id = new String[] { "things" };
0221 db.write(o);
0222
0223 assertEquals(9, db.count(ArrayKeyIndexType.class));
0224
0225 db.removeAllByIndexValues(
0226 ArrayKeyIndexType.class,
0227 KVIndex.NATURAL_INDEX_NAME,
0228 ImmutableSet.of(new int[] {0, 0, 0}, new int[] { 2, 2, 2 }));
0229 assertEquals(7, db.count(ArrayKeyIndexType.class));
0230
0231 db.removeAllByIndexValues(
0232 ArrayKeyIndexType.class,
0233 "id",
0234 ImmutableSet.of(new String[] { "things" }));
0235 assertEquals(4, db.count(ArrayKeyIndexType.class));
0236
0237 db.removeAllByIndexValues(
0238 ArrayKeyIndexType.class,
0239 "id",
0240 ImmutableSet.of(new String[] { "more things" }));
0241 assertEquals(0, db.count(ArrayKeyIndexType.class));
0242 }
0243
0244 @Test
0245 public void testSkip() throws Exception {
0246 for (int i = 0; i < 10; i++) {
0247 db.write(createCustomType1(i));
0248 }
0249
0250 KVStoreIterator<CustomType1> it = db.view(CustomType1.class).closeableIterator();
0251 assertTrue(it.hasNext());
0252 assertTrue(it.skip(5));
0253 assertEquals("key5", it.next().key);
0254 assertTrue(it.skip(3));
0255 assertEquals("key9", it.next().key);
0256 assertFalse(it.hasNext());
0257 }
0258
0259 @Test
0260 public void testNegativeIndexValues() throws Exception {
0261 List<Integer> expected = Arrays.asList(-100, -50, 0, 50, 100);
0262
0263 expected.forEach(i -> {
0264 try {
0265 db.write(createCustomType1(i));
0266 } catch (Exception e) {
0267 throw new RuntimeException(e);
0268 }
0269 });
0270
0271 List<Integer> results = StreamSupport
0272 .stream(db.view(CustomType1.class).index("int").spliterator(), false)
0273 .map(e -> e.num)
0274 .collect(Collectors.toList());
0275
0276 assertEquals(expected, results);
0277 }
0278
0279 private CustomType1 createCustomType1(int i) {
0280 CustomType1 t = new CustomType1();
0281 t.key = "key" + i;
0282 t.id = "id" + i;
0283 t.name = "name" + i;
0284 t.num = i;
0285 t.child = "child" + i;
0286 return t;
0287 }
0288
0289 private int countKeys(Class<?> type) throws Exception {
0290 byte[] prefix = db.getTypeInfo(type).keyPrefix();
0291 int count = 0;
0292
0293 DBIterator it = db.db().iterator();
0294 it.seek(prefix);
0295
0296 while (it.hasNext()) {
0297 byte[] key = it.next().getKey();
0298 if (LevelDBIterator.startsWith(key, prefix)) {
0299 count++;
0300 }
0301 }
0302
0303 return count;
0304 }
0305
0306 public static class IntKeyType {
0307
0308 @KVIndex
0309 public int key;
0310
0311 @KVIndex("id")
0312 public String id;
0313
0314 public List<String> values;
0315
0316 @Override
0317 public boolean equals(Object o) {
0318 if (o instanceof IntKeyType) {
0319 IntKeyType other = (IntKeyType) o;
0320 return key == other.key && id.equals(other.id) && values.equals(other.values);
0321 }
0322 return false;
0323 }
0324
0325 @Override
0326 public int hashCode() {
0327 return id.hashCode();
0328 }
0329
0330 }
0331
0332 }