Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

KeyRangeTest.java

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 2002-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: KeyRangeTest.java,v 12.1 2005/01/31 19:27:35 mark Exp $
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         /* 0 */ {1},
00042         /* 1 */ {FF},
00043         /* 2 */ {FF, 0},
00044         /* 3 */ {FF, 0x7F},
00045         /* 4 */ {FF, FF},
00046         /* 5 */ {FF, FF, 0},
00047         /* 6 */ {FF, FF, 0x7F},
00048         /* 7 */ {FF, FF, FF},
00049     };
00050     private static byte[][] EXTREME_KEY_BYTES = {
00051         /* 0 */ {0},
00052         /* 1 */ {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         /* Ensure that GC can cleanup. */
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         // with empty range
00169 
00170         cursor = new DataCursor(view, false);
00171         expectRange(KEYS, 0, end, reversed);
00172         cursor.close();
00173 
00174         // begin key only, inclusive
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         // begin key only, exclusive
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         // end key only, inclusive
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         // end key only, exclusive
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         // begin and end keys, inclusive and exclusive
00207 
00208         for (int i = 0; i <= end; i++) {
00209             for (int j = i; j <= end; j++) {
00210                 // begin inclusive, end inclusive
00211 
00212                 cursor = newCursor(view, keys[i], true, keys[j],
00213                                         true, reversed);
00214                 expectRange(KEYS, i, j, reversed);
00215                 cursor.close();
00216 
00217                 // begin inclusive, end exclusive
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                 // begin exclusive, end inclusive
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                 // begin exclusive, end exclusive
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         // single key range
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         // start with lower extreme (before any existing key)
00249 
00250         cursor = newCursor(view, extremeKeys[0], true, null, false, reversed);
00251         expectRange(KEYS, 0, end, reversed);
00252         cursor.close();
00253 
00254         // start with higher extreme (after any existing key)
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         // check that moving past ends doesn't move the cursor
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         /* Base range [1, 2] */
00376         begin.setData(new byte[] { 1 });
00377         end.setData(new byte[] { 2 });
00378         range = range.subRange(begin, true, end, true);
00379 
00380         /* Subrange (0, 1] is invalid **. */
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         /* Subrange [1, 3) is invalid. */
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         /* Subrange [2, 2] is valid. */
00397         begin2.setData(new byte[] { 2 });
00398         end2.setData(new byte[] { 2 });
00399         range2 = range.subRange(begin2, true, end2, true);
00400 
00401         /* Subrange [0, 1] is invalid. */
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         /* Subrange (0, 3] is invalid. */
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         /* Subrange [3, 3) is invalid. */
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 }

Generated on Sun Dec 25 12:14:53 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2