KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > je > dbi > DbCursorTestBase


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002,2006 Oracle. All rights reserved.
5  *
6  * $Id: DbCursorTestBase.java,v 1.94 2006/10/30 21:14:43 bostic Exp $
7  */

8
9 package com.sleepycat.je.dbi;
10
11 import java.io.File JavaDoc;
12 import java.io.IOException JavaDoc;
13 import java.util.Comparator JavaDoc;
14 import java.util.Enumeration JavaDoc;
15 import java.util.Hashtable JavaDoc;
16 import java.util.Random JavaDoc;
17
18 import junit.framework.TestCase;
19
20 import com.sleepycat.je.Cursor;
21 import com.sleepycat.je.Database;
22 import com.sleepycat.je.DatabaseConfig;
23 import com.sleepycat.je.DatabaseException;
24 import com.sleepycat.je.DbInternal;
25 import com.sleepycat.je.DbTestProxy;
26 import com.sleepycat.je.Environment;
27 import com.sleepycat.je.EnvironmentConfig;
28 import com.sleepycat.je.LockMode;
29 import com.sleepycat.je.LockStats;
30 import com.sleepycat.je.OperationStatus;
31 import com.sleepycat.je.VerifyConfig;
32 import com.sleepycat.je.config.EnvironmentParams;
33 import com.sleepycat.je.tree.BIN;
34 import com.sleepycat.je.tree.DuplicateEntryException;
35 import com.sleepycat.je.tree.Node;
36 import com.sleepycat.je.tree.Tree;
37 import com.sleepycat.je.util.StringDbt;
38 import com.sleepycat.je.util.TestUtils;
39
40 /**
41  * Various unit tests for CursorImpl.
42  */

43 public class DbCursorTestBase extends TestCase {
44     protected File JavaDoc envHome;
45     protected Cursor cursor;
46     protected Cursor cursor2;
47     protected Database exampleDb;
48     protected Environment exampleEnv;
49     protected Hashtable JavaDoc simpleDataMap;
50     protected Comparator JavaDoc btreeComparisonFunction = null;
51     protected Comparator JavaDoc duplicateComparisonFunction = null;
52     protected StringDbt[] simpleKeys;
53     protected StringDbt[] simpleData;
54     protected boolean duplicatesAllowed;
55
56     protected static final int N_KEY_BYTES = 10;
57     protected static final int N_ITERS = 2;
58     protected static final int N_KEYS = 5000;
59     protected static final int N_TOP_LEVEL_KEYS = 10;
60     protected static final int N_DUPLICATES_PER_KEY = 2500;
61     protected static final int N_COUNT_DUPLICATES_PER_KEY = 500;
62     protected static final int N_COUNT_TOP_KEYS = 1;
63
64     protected static int dbCnt = 0;
65
66     public DbCursorTestBase()
67         throws DatabaseException {
68
69         envHome = new File JavaDoc(System.getProperty(TestUtils.DEST_DIR));
70     }
71
72     public void setUp()
73     throws IOException JavaDoc, DatabaseException {
74
75         TestUtils.removeLogFiles("Setup", envHome, false);
76     }
77
78     protected void initEnv(boolean duplicatesAllowed)
79         throws DatabaseException {
80
81     initEnvInternal(duplicatesAllowed, false);
82     }
83
84     protected void initEnvTransactional(boolean duplicatesAllowed)
85         throws DatabaseException {
86
87     initEnvInternal(duplicatesAllowed, true);
88     }
89
90     private void initEnvInternal(boolean duplicatesAllowed,
91                  boolean transactionalDatabase)
92     throws DatabaseException {
93
94         this.duplicatesAllowed = duplicatesAllowed;
95
96         // Set up sample data
97
int nKeys = simpleKeyStrings.length;
98         simpleKeys = new StringDbt[nKeys];
99         simpleData = new StringDbt[nKeys];
100         for (int i = 0; i < nKeys; i++) {
101             simpleKeys[i] = new StringDbt(simpleKeyStrings[i]);
102             simpleData[i] = new StringDbt(simpleDataStrings[i]);
103         }
104
105         // Set up an environment
106
EnvironmentConfig envConfig = TestUtils.initEnvConfig();
107         envConfig.setTxnNoSync(Boolean.getBoolean(TestUtils.NO_SYNC));
108         envConfig.setTransactional(true);
109         envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(), "6");
110     envConfig.setConfigParam(EnvironmentParams.MAX_MEMORY.getName(),
111                  new Long JavaDoc(1 << 24).toString());
112         envConfig.setAllowCreate(true);
113         exampleEnv = new Environment(envHome, envConfig);
114
115         // Set up a database
116
String JavaDoc databaseName = "simpleDb" + dbCnt++;
117         DatabaseConfig dbConfig = new DatabaseConfig();
118     if (btreeComparisonFunction != null) {
119         dbConfig.setBtreeComparator(btreeComparisonFunction.getClass());
120     }
121     if (duplicateComparisonFunction != null) {
122         dbConfig.setDuplicateComparator
123         (duplicateComparisonFunction.getClass());
124     }
125         dbConfig.setAllowCreate(true);
126         dbConfig.setSortedDuplicates(duplicatesAllowed);
127     dbConfig.setTransactional(transactionalDatabase);
128         exampleDb = exampleEnv.openDatabase(null, databaseName, dbConfig);
129
130         // Set up cursors
131
cursor = exampleDb.openCursor(null, null);
132         cursor2 = exampleDb.openCursor(null, null);
133         simpleDataMap = new Hashtable JavaDoc();
134     }
135
136     public void tearDown()
137     throws IOException JavaDoc, DatabaseException {
138
139     simpleKeys = null;
140     simpleData = null;
141
142     try {
143         if (cursor != null) {
144         cursor.close();
145         cursor = null;
146         }
147     } catch (DatabaseException DBE) {
148         /*
149          * If already closed, well, that's life. Just ignore it.
150          * This is expected because some of the tests in this suite
151          * call tearDown on their own. Rather than add another method
152          * (like Cursor.isClosed()), just catch and ignore the exception.
153          */

154     }
155
156     try {
157         if (cursor2 != null) {
158         cursor2.close();
159         cursor2 = null;
160         }
161     } catch (DatabaseException DBE) {
162         /* Same as above. */
163     }
164
165     if (exampleDb != null) {
166             try {
167                 exampleDb.close();
168             } catch (Throwable JavaDoc e) {
169                 System.out.println("tearDown: " + e);
170             }
171         exampleDb = null;
172     }
173         if (exampleEnv != null) {
174         try {
175         exampleEnv.close();
176         } catch (DatabaseException DE) {
177         /*
178          * Ignore this exception. It's caused by us calling
179          * tearDown() within the test. Each tearDown() call
180          * forces the database closed. So when the call from
181          * junit comes along, it's already closed.
182          */

183         }
184             exampleEnv = null;
185         }
186
187     simpleDataMap = null;
188
189     TestUtils.removeLogFiles("TearDown", envHome, false);
190     }
191
192     protected String JavaDoc[] simpleKeyStrings = {
193     "foo", "bar", "baz", "aaa", "fubar",
194     "foobar", "quux", "mumble", "froboy" };
195
196     protected String JavaDoc[] simpleDataStrings = {
197     "one", "two", "three", "four", "five",
198     "six", "seven", "eight", "nine" };
199
200     protected void doSimpleCursorPuts()
201     throws DatabaseException {
202
203     for (int i = 0; i < simpleKeyStrings.length; i++) {
204         putAndVerifyCursor(cursor, simpleKeys[i], simpleData[i], true);
205         simpleDataMap.put(simpleKeyStrings[i], simpleDataStrings[i]);
206     }
207     }
208
209     /**
210      * A class that performs cursor walking. The walkData method iterates
211      * over all data in the database and calls the "perData()" method on
212      * each data item. The perData() method is expected to be overridden
213      * by the user.
214      */

215     protected class DataWalker {
216     String JavaDoc prevKey = "";
217     String JavaDoc prevData = "";
218     int nEntries = 0;
219     int deletedEntries = 0;
220     int extraVisibleEntries = 0;
221     protected int nHandleEndOfSet = 0;
222     String JavaDoc whenFoundDoInsert;
223     String JavaDoc newKey;
224     String JavaDoc deletedEntry = null;
225     Hashtable JavaDoc dataMap;
226     Hashtable JavaDoc addedDataMap;
227     Random JavaDoc rnd = new Random JavaDoc();
228     /* True if the datamap processing should not happen in the walkData
229        routine. */

230     boolean ignoreDataMap = false;
231
232     DataWalker(Hashtable JavaDoc dataMap) {
233         this.dataMap = dataMap;
234         this.addedDataMap = null;
235     }
236
237     DataWalker(Hashtable JavaDoc dataMap,
238            Hashtable JavaDoc addedDataMap) {
239         this.dataMap = dataMap;
240         this.addedDataMap = addedDataMap;
241     }
242
243     DataWalker() {
244         this.dataMap = simpleDataMap;
245         this.addedDataMap = null;
246     }
247
248     DataWalker(String JavaDoc whenFoundDoInsert,
249            String JavaDoc newKey,
250            Hashtable JavaDoc dataMap) {
251         this.whenFoundDoInsert = whenFoundDoInsert;
252         this.newKey = newKey;
253         this.dataMap = dataMap;
254         this.addedDataMap = null;
255     }
256
257     void setIgnoreDataMap(boolean ignoreDataMap) {
258         this.ignoreDataMap = ignoreDataMap;
259     }
260
261     OperationStatus getFirst(StringDbt foundKey, StringDbt foundData)
262         throws DatabaseException {
263
264         return cursor.getFirst(foundKey, foundData,
265                    LockMode.DEFAULT);
266     }
267
268     OperationStatus getData(StringDbt foundKey, StringDbt foundData)
269         throws DatabaseException {
270
271         return cursor.getNext(foundKey, foundData,
272                   LockMode.DEFAULT);
273     }
274
275     StringDbt foundKey = new StringDbt();
276     StringDbt foundData = new StringDbt();
277
278     void walkData()
279         throws DatabaseException {
280
281         /* get some data back */
282         OperationStatus status = getFirst(foundKey, foundData);
283
284         while (status == OperationStatus.SUCCESS) {
285                 String JavaDoc foundKeyString = foundKey.getString();
286                 String JavaDoc foundDataString = foundData.getString();
287
288         if (!ignoreDataMap) {
289             if (dataMap.get(foundKeyString) != null) {
290             assertTrue(((String JavaDoc) dataMap.get(foundKeyString)).
291                    equals(foundDataString));
292             } else if (addedDataMap != null &&
293                    addedDataMap.get(foundKeyString) != null) {
294             assertTrue(((String JavaDoc) addedDataMap.get(foundKeyString)).
295                    equals(foundDataString));
296             } else {
297             fail("didn't find key in either map (" +
298                  foundKeyString +
299                  ")");
300             }
301         }
302
303                 LockStats stat =
304                     DbTestProxy.dbcGetCursorImpl(cursor).getLockStats();
305                 assertEquals(1, stat.getNReadLocks());
306                 assertEquals(0, stat.getNWriteLocks());
307                 perData(foundKeyString, foundDataString);
308                 nEntries++;
309         status = getData(foundKey, foundData);
310         if (status != OperationStatus.SUCCESS) {
311             nHandleEndOfSet++;
312             status = handleEndOfSet(status);
313         }
314         }
315             TestUtils.validateNodeMemUsage(DbInternal.
316                        envGetEnvironmentImpl(exampleEnv),
317                        false);
318     }
319
320     void perData(String JavaDoc foundKey, String JavaDoc foundData)
321         throws DatabaseException {
322
323         /* to be overridden */
324     }
325
326     OperationStatus handleEndOfSet(OperationStatus status)
327         throws DatabaseException {
328
329         return status;
330     }
331
332     void close()
333         throws DatabaseException {
334
335         cursor.close();
336     }
337     }
338
339     protected class BackwardsDataWalker extends DataWalker {
340     BackwardsDataWalker(Hashtable JavaDoc dataMap) {
341         super(dataMap);
342     }
343
344     BackwardsDataWalker(Hashtable JavaDoc dataMap,
345                 Hashtable JavaDoc addedDataMap) {
346         super(dataMap, addedDataMap);
347     }
348
349     BackwardsDataWalker(String JavaDoc whenFoundDoInsert,
350                 String JavaDoc newKey,
351                 Hashtable JavaDoc dataMap) {
352         super(whenFoundDoInsert, newKey, dataMap);
353     }
354
355     OperationStatus getFirst(StringDbt foundKey, StringDbt foundData)
356         throws DatabaseException {
357
358         return cursor.getLast(foundKey, foundData,
359                   LockMode.DEFAULT);
360     }
361
362     OperationStatus getData(StringDbt foundKey, StringDbt foundData)
363         throws DatabaseException {
364
365         return cursor.getPrev(foundKey, foundData,
366                   LockMode.DEFAULT);
367     }
368     }
369
370     protected class DupDataWalker extends DataWalker {
371     DupDataWalker(Hashtable JavaDoc dataMap) {
372         super(dataMap);
373     }
374
375     DupDataWalker(Hashtable JavaDoc dataMap,
376               Hashtable JavaDoc addedDataMap) {
377         super(dataMap, addedDataMap);
378     }
379
380     DupDataWalker(String JavaDoc whenFoundDoInsert,
381               String JavaDoc newKey,
382               Hashtable JavaDoc dataMap) {
383         super(whenFoundDoInsert, newKey, dataMap);
384     }
385
386     OperationStatus getData(StringDbt foundKey, StringDbt foundData)
387         throws DatabaseException {
388
389         return cursor.getNextDup(foundKey, foundData,
390                      LockMode.DEFAULT);
391     }
392     }
393
394     protected class BackwardsDupDataWalker extends BackwardsDataWalker {
395     BackwardsDupDataWalker(Hashtable JavaDoc dataMap) {
396         super(dataMap);
397     }
398
399     BackwardsDupDataWalker(Hashtable JavaDoc dataMap,
400                    Hashtable JavaDoc addedDataMap) {
401         super(dataMap, addedDataMap);
402     }
403
404     BackwardsDupDataWalker(String JavaDoc whenFoundDoInsert,
405                    String JavaDoc newKey,
406                    Hashtable JavaDoc dataMap) {
407         super(whenFoundDoInsert, newKey, dataMap);
408     }
409
410     OperationStatus getData(StringDbt foundKey, StringDbt foundData)
411         throws DatabaseException {
412
413         return cursor.getPrevDup(foundKey, foundData,
414                      LockMode.DEFAULT);
415     }
416     }
417
418     protected class NoDupDataWalker extends DataWalker {
419     NoDupDataWalker(Hashtable JavaDoc dataMap) {
420         super(dataMap);
421     }
422
423     NoDupDataWalker(Hashtable JavaDoc dataMap,
424             Hashtable JavaDoc addedDataMap) {
425         super(dataMap, addedDataMap);
426     }
427
428     NoDupDataWalker(String JavaDoc whenFoundDoInsert,
429             String JavaDoc newKey,
430             Hashtable JavaDoc dataMap) {
431         super(whenFoundDoInsert, newKey, dataMap);
432     }
433
434     OperationStatus getData(StringDbt foundKey, StringDbt foundData)
435         throws DatabaseException {
436
437         return cursor.getNextNoDup(foundKey, foundData,
438                        LockMode.DEFAULT);
439     }
440     }
441
442     protected class NoDupBackwardsDataWalker extends BackwardsDataWalker {
443     NoDupBackwardsDataWalker(Hashtable JavaDoc dataMap) {
444         super(dataMap);
445     }
446
447     NoDupBackwardsDataWalker(Hashtable JavaDoc dataMap,
448                  Hashtable JavaDoc addedDataMap) {
449         super(dataMap, addedDataMap);
450     }
451
452     NoDupBackwardsDataWalker(String JavaDoc whenFoundDoInsert,
453                  String JavaDoc newKey,
454                  Hashtable JavaDoc dataMap) {
455         super(whenFoundDoInsert, newKey, dataMap);
456     }
457
458     OperationStatus getData(StringDbt foundKey, StringDbt foundData)
459         throws DatabaseException {
460
461         return cursor.getPrevNoDup(foundKey, foundData,
462                        LockMode.DEFAULT);
463     }
464     }
465
466     /**
467      * Construct the next highest key.
468      */

469     protected String JavaDoc nextKey(String JavaDoc key) {
470     byte[] sb = key.getBytes();
471     sb[sb.length - 1]++;
472     return new String JavaDoc(sb);
473     }
474
475     /**
476      * Construct the next lowest key.
477      */

478     protected String JavaDoc prevKey(String JavaDoc key) {
479     byte[] sb = key.getBytes();
480     sb[sb.length - 1]--;
481     return new String JavaDoc(sb);
482     }
483
484     /**
485      * Helper routine for testLargeXXX routines.
486      */

487     protected void doLargePut(Hashtable JavaDoc dataMap, int nKeys)
488     throws DatabaseException {
489
490     for (int i = 0; i < nKeys; i++) {
491         byte[] key = new byte[N_KEY_BYTES];
492         TestUtils.generateRandomAlphaBytes(key);
493         String JavaDoc keyString = new String JavaDoc(key);
494         String JavaDoc dataString = Integer.toString(i);
495         putAndVerifyCursor(cursor, new StringDbt(keyString),
496                                new StringDbt(dataString), true);
497         if (dataMap != null) {
498         dataMap.put(keyString, dataString);
499         }
500     }
501     }
502
503     /**
504      * Helper routine for testLargeXXX routines.
505      */

506     protected void doLargePutPerf(int nKeys)
507     throws DatabaseException {
508
509     byte[][] keys = new byte[nKeys][];
510     for (int i = 0; i < nKeys; i++) {
511         byte[] key = new byte[20];
512         keys[i] = key;
513         TestUtils.generateRandomAlphaBytes(key);
514         String JavaDoc keyString = new String JavaDoc(key);
515         byte[] dataBytes = new byte[120];
516         TestUtils.generateRandomAlphaBytes(dataBytes);
517         String JavaDoc dataString = new String JavaDoc(dataBytes);
518         putAndVerifyCursor(cursor, new StringDbt(keyString),
519                                new StringDbt(dataString), true);
520     }
521     }
522
523     /**
524      * Create some simple duplicate data.
525      */

526     protected void doSimpleDuplicatePuts()
527     throws DatabaseException {
528
529     for (int i = 0; i < simpleKeyStrings.length; i++) {
530         for (int j = 0; j < simpleKeyStrings.length; j++) {
531         putAndVerifyCursor(cursor, simpleKeys[i], simpleData[j], true);
532         }
533     }
534     }
535
536     /**
537      * Create a tree with N_TOP_LEVEL_KEYS keys and N_DUPLICATES_PER_KEY
538      * data items per key.
539      *
540      * @param dataMap A Hashtable of hashtables. This routine adds entries
541      * to the top level hash for each key created. Secondary hashes contain
542      * the duplicate data items for each key in the top level hash.
543      *
544      * @param putVariant a boolean for varying the way the data is put with the
545      * cursor, currently unused..
546      */

547     protected void createRandomDuplicateData(Hashtable JavaDoc dataMap,
548                          boolean putVariant)
549     throws DatabaseException {
550
551         createRandomDuplicateData(N_TOP_LEVEL_KEYS,
552                                   N_DUPLICATES_PER_KEY,
553                                   dataMap,
554                                   putVariant,
555                   false);
556     }
557
558     /**
559      * Create a tree with a given number of keys and nDup
560      * data items per key.
561      *
562      * @param nTopKeys the number of top level keys to create. If negative,
563      * create that number of top level keys with dupes underneath and the
564      * same number of top level keys without any dupes.
565      *
566      * @param nDup The number of duplicates to create in the duplicate subtree.
567      *
568      * @param dataMap A Hashtable of hashtables. This routine adds entries
569      * to the top level hash for each key created. Secondary hashes contain
570      * the duplicate data items for each key in the top level hash.
571      *
572      * @param putVariant a boolean for varying the way the data is put with the
573      * cursor, currently unused..
574      */

575     protected void createRandomDuplicateData(int nTopKeys,
576                                              int nDup,
577                                              Hashtable JavaDoc dataMap,
578                          boolean putVariant,
579                          boolean verifyCount)
580     throws DatabaseException {
581
582     boolean createSomeNonDupes = false;
583     if (nTopKeys < 0) {
584         nTopKeys = Math.abs(nTopKeys);
585         nTopKeys <<= 1;
586         createSomeNonDupes = true;
587     }
588
589         byte[][] keys = new byte[nTopKeys][];
590         for (int i = 0; i < nTopKeys; i++) {
591             byte[] key = new byte[N_KEY_BYTES];
592             keys[i] = key;
593             TestUtils.generateRandomAlphaBytes(key);
594         String JavaDoc keyString = new String JavaDoc(key);
595         Hashtable JavaDoc ht = new Hashtable JavaDoc();
596         if (dataMap != null) {
597         dataMap.put(keyString, ht);
598         }
599         int nDupesThisTime = nDup;
600         if (createSomeNonDupes && (i % 2) == 0) {
601         nDupesThisTime = 1;
602         }
603         for (int j = 1; j <= nDupesThisTime; j++) {
604         byte[] data = new byte[N_KEY_BYTES];
605         TestUtils.generateRandomAlphaBytes(data);
606         OperationStatus status =
607                     putAndVerifyCursor(cursor, new StringDbt(keyString),
608                                        new StringDbt(data), putVariant);
609
610         if (verifyCount) {
611             assertTrue(cursor.count() == j);
612         }
613
614         if (status != OperationStatus.SUCCESS) {
615             throw new DuplicateEntryException
616             ("Duplicate Entry");
617         }
618         String JavaDoc dataString = new String JavaDoc(data);
619         ht.put(dataString, dataString);
620         }
621         }
622     }
623
624     /**
625      * Debugging routine. Iterate through the transient hashtable of
626      * key/data pairs and ensure that each key can be retrieved from
627      * the tree.
628      */

629     protected void verifyEntries(Hashtable JavaDoc dataMap)
630     throws DatabaseException {
631
632     Tree tree = DbInternal.dbGetDatabaseImpl(exampleDb).getTree();
633     Enumeration JavaDoc e = dataMap.keys();
634     while (e.hasMoreElements()) {
635         String JavaDoc key = (String JavaDoc) e.nextElement();
636         if (!retrieveData(tree, key.getBytes())) {
637         System.out.println("Couldn't find: " + key);
638         }
639     }
640     }
641
642     /* Throw assertion if the database is not valid. */
643     protected void validateDatabase()
644         throws DatabaseException {
645
646         DatabaseImpl dbImpl = DbInternal.dbGetDatabaseImpl(exampleDb);
647         assertTrue(dbImpl.verify(new VerifyConfig(), dbImpl.getEmptyStats()));
648     }
649
650     /**
651      * Helper routine for above.
652      */

653     protected boolean retrieveData(Tree tree, byte[] key)
654     throws DatabaseException {
655
656     TestUtils.checkLatchCount();
657     Node n =
658         tree.search(key, Tree.SearchType.NORMAL, -1, null, true);
659     if (!(n instanceof BIN)) {
660         fail("search didn't return a BIN for key: " + key);
661     }
662     BIN bin = (BIN) n;
663     try {
664         int index = bin.findEntry(key, false, true);
665         if (index == -1) {
666         return false;
667         }
668         return true;
669     } finally {
670         bin.releaseLatch();
671         TestUtils.checkLatchCount();
672     }
673     }
674
675     protected OperationStatus putAndVerifyCursor(Cursor cursor, StringDbt key,
676                          StringDbt data,
677                                                  boolean putVariant)
678     throws DatabaseException {
679
680     OperationStatus status;
681     if (duplicatesAllowed) {
682         status = cursor.putNoDupData(key, data);
683     } else {
684         status = cursor.putNoOverwrite(key, data);
685     }
686
687     if (status == OperationStatus.SUCCESS) {
688         StringDbt keyCheck = new StringDbt();
689         StringDbt dataCheck = new StringDbt();
690
691         assertEquals(OperationStatus.SUCCESS, cursor.getCurrent
692              (keyCheck, dataCheck, LockMode.DEFAULT));
693         assertEquals(key.getString(), keyCheck.getString());
694         assertEquals(data.getString(), dataCheck.getString());
695     }
696
697     return status;
698     }
699
700     protected static class BtreeComparator implements Comparator JavaDoc {
701     protected boolean ascendingComparison = true;
702
703     protected BtreeComparator() {
704     }
705
706     public int compare(Object JavaDoc o1, Object JavaDoc o2) {
707         byte[] arg1;
708         byte[] arg2;
709         if (ascendingComparison) {
710         arg1 = (byte[]) o1;
711         arg2 = (byte[]) o2;
712         } else {
713         arg1 = (byte[]) o2;
714         arg2 = (byte[]) o1;
715         }
716         int a1Len = arg1.length;
717         int a2Len = arg2.length;
718
719         int limit = Math.min(a1Len, a2Len);
720
721         for (int i = 0; i < limit; i++) {
722         byte b1 = arg1[i];
723         byte b2 = arg2[i];
724         if (b1 == b2) {
725             continue;
726         } else {
727             /* Remember, bytes are signed, so convert to shorts so that
728                we effectively do an unsigned byte comparison. */

729             short s1 = (short) (b1 & 0x7F);
730             short s2 = (short) (b2 & 0x7F);
731             if (b1 < 0) {
732             s1 |= 0x80;
733             }
734             if (b2 < 0) {
735             s2 |= 0x80;
736             }
737             return (s1 - s2);
738         }
739         }
740
741         return (a1Len - a2Len);
742     }
743     }
744
745     protected static class ReverseBtreeComparator extends BtreeComparator {
746     protected ReverseBtreeComparator() {
747         ascendingComparison = false;
748     }
749     }
750 }
751
Popular Tags