00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 package com.sleepycat.collections;
00011
00012 import java.io.File;
00013 import java.util.Arrays;
00014 import java.util.Comparator;
00015
00016 import junit.framework.Test;
00017 import junit.framework.TestCase;
00018 import junit.framework.TestSuite;
00019
00020 import com.sleepycat.bind.ByteArrayBinding;
00021 import com.sleepycat.collections.test.DbTestUtil;
00022 import com.sleepycat.compat.DbCompat;
00023 import com.sleepycat.db.Database;
00024 import com.sleepycat.db.DatabaseConfig;
00025 import com.sleepycat.db.DatabaseEntry;
00026 import com.sleepycat.db.DatabaseException;
00027 import com.sleepycat.db.Environment;
00028 import com.sleepycat.db.EnvironmentConfig;
00029 import com.sleepycat.db.OperationStatus;
00030
00034 public class KeyRangeTest extends TestCase {
00035
00036 private static boolean VERBOSE = false;
00037
00038 private static final byte FF = (byte) 0xFF;
00039
00040 private static final byte[][] KEYS = {
00041 {1},
00042 {FF},
00043 {FF, 0},
00044 {FF, 0x7F},
00045 {FF, FF},
00046 {FF, FF, 0},
00047 {FF, FF, 0x7F},
00048 {FF, FF, FF},
00049 };
00050 private static byte[][] EXTREME_KEY_BYTES = {
00051 {0},
00052 {FF, FF, FF, FF},
00053 };
00054
00055 private Environment env;
00056 private Database store;
00057 private DataView view;
00058 private DataCursor cursor;
00059
00060 public static void main(String[] args)
00061 throws Exception {
00062
00063 junit.framework.TestResult tr =
00064 junit.textui.TestRunner.run(suite());
00065 if (tr.errorCount() > 0 ||
00066 tr.failureCount() > 0) {
00067 System.exit(1);
00068 } else {
00069 System.exit(0);
00070 }
00071 }
00072
00073 public static Test suite() {
00074
00075 return new TestSuite(KeyRangeTest.class);
00076 }
00077
00078 public KeyRangeTest(String name) {
00079
00080 super(name);
00081 }
00082
00083 public void setUp()
00084 throws Exception {
00085
00086 DbTestUtil.printTestName(DbTestUtil.qualifiedTestName(this));
00087 }
00088
00089 private void openDb(Comparator comparator)
00090 throws Exception {
00091
00092 File dir = DbTestUtil.getNewDir();
00093 ByteArrayBinding dataBinding = new ByteArrayBinding();
00094 EnvironmentConfig envConfig = new EnvironmentConfig();
00095 envConfig.setAllowCreate(true);
00096 DbCompat.setInitializeCache(envConfig, true);
00097 env = new Environment(dir, envConfig);
00098 DatabaseConfig dbConfig = new DatabaseConfig();
00099 DbCompat.setTypeBtree(dbConfig);
00100 dbConfig.setAllowCreate(true);
00101 if (comparator != null) {
00102 DbCompat.setBtreeComparator(dbConfig, comparator);
00103 }
00104 store = DbCompat.openDatabase(env, null, "test.db", null, dbConfig);
00105 view = new DataView(store, dataBinding, dataBinding, null, true, null);
00106 }
00107
00108 private void closeDb()
00109 throws Exception {
00110
00111 store.close();
00112 store = null;
00113 env.close();
00114 env = null;
00115 }
00116
00117 public void tearDown()
00118 throws Exception {
00119
00120 try {
00121 if (store != null) {
00122 store.close();
00123 }
00124 } catch (Exception e) {
00125 System.out.println("Exception ignored during close: " + e);
00126 }
00127 try {
00128 if (env != null) {
00129 env.close();
00130 }
00131 } catch (Exception e) {
00132 System.out.println("Exception ignored during close: " + e);
00133 }
00134
00135 env = null;
00136 store = null;
00137 view = null;
00138 cursor = null;
00139 }
00140
00141 public void testScan() throws Exception {
00142 openDb(null);
00143 doScan(false);
00144 closeDb();
00145 }
00146
00147 public void testScanComparator() throws Exception {
00148 openDb(new ReverseComparator());
00149 doScan(true);
00150 closeDb();
00151 }
00152
00153 private void doScan(boolean reversed) throws Exception {
00154
00155 byte[][] keys = new byte[KEYS.length][];
00156 final int end = KEYS.length - 1;
00157 cursor = new DataCursor(view, true);
00158 for (int i = 0; i <= end; i++) {
00159 keys[i] = KEYS[i];
00160 cursor.put(keys[i], KEYS[i], null, false);
00161 }
00162 cursor.close();
00163 byte[][] extremeKeys = new byte[EXTREME_KEY_BYTES.length][];
00164 for (int i = 0; i < extremeKeys.length; i++) {
00165 extremeKeys[i] = EXTREME_KEY_BYTES[i];
00166 }
00167
00168
00169
00170 cursor = new DataCursor(view, false);
00171 expectRange(KEYS, 0, end, reversed);
00172 cursor.close();
00173
00174
00175
00176 for (int i = 0; i <= end; i++) {
00177 cursor = newCursor(view, keys[i], true, null, false, reversed);
00178 expectRange(KEYS, i, end, reversed);
00179 cursor.close();
00180 }
00181
00182
00183
00184 for (int i = 0; i <= end; i++) {
00185 cursor = newCursor(view, keys[i], false, null, false, reversed);
00186 expectRange(KEYS, i + 1, end, reversed);
00187 cursor.close();
00188 }
00189
00190
00191
00192 for (int i = 0; i <= end; i++) {
00193 cursor = newCursor(view, null, false, keys[i], true, reversed);
00194 expectRange(KEYS, 0, i, reversed);
00195 cursor.close();
00196 }
00197
00198
00199
00200 for (int i = 0; i <= end; i++) {
00201 cursor = newCursor(view, null, false, keys[i], false, reversed);
00202 expectRange(KEYS, 0, i - 1, reversed);
00203 cursor.close();
00204 }
00205
00206
00207
00208 for (int i = 0; i <= end; i++) {
00209 for (int j = i; j <= end; j++) {
00210
00211
00212 cursor = newCursor(view, keys[i], true, keys[j],
00213 true, reversed);
00214 expectRange(KEYS, i, j, reversed);
00215 cursor.close();
00216
00217
00218
00219 cursor = newCursor(view, keys[i], true, keys[j],
00220 false, reversed);
00221 expectRange(KEYS, i, j - 1, reversed);
00222 cursor.close();
00223
00224
00225
00226 cursor = newCursor(view, keys[i], false, keys[j],
00227 true, reversed);
00228 expectRange(KEYS, i + 1, j, reversed);
00229 cursor.close();
00230
00231
00232
00233 cursor = newCursor(view, keys[i], false, keys[j],
00234 false, reversed);
00235 expectRange(KEYS, i + 1, j - 1, reversed);
00236 cursor.close();
00237 }
00238 }
00239
00240
00241
00242 for (int i = 0; i <= end; i++) {
00243 cursor = new DataCursor(view, false, keys[i]);
00244 expectRange(KEYS, i, i, reversed);
00245 cursor.close();
00246 }
00247
00248
00249
00250 cursor = newCursor(view, extremeKeys[0], true, null, false, reversed);
00251 expectRange(KEYS, 0, end, reversed);
00252 cursor.close();
00253
00254
00255
00256 cursor = newCursor(view, null, false, extremeKeys[1], true, reversed);
00257 expectRange(KEYS, 0, end, reversed);
00258 cursor.close();
00259 }
00260
00261 private DataCursor newCursor(DataView view,
00262 Object beginKey, boolean beginInclusive,
00263 Object endKey, boolean endInclusive,
00264 boolean reversed)
00265 throws Exception {
00266
00267 if (reversed) {
00268 return new DataCursor(view, false,
00269 endKey, endInclusive,
00270 beginKey, beginInclusive);
00271 } else {
00272 return new DataCursor(view, false,
00273 beginKey, beginInclusive,
00274 endKey, endInclusive);
00275 }
00276 }
00277
00278 private void expectRange(byte[][] bytes, int first, int last,
00279 boolean reversed)
00280 throws DatabaseException {
00281
00282 int i;
00283 boolean init;
00284 for (init = true, i = first;; i++, init = false) {
00285 if (checkRange(bytes, first, last, i <= last,
00286 reversed, !reversed, init, i)) {
00287 break;
00288 }
00289 }
00290 for (init = true, i = last;; i--, init = false) {
00291 if (checkRange(bytes, first, last, i >= first,
00292 reversed, reversed, init, i)) {
00293 break;
00294 }
00295 }
00296 }
00297
00298 private boolean checkRange(byte[][] bytes, int first, int last,
00299 boolean inRange, boolean reversed,
00300 boolean forward, boolean init,
00301 int i)
00302 throws DatabaseException {
00303
00304 OperationStatus s;
00305 if (forward) {
00306 if (init) {
00307 s = cursor.getFirst(false);
00308 } else {
00309 s = cursor.getNext(false);
00310 }
00311 } else {
00312 if (init) {
00313 s = cursor.getLast(false);
00314 } else {
00315 s = cursor.getPrev(false);
00316 }
00317 }
00318
00319 String msg = " " + (forward ? "next" : "prev") + " i=" + i +
00320 " first=" + first + " last=" + last +
00321 (reversed ? " reversed" : " not reversed");
00322
00323
00324 if (s == OperationStatus.SUCCESS && i == first) {
00325 OperationStatus s2 = reversed ? cursor.getNext(false)
00326 : cursor.getPrev(false);
00327 assertEquals(msg, OperationStatus.NOTFOUND, s2);
00328 }
00329 if (s == OperationStatus.SUCCESS && i == last) {
00330 OperationStatus s2 = reversed ? cursor.getPrev(false)
00331 : cursor.getNext(false);
00332 assertEquals(msg, OperationStatus.NOTFOUND, s2);
00333 }
00334
00335 byte[] val = (s == OperationStatus.SUCCESS)
00336 ? ((byte[]) cursor.getCurrentValue())
00337 : null;
00338
00339 if (inRange) {
00340 assertNotNull("RangeNotFound" + msg, val);
00341
00342 if (!Arrays.equals(val, bytes[i])){
00343 printBytes(val);
00344 printBytes(bytes[i]);
00345 fail("RangeKeyNotEqual" + msg);
00346 }
00347 if (VERBOSE) {
00348 System.out.println("GotRange" + msg);
00349 }
00350 return false;
00351 } else {
00352 assertEquals("RangeExceeded" + msg, OperationStatus.NOTFOUND, s);
00353 return true;
00354 }
00355 }
00356
00357 private void printBytes(byte[] bytes) {
00358
00359 for (int i = 0; i < bytes.length; i += 1) {
00360 System.out.print(Integer.toHexString(bytes[i] & 0xFF));
00361 System.out.print(' ');
00362 }
00363 System.out.println();
00364 }
00365
00366 public void testSubRanges() {
00367
00368 DatabaseEntry begin = new DatabaseEntry();
00369 DatabaseEntry begin2 = new DatabaseEntry();
00370 DatabaseEntry end = new DatabaseEntry();
00371 DatabaseEntry end2 = new DatabaseEntry();
00372 KeyRange range = new KeyRange(null);
00373 KeyRange range2;
00374
00375
00376 begin.setData(new byte[] { 1 });
00377 end.setData(new byte[] { 2 });
00378 range = range.subRange(begin, true, end, true);
00379
00380
00381 begin2.setData(new byte[] { 0 });
00382 end2.setData(new byte[] { 1 });
00383 try {
00384 range2 = range.subRange(begin2, false, end2, true);
00385 fail();
00386 } catch (KeyRangeException expected) {}
00387
00388
00389 begin2.setData(new byte[] { 1 });
00390 end2.setData(new byte[] { 3 });
00391 try {
00392 range2 = range.subRange(begin2, true, end2, false);
00393 fail();
00394 } catch (KeyRangeException expected) {}
00395
00396
00397 begin2.setData(new byte[] { 2 });
00398 end2.setData(new byte[] { 2 });
00399 range2 = range.subRange(begin2, true, end2, true);
00400
00401
00402 begin2.setData(new byte[] { 0 });
00403 end2.setData(new byte[] { 1 });
00404 try {
00405 range2 = range.subRange(begin2, true, end2, true);
00406 fail();
00407 } catch (KeyRangeException expected) {}
00408
00409
00410 begin2.setData(new byte[] { 0 });
00411 end2.setData(new byte[] { 3 });
00412 try {
00413 range2 = range.subRange(begin2, false, end2, true);
00414 fail();
00415 } catch (KeyRangeException expected) {}
00416
00417
00418 begin2.setData(new byte[] { 3 });
00419 end2.setData(new byte[] { 3 });
00420 try {
00421 range2 = range.subRange(begin2, true, end2, false);
00422 fail();
00423 } catch (KeyRangeException expected) {}
00424 }
00425
00426 public static class ReverseComparator implements Comparator {
00427 public int compare(Object o1, Object o2) {
00428 byte[] d1 = (byte[]) o1;
00429 byte[] d2 = (byte[]) o2;
00430 int cmp = KeyRange.compareBytes(d1, 0, d1.length,
00431 d2, 0, d2.length);
00432 if (cmp < 0) {
00433 return 1;
00434 } else if (cmp > 0) {
00435 return -1;
00436 } else {
00437 return 0;
00438 }
00439 }
00440 }
00441 }