[reported by Alex Boisvert <boisvert@exoffice.com>]
Hi Cees,
I've found a bug in PageManager... :(
Luckily, I've also found a way to reproduce it systematically. I've
attached to this message two .java files to reproduce the problem.
Here's the recipe to trigger the bug:
1) Run "java InsertNoClose"
This will print two "insert id=xxxxx"
2) Run "java Fetch xxxx" where xxxx is the second id shown in 1).
ie.
% java InsertNoClose
Insert id=131090
Insert id=131100
% java Fetch 131100
Fetch id = 131100
Exception in thread "main" java.lang.Error: double get for block 0
at com.cdegroot.db.recman.RecordFile.get(RecordFile.java:133)
at
com.cdegroot.db.recman.PhysicalRowIdManager.fetch(PhysicalRowIdManager.java:94)
at
com.cdegroot.db.recman.RecordManager.fetch(RecordManager.java:156)
at Fetch.main(Fetch.java:22)
I don't know if you have time to look into this bug in the near future.
I will certainly have a quick look in the code to see if it's an easy
fix....
In any case, I'd like to know what you think of this.
Regards,
alex.
PS: We (at Exoffice) really like the PageManager. Thanks for your
work.
--
Alex Boisvert, XJ2EE Project Manager
Exoffice Technologies, Inc.
http://www.exoffice.com
mailto:boisvert@exoffice.com
2. InsertNoClose.java
import java.io.*;
import java.util.*;
import com.cdegroot.db.recman.*;
/***********************************************************************
* Demonstrate bug in PageManager
*
* 1) Insert two records (and make sure we can re-read them)
* 2) Exit the application without closing the RecordManager
**********************************************************************/
public class InsertNoClose {
public static void main(String[] args) {
try {
RecordManager recman = new RecordManager("test");
long id;
byte[] buf;
id = recman.insert(new byte[1024]);
System.out.println("Insert id="+id);
buf = recman.fetch(id);
id = recman.insert(new byte[1024]);
System.out.println("Insert id="+id);
buf = recman.fetch(id);
// force exit (no explicit close call)
System.exit(1);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
3. Fetch.java
import java.io.*;
import java.util.*;
import com.cdegroot.db.recman.*;
/***********************************************************************
* Fetch records from database
*
* Usage: java Fetch recordNumber ...
**********************************************************************/
public class Fetch {
public static void main(String[] args) {
try {
RecordManager recman = new RecordManager("test");
long id;
byte[] buf;
for (int i=0; i<args.length; i++) {
id = Long.parseLong(args[i]);
System.out.println("fetch id="+id);
buf = recman.fetch(id);
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
I\'ve submitted a fix for this.
cvs -z9 commit -m \&quot;Fix [ Bug #103848 ] \&quot;double get\&quot; exception on opening unclosed database\&quot; TransactionManager.java (in directory C:\\sourceforge\\jdbm\\db\\com\\cdegroot\\db\\recman)
Checking in TransactionManager.java;
/cvsroot/jdbm/db/com/cdegroot/db/recman/TransactionManager.java,v <-- TransactionManager.java
new revision: 1.2; previous revision: 1.1
done
The TransactionManager was serializing the same BlockIo instance twice in the same ObjectOutputStream... well, as it turns out, the ObjectOutputStream only serialized the first \&quot;version\&quot; of the BlockIo (as per serialization spec.). Thus, the transaction log was inconsistent with the changes made in the file.