This discussion is archived
4 Replies Latest reply: Jul 21, 2012 1:34 PM by 950910 RSS

Custom B-Tree Comparator causes IndexOutOfBoundsException

950910 Newbie
Currently Being Moderated
Apologies, I can't seem to figure out how to format the code below.

I've created a database that uses a custom B-Tree Comparator for a key that has type Long. The Comparator just reverses the natural sort order for longs so that entries with greater long values for their keys are returned earlier during iteration.

For some reason, my custom Comparator's compare method throws an IndexOutOfBoundsException when attempting to insert values.

Setting up the database:



EnvironmentConfig envCfg = new EnvironmentConfig();
envCfg.setAllowCreate(true);
envCfg.setTransactional(true);
this.env = new Environment(dbDir, envCfg);

DatabaseConfig dbCfg = new DatabaseConfig();
dbCfg.setAllowCreate(true);
dbCfg.setTransactional(true);
dbCfg.setSortedDuplicates(false);
dbCfg.setBTreeComparator(ReverseLongComparator.class);

Database classDb = this.env.openDatabase(null, "ClassDb", dbCfg);
this.classCtlg = new StoredClassCatalog(classDb);

this.deploymentDb = this.env.openDatabase(null, "MyDatabase", dbCfg);
this.keyBinding = TupleBinding.getPrimitiveBinding(Long.class);
this.depRecBinding = new SerialBinding<MyRecord>(this.classCtlg, MyRecord.class);

map = new StoredSortedMap<Long, MyRecord.class);




ReverseLongComparator:



public class ReverseLongComparator implements Comparator<byte[]>, Serializable {

private static final long serialVersionUID = 1L;

@Override
public int compare(byte[] o1, byte[] o2) {
long k1 = o1.length == 1 ? 0 : LongBinding.entryToLong( new DatabaseEntry(o1) );
long k2 = o2.length == 1 ? 0 : LongBinding.entryToLong( new DatabaseEntry(o2) );

// We want keys to be sorted most recent first. Swap the order
// of the comparison
return Long.compare(k2, k1);
}
}




Code to store a record:



public void storeRecord(final MyRecord rec) throws Exception {
TransactionWorker worker = new TransactionWorker(){
@Override
public void doWork() throws Exception {
map.put(rec.getId(), rec);
}
};

runTxnWorker(this.txnRunner, worker);
}




The error occurs inside ReverseLongComparator. During the first record insertion, the second byte[] o2 has zero length. When the LongBinding.entryToObject is called, the exception is thrown.

Edited by: 947907 on Jul 21, 2012 10:45 AM
  • 1. Re: Custom B-Tree Comparator causes IndexOutOfBoundsException
    greybird Expert
    Currently Being Moderated
    During the first record insertion, the second byte[] o2 has zero length
    This should not happen, based on the code you've posted.

    Please post the complete stack trace (as a general rule, always post the stack trace) and also the version of JE you're using.

    Also, I'm curious about why you have the code checking for length == 1:
    long k1 = o1.length == 1 ? 0 : LongBinding.entryToLong( new DatabaseEntry(o1) );
    long k2 = o2.length == 1 ? 0 : LongBinding.entryToLong( new DatabaseEntry(o2) );
    Is there something else you're not telling us about the way values are stored?

    --mark                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
  • 2. Re: Custom B-Tree Comparator causes IndexOutOfBoundsException
    950910 Newbie
    Currently Being Moderated
    Hi Mark,

    I'm using bdb je 5.0.55.

    To answer your question, I was checking the length of the array for size 1 because that is the size of the array that is causing the IndexOutOfBoundsException. I thought that this might represent an entry with a null key and put that code in while doing some testing. Should have been removed but wasn't.


    Full stack trace:

    Caused by: java.lang.IndexOutOfBoundsException
    at com.sleepycat.bind.tuple.TupleInput.readUnsignedLong(TupleInput.java:385)
    at com.sleepycat.bind.tuple.TupleInput.readLong(TupleInput.java:216)
    at com.sleepycat.bind.tuple.LongBinding.entryToLong(LongBinding.java:60)
    at com.mycompany.util.ReverseLongComparator.compare(ReverseLongComparator.java:20)
    at com.mycompany.util.ReverseLongComparator.compare(ReverseLongComparator.java:1)
    at com.sleepycat.je.tree.Key.compareKeys(Key.java:188)
    at com.sleepycat.je.tree.IN.findEntry(IN.java:2248)
    at com.sleepycat.je.tree.IN.findEntry(IN.java:2169)
    at com.sleepycat.je.tree.IN.insertEntry1(IN.java:2337)
    at com.sleepycat.je.dbi.CursorImpl.insertNewSlot(CursorImpl.java:923)
    at com.sleepycat.je.dbi.CursorImpl.putInternal(CursorImpl.java:839)
    at com.sleepycat.je.dbi.CursorImpl.put(CursorImpl.java:779)
    at com.sleepycat.je.Cursor.putAllowPhantoms(Cursor.java:2243)
    at com.sleepycat.je.Cursor.putNoNotify(Cursor.java:2200)
    at com.sleepycat.je.Cursor.putNotify(Cursor.java:2117)
    at com.sleepycat.je.Cursor.putNoDups(Cursor.java:2052)
    at com.sleepycat.je.Cursor.putInternal(Cursor.java:2020)
    at com.sleepycat.je.Cursor.put(Cursor.java:742)
    at com.sleepycat.bind.serial.StoredClassCatalog.putClassInfo(StoredClassCatalog.java:360)
    at com.sleepycat.bind.serial.StoredClassCatalog.getClassInfo(StoredClassCatalog.java:269)
    at com.sleepycat.bind.serial.StoredClassCatalog.getClassID(StoredClassCatalog.java:152)
    at com.sleepycat.bind.serial.SerialOutput.writeClassDescriptor(SerialOutput.java:86)
    at java.io.ObjectOutputStream.writeNonProxyDesc(ObjectOutputStream.java:1269)
    at java.io.ObjectOutputStream.writeClassDesc(ObjectOutputStream.java:1227)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1411)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
    at com.sleepycat.bind.serial.SerialBinding.objectToEntry(SerialBinding.java:179)
    at com.sleepycat.collections.DataView.useValue(DataView.java:549)
    at com.sleepycat.collections.DataCursor.initForPut(DataCursor.java:817)
    at com.sleepycat.collections.DataCursor.put(DataCursor.java:751)
    at com.sleepycat.collections.StoredContainer.putKeyValue(StoredContainer.java:321)
    at com.sleepycat.collections.StoredMap.put(StoredMap.java:279)
    at com.mycompany.SleepycatDAO$2.doWork(SleepycatDAO.java:211)
    at com.sleepycat.collections.TransactionRunner.run(TransactionRunner.java:226)
    at com.mycompany.util.SleepycatUtil.runTxnWorker(SleepycatUtil.java:276)
    ... 26 more
  • 3. Re: Custom B-Tree Comparator causes IndexOutOfBoundsException
    greybird Expert
    Currently Being Moderated
    Thanks. The stack trace shows your comparator being called when writing to the class catalog database. I should have noticed the error in your code earlier:
    DatabaseConfig dbCfg = new DatabaseConfig();
    dbCfg.setAllowCreate(true);
    dbCfg.setTransactional(true);
    dbCfg.setSortedDuplicates(false);
    dbCfg.setBTreeComparator(ReverseLongComparator.class);
    Database classDb = this.env.openDatabase(null, "ClassDb", dbCfg);
    this.classCtlg = new StoredClassCatalog(classDb);
    this.deploymentDb = this.env.openDatabase(null, "MyDatabase", dbCfg);
    You're using the same db config for the class catalog db as for your app db. Your comparator won't work with the class catalog db.

    --mark                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
  • 4. Re: Custom B-Tree Comparator causes IndexOutOfBoundsException
    950910 Newbie
    Currently Being Moderated
    Thanks Mark.

    Should have caught that myself.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points