debugging of kelondroRecords ... possibly synchronization bugs found

git-svn-id: https://svn.berlios.de/svnroot/repos/yacy/trunk@1188 6c8d7289-2bf4-0310-a012-ef5d649a1542
pull/1/head
orbiter 20 years ago
parent a1061495d4
commit 288b2c353e

@ -54,6 +54,7 @@ public class dbtest {
public STEntry(final long aSource) { public STEntry(final long aSource) {
this.key = randomHash(aSource, aSource); this.key = randomHash(aSource, aSource);
this.value = new byte[valuelength]; this.value = new byte[valuelength];
for (int i = 0; i < valuelength; i++) this.value[i] = 0;
final byte[] tempKey = String.valueOf(aSource).getBytes(); final byte[] tempKey = String.valueOf(aSource).getBytes();
System.arraycopy(tempKey, 0, this.value, 0, tempKey.length); System.arraycopy(tempKey, 0, this.value, 0, tempKey.length);
} }
@ -128,6 +129,7 @@ public class dbtest {
try { try {
final byte[][] entryBytes = getTable().get(entry.getKey()); final byte[][] entryBytes = getTable().get(entry.getKey());
if (entryBytes != null) { if (entryBytes != null) {
System.out.println("ENTRY=" + new String(entryBytes[1]));
final STEntry dbEntry = new STEntry(entryBytes[0], entryBytes[1]); final STEntry dbEntry = new STEntry(entryBytes[0], entryBytes[1]);
if (!dbEntry.isValid()) { if (!dbEntry.isValid()) {
System.out.println(dbEntry); System.out.println(dbEntry);
@ -139,7 +141,6 @@ public class dbtest {
System.err.println(e); System.err.println(e);
} }
} }
} }
public static void main(String[] args) { public static void main(String[] args) {

@ -151,26 +151,26 @@ public class kelondroRecords {
public kelondroRecords(File file, long buffersize /* bytes */, public kelondroRecords(File file, long buffersize /* bytes */,
short ohbytec, short ohhandlec, short ohbytec, short ohhandlec,
int[] columns, int FHandles, int txtProps, int txtPropWidth) throws IOException { int[] columns, int FHandles, int txtProps, int txtPropWidth) throws IOException {
// creates a new file // creates a new file
// file: the file that shall be created // file: the file that shall be created
// oha : overhead size array of four bytes: oha[0]=# of bytes, oha[1]=# of shorts, oha[2]=# of ints, oha[3]=# of longs, // oha : overhead size array of four bytes: oha[0]=# of bytes, oha[1]=# of shorts, oha[2]=# of ints, oha[3]=# of longs,
// columns: array with size of column width; columns.length is number of columns // columns: array with size of column width; columns.length is number of columns
// FHandles: number of integer properties // FHandles: number of integer properties
// txtProps: number of text properties // txtProps: number of text properties
if (file.exists()) throw new IOException("kelondroRecords: file " + file + " already exist"); assert (!file.exists()): "file " + file + " already exist";
this.filename = file.getCanonicalPath(); this.filename = file.getCanonicalPath();
kelondroRA raf = new kelondroFileRA(this.filename); kelondroRA raf = new kelondroFileRA(this.filename);
//kelondroRA raf = new kelondroBufferedRA(new kelondroFileRA(this.filename)); //kelondroRA raf = new kelondroBufferedRA(new kelondroFileRA(this.filename), 1024, 100);
//kelondroRA raf = new kelondroNIOFileRA(this.filename, false, 10000); // kelondroRA raf = new kelondroNIOFileRA(this.filename, false, 10000);
init(raf, ohbytec, ohhandlec, columns, FHandles, txtProps, txtPropWidth); init(raf, ohbytec, ohhandlec, columns, FHandles, txtProps, txtPropWidth);
initCache(buffersize); initCache(buffersize);
} }
public kelondroRecords(kelondroRA ra, long buffersize /* bytes */, public kelondroRecords(kelondroRA ra, long buffersize /* bytes */,
short ohbytec, short ohhandlec, short ohbytec, short ohhandlec,
int[] columns, int FHandles, int txtProps, int txtPropWidth) throws IOException { int[] columns, int FHandles, int txtProps, int txtPropWidth) throws IOException {
this.filename = null; this.filename = null;
init(ra, ohbytec, ohhandlec, columns, FHandles, txtProps, txtPropWidth); init(ra, ohbytec, ohhandlec, columns, FHandles, txtProps, txtPropWidth);
initCache(buffersize); initCache(buffersize);
@ -179,64 +179,66 @@ public class kelondroRecords {
private void init(kelondroRA ra, short ohbytec, short ohhandlec, private void init(kelondroRA ra, short ohbytec, short ohhandlec,
int[] columns, int FHandles, int txtProps, int txtPropWidth) throws IOException { int[] columns, int FHandles, int txtProps, int txtPropWidth) throws IOException {
// store dynamic run-time data // store dynamic run-time data
this.entryFile = ra; this.entryFile = ra;
this.overhead = ohbytec + 4 * ohhandlec; this.overhead = ohbytec + 4 * ohhandlec;
this.recordsize = this.overhead; this.recordsize = this.overhead;
for (int i = 0; i < columns.length; i++) this.recordsize += columns[i]; for (int i = 0; i < columns.length; i++)
this.recordsize += columns[i];
this.headchunksize = overhead + columns[0]; this.headchunksize = overhead + columns[0];
this.tailchunksize = this.recordsize - this.headchunksize; this.tailchunksize = this.recordsize - this.headchunksize;
// store dynamic run-time seek pointers // store dynamic run-time seek pointers
POS_HANDLES = POS_COLWIDTHS + columns.length * 4; POS_HANDLES = POS_COLWIDTHS + columns.length * 4;
POS_TXTPROPS = POS_HANDLES + FHandles * 4; POS_TXTPROPS = POS_HANDLES + FHandles * 4;
POS_NODES = POS_TXTPROPS + txtProps * txtPropWidth; POS_NODES = POS_TXTPROPS + txtProps * txtPropWidth;
// store dynamic back-up variables // store dynamic back-up variables
USEDC = 0; USEDC = 0;
FREEC = 0; FREEC = 0;
FREEH = new Handle(NUL); FREEH = new Handle(NUL);
OHBYTEC = ohbytec; OHBYTEC = ohbytec;
OHHANDLEC = ohhandlec; OHHANDLEC = ohhandlec;
COLWIDTHS = columns; COLWIDTHS = columns;
HANDLES = new Handle[FHandles]; for (int i = 0; i < FHandles; i++) HANDLES[i] = new Handle(NUL); HANDLES = new Handle[FHandles];
TXTPROPS = new byte[txtProps][]; for (int i = 0; i < txtProps; i++) TXTPROPS[i] = new byte[0]; for (int i = 0; i < FHandles; i++) HANDLES[i] = new Handle(NUL);
TXTPROPW = txtPropWidth; TXTPROPS = new byte[txtProps][];
for (int i = 0; i < txtProps; i++) TXTPROPS[i] = new byte[0];
// write data to file TXTPROPW = txtPropWidth;
entryFile.seek(POS_MAGIC); entryFile.writeByte(4); // magic marker for this file type
entryFile.seek(POS_BUSY); entryFile.writeByte(0); // unlock: default // write data to file
entryFile.seek(POS_PORT); entryFile.writeShort(4444); // default port (not used yet) entryFile.seek(POS_MAGIC); entryFile.writeByte(4); // magic marker for this file type
entryFile.seek(POS_DESCR); entryFile.write("--AnomicRecords file structure--".getBytes()); entryFile.seek(POS_BUSY); entryFile.writeByte(0); // unlock: default
entryFile.seek(POS_COLUMNS); entryFile.writeShort(this.COLWIDTHS.length); entryFile.seek(POS_PORT); entryFile.writeShort(4444); // default port (not used yet)
entryFile.seek(POS_OHBYTEC); entryFile.writeShort(OHBYTEC); entryFile.seek(POS_DESCR); entryFile.write("--AnomicRecords file structure--".getBytes());
entryFile.seek(POS_OHHANDLEC); entryFile.writeShort(OHHANDLEC); entryFile.seek(POS_COLUMNS); entryFile.writeShort(this.COLWIDTHS.length);
entryFile.seek(POS_USEDC); entryFile.writeInt(this.USEDC); entryFile.seek(POS_OHBYTEC); entryFile.writeShort(OHBYTEC);
entryFile.seek(POS_FREEC); entryFile.writeInt(this.FREEC); entryFile.seek(POS_OHHANDLEC); entryFile.writeShort(OHHANDLEC);
entryFile.seek(POS_FREEH); entryFile.writeInt(this.FREEH.index); entryFile.seek(POS_USEDC); entryFile.writeInt(this.USEDC);
entryFile.seek(POS_MD5PW); entryFile.write("PASSWORDPASSWORD".getBytes()); entryFile.seek(POS_FREEC); entryFile.writeInt(this.FREEC);
entryFile.seek(POS_ENCRYPTION); entryFile.write("ENCRYPTION!#$%&?".getBytes()); entryFile.seek(POS_FREEH); entryFile.writeInt(this.FREEH.index);
entryFile.seek(POS_OFFSET); entryFile.writeLong(POS_NODES); entryFile.seek(POS_MD5PW); entryFile.write("PASSWORDPASSWORD".getBytes());
entryFile.seek(POS_INTPROPC); entryFile.writeInt(FHandles); entryFile.seek(POS_ENCRYPTION); entryFile.write("ENCRYPTION!#$%&?".getBytes());
entryFile.seek(POS_TXTPROPC); entryFile.writeInt(txtProps); entryFile.seek(POS_OFFSET); entryFile.writeLong(POS_NODES);
entryFile.seek(POS_TXTPROPW); entryFile.writeInt(txtPropWidth); entryFile.seek(POS_INTPROPC); entryFile.writeInt(FHandles);
entryFile.seek(POS_TXTPROPC); entryFile.writeInt(txtProps);
// write configuration arrays entryFile.seek(POS_TXTPROPW); entryFile.writeInt(txtPropWidth);
for (int i = 0; i < this.COLWIDTHS.length; i++) {
entryFile.seek(POS_COLWIDTHS + 4 * i); // write configuration arrays
entryFile.writeInt(COLWIDTHS[i]); for (int i = 0; i < this.COLWIDTHS.length; i++) {
} entryFile.seek(POS_COLWIDTHS + 4 * i);
for (int i = 0; i < this.HANDLES.length; i++) { entryFile.writeInt(COLWIDTHS[i]);
entryFile.seek(POS_HANDLES + 4 * i); }
entryFile.writeInt(NUL); for (int i = 0; i < this.HANDLES.length; i++) {
HANDLES[i] = new Handle(NUL); entryFile.seek(POS_HANDLES + 4 * i);
} entryFile.writeInt(NUL);
for (int i = 0; i < this.TXTPROPS.length; i++) { HANDLES[i] = new Handle(NUL);
entryFile.seek(POS_TXTPROPS + TXTPROPW * i); }
for (int j = 0; j < TXTPROPW; j++) entryFile.writeByte(0); for (int i = 0; i < this.TXTPROPS.length; i++) {
} entryFile.seek(POS_TXTPROPS + TXTPROPW * i);
for (int j = 0; j < TXTPROPW; j++)
// thats it! entryFile.writeByte(0);
}
} }
public void setLogger(Logger newLogger) { public void setLogger(Logger newLogger) {
@ -252,22 +254,24 @@ public class kelondroRecords {
public void clear() throws IOException { public void clear() throws IOException {
// Removes all mappings from this map // Removes all mappings from this map
//throw new UnsupportedOperationException("clear not supported"); // throw new UnsupportedOperationException("clear not supported");
USEDC = 0; USEDC = 0;
FREEC = 0; FREEC = 0;
FREEH = new Handle(NUL); FREEH = new Handle(NUL);
entryFile.seek(POS_USEDC); entryFile.writeInt(this.USEDC); entryFile.seek(POS_USEDC);
entryFile.seek(POS_FREEC); entryFile.writeInt(this.FREEC); entryFile.writeInt(this.USEDC);
entryFile.seek(POS_FREEH); entryFile.writeInt(this.FREEH.index); entryFile.seek(POS_FREEC);
entryFile.writeInt(this.FREEC);
entryFile.seek(POS_FREEH);
entryFile.writeInt(this.FREEH.index);
} }
public kelondroRecords(File file, long buffersize) throws IOException{ public kelondroRecords(File file, long buffersize) throws IOException{
// opens an existing tree // opens an existing tree
if (!file.exists()) throw new IOException("kelondroRecords: file " + file.getAbsoluteFile().toString() + " does not exist"); assert (file.exists()): "file " + file.getAbsoluteFile().toString() + " does not exist";
this.filename = file.getCanonicalPath(); this.filename = file.getCanonicalPath();
kelondroRA raf = new kelondroFileRA(this.filename); kelondroRA raf = new kelondroFileRA(this.filename);
//kelondroRA raf = new kelondroBufferedRA(new kelondroFileRA(this.filename)); //kelondroRA raf = new kelondroBufferedRA(new kelondroFileRA(this.filename), 1024, 100);
//kelondroRA raf = new kelondroCachedRA(new kelondroFileRA(this.filename), 5000000, 1000); //kelondroRA raf = new kelondroCachedRA(new kelondroFileRA(this.filename), 5000000, 1000);
//kelondroRA raf = new kelondroNIOFileRA(this.filename, (file.length() < 4000000), 10000); //kelondroRA raf = new kelondroNIOFileRA(this.filename, (file.length() < 4000000), 10000);
init(raf); init(raf);
@ -281,48 +285,48 @@ public class kelondroRecords {
} }
private void init(kelondroRA ra) throws IOException { private void init(kelondroRA ra) throws IOException {
// assign values that are only present at run-time // assign values that are only present at run-time
this.entryFile = ra; this.entryFile = ra;
// read dynamic variables that are back-ups of stored values in file; read/defined on instantiation // read dynamic variables that are back-ups of stored values in file;
entryFile.seek(POS_USEDC); this.USEDC = entryFile.readInt(); // read/defined on instantiation
entryFile.seek(POS_FREEC); this.FREEC = entryFile.readInt(); entryFile.seek(POS_USEDC); this.USEDC = entryFile.readInt();
entryFile.seek(POS_FREEH); this.FREEH = new Handle(entryFile.readInt()); entryFile.seek(POS_FREEC); this.FREEC = entryFile.readInt();
entryFile.seek(POS_FREEH); this.FREEH = new Handle(entryFile.readInt());
entryFile.seek(POS_OHBYTEC); OHBYTEC = entryFile.readShort(); entryFile.seek(POS_OHBYTEC); this.OHBYTEC = entryFile.readShort();
entryFile.seek(POS_OHHANDLEC); OHHANDLEC = entryFile.readShort(); entryFile.seek(POS_OHHANDLEC); this.OHHANDLEC = entryFile.readShort();
entryFile.seek(POS_COLUMNS); this.COLWIDTHS = new int[entryFile.readShort()]; entryFile.seek(POS_COLUMNS); this.COLWIDTHS = new int[entryFile.readShort()];
entryFile.seek(POS_INTPROPC); this.HANDLES = new Handle[entryFile.readInt()]; entryFile.seek(POS_INTPROPC); this.HANDLES = new Handle[entryFile.readInt()];
entryFile.seek(POS_TXTPROPC); this.TXTPROPS = new byte[entryFile.readInt()][]; entryFile.seek(POS_TXTPROPC); this.TXTPROPS = new byte[entryFile.readInt()][];
entryFile.seek(POS_TXTPROPW); this.TXTPROPW = entryFile.readInt(); entryFile.seek(POS_TXTPROPW); this.TXTPROPW = entryFile.readInt();
if (COLWIDTHS.length == 0) throw new kelondroException(filename, "init: zero columns; strong failure"); if (COLWIDTHS.length == 0) throw new kelondroException(filename, "init: zero columns; strong failure");
// calculate dynamic run-time seek pointers // calculate dynamic run-time seek pointers
POS_HANDLES = POS_COLWIDTHS + COLWIDTHS.length * 4; POS_HANDLES = POS_COLWIDTHS + COLWIDTHS.length * 4;
POS_TXTPROPS = POS_HANDLES + HANDLES.length * 4; POS_TXTPROPS = POS_HANDLES + HANDLES.length * 4;
POS_NODES = POS_TXTPROPS + TXTPROPS.length * TXTPROPW; POS_NODES = POS_TXTPROPS + TXTPROPS.length * TXTPROPW;
// read configuration arrays // read configuration arrays
for (int i = 0; i < COLWIDTHS.length; i++) { for (int i = 0; i < COLWIDTHS.length; i++) {
entryFile.seek(POS_COLWIDTHS + 4 * i); entryFile.seek(POS_COLWIDTHS + 4 * i);
COLWIDTHS[i] = entryFile.readInt(); COLWIDTHS[i] = entryFile.readInt();
} }
for (int i = 0; i < HANDLES.length; i++) { for (int i = 0; i < HANDLES.length; i++) {
entryFile.seek(POS_HANDLES + 4 * i); entryFile.seek(POS_HANDLES + 4 * i);
HANDLES[i] = new Handle(entryFile.readInt()); HANDLES[i] = new Handle(entryFile.readInt());
} }
for (int i = 0; i < TXTPROPS.length; i++) { for (int i = 0; i < TXTPROPS.length; i++) {
entryFile.seek(POS_TXTPROPS + TXTPROPW * i); entryFile.seek(POS_TXTPROPS + TXTPROPW * i);
TXTPROPS[i] = new byte[TXTPROPW]; TXTPROPS[i] = new byte[TXTPROPW];
entryFile.readFully(TXTPROPS[i], 0, TXTPROPS[i].length); entryFile.readFully(TXTPROPS[i], 0, TXTPROPS[i].length);
} }
// assign remaining values that are only present at run-time // assign remaining values that are only present at run-time
this.overhead = OHBYTEC + 4 * OHHANDLEC; this.overhead = OHBYTEC + 4 * OHHANDLEC;
this.recordsize = this.overhead; this.recordsize = this.overhead;
for (int i = 0; i < COLWIDTHS.length; i++) this.recordsize += COLWIDTHS[i]; for (int i = 0; i < COLWIDTHS.length; i++) this.recordsize += COLWIDTHS[i];
this.headchunksize = this.overhead + COLWIDTHS[0]; this.headchunksize = this.overhead + COLWIDTHS[0];
this.tailchunksize = this.recordsize - this.headchunksize; this.tailchunksize = this.recordsize - this.headchunksize;
@ -380,7 +384,6 @@ public class kelondroRecords {
return new int[]{XcacheSize - (XcacheHeaders[CP_HIGH].size() + XcacheHeaders[CP_MEDIUM].size() + XcacheHeaders[CP_LOW].size()), XcacheHeaders[CP_HIGH].size(), XcacheHeaders[CP_MEDIUM].size(), XcacheHeaders[CP_LOW].size()}; return new int[]{XcacheSize - (XcacheHeaders[CP_HIGH].size() + XcacheHeaders[CP_MEDIUM].size() + XcacheHeaders[CP_LOW].size()), XcacheHeaders[CP_HIGH].size(), XcacheHeaders[CP_MEDIUM].size(), XcacheHeaders[CP_LOW].size()};
} }
protected Node newNode() throws IOException { protected Node newNode() throws IOException {
return new Node(); return new Node();
} }
@ -416,43 +419,41 @@ public class kelondroRecords {
dispose(handle); dispose(handle);
} }
public class Node { public class Node {
// an Node holds all information of one row of data. This includes the key to the entry // an Node holds all information of one row of data. This includes the key to the entry
// which is stored as entry element at position 0 // which is stored as entry element at position 0
// an Node object can be created in two ways: // an Node object can be created in two ways:
// 1. instantiation with an index number. After creation the Object does not hold any // 1. instantiation with an index number. After creation the Object does not hold any
// value information until such is retrieved using the getValue() method // value information until such is retrieved using the getValue() method
// 2. instantiation with a value array. the values are not directly written into the // 2. instantiation with a value array. the values are not directly written into the
// file. Expanding the tree structure is then done using the save() method. at any // file. Expanding the tree structure is then done using the save() method. at any
// time it is possible to verify the save state using the saved() predicate. // time it is possible to verify the save state using the saved() predicate.
// Therefore an entry object has three modes: // Therefore an entry object has three modes:
// a: holding an index information only (saved() = true) // a: holding an index information only (saved() = true)
// b: holding value information only (saved() = false) // b: holding value information only (saved() = false)
// c: holding index and value information at the same time (saved() = true) // c: holding index and value information at the same time (saved() = true)
// which can be the result of one of the two processes as follow: // which can be the result of one of the two processes as follow:
// (i) created with index and after using the getValue() method, or // (i) created with index and after using the getValue() method, or
// (ii) created with values and after calling the save() method // (ii) created with values and after calling the save() method
// the method will therefore throw an IllegalStateException when the following // the method will therefore throw an IllegalStateException when the following
// process step is performed: // process step is performed:
// - create the Node with index and call then the save() method // - create the Node with index and call then the save() method
// this case can be decided with // this case can be decided with
// ((index != NUL) && (values == null)) // ((index != NUL) && (values == null))
// The save() method represents the insert function for the tree. Balancing functions // The save() method represents the insert function for the tree. Balancing functions
// are applied automatically. While balancing, the Node does never change its index key, // are applied automatically. While balancing, the Node does never change its index key,
// but its parent/child keys. // but its parent/child keys.
//private byte[] ohBytes = null; // the overhead bytes, OHBYTEC values //private byte[] ohBytes = null; // the overhead bytes, OHBYTEC values
//private Handle[] ohHandle= null; // the overhead handles, OHHANDLEC values //private Handle[] ohHandle= null; // the overhead handles, OHHANDLEC values
//private byte[][] values = null; // an array of byte[] nodes is the value vector //private byte[][] values = null; // an array of byte[] nodes is the value vector
private Handle handle = null; // index of the entry, by default NUL means undefined private Handle handle = null; // index of the entry, by default NUL means undefined
private byte[] headChunk = null; // contains ohBytes, ohHandles and the key value private byte[] headChunk = null; // contains ohBytes, ohHandles and the key value
private byte[] tailChunk = null; // contains all values except the key value private byte[] tailChunk = null; // contains all values except the key value
private boolean headChanged = false; private boolean headChanged = false;
private boolean tailChanged = false; private boolean tailChanged = false;
private Node() throws IOException { private Node() throws IOException {
// create a new empty node and reserve empty space in file for it // create a new empty node and reserve empty space in file for it
// use this method only if you want to extend the file with new entries // use this method only if you want to extend the file with new entries
// without the need to have content in it. // without the need to have content in it.
this.handle = new Handle(); this.handle = new Handle();
@ -464,7 +465,7 @@ public class kelondroRecords {
for (int i = 0; i < tailchunksize; i++) this.tailChunk[i] = 0; for (int i = 0; i < tailchunksize; i++) this.tailChunk[i] = 0;
this.headChanged = true; this.headChanged = true;
this.tailChanged = true; this.tailChanged = true;
} }
/* /*
private Node(Handle handle) throws IOException { private Node(Handle handle) throws IOException {
@ -483,12 +484,15 @@ public class kelondroRecords {
*/ */
private Node(Handle handle, Node parentNode, int referenceInParent) throws IOException { private Node(Handle handle, Node parentNode, int referenceInParent) throws IOException {
// this creates an entry with an pre-reserved entry position // this creates an entry with an pre-reserved entry position values can be written
// values can be written using the setValues() method // using the setValues() method but we expect that values are already there in the file
// but we expect that values are already there in the file ready to be read which we do not here // ready to be read which we do not here
if (handle == null) throw new IllegalArgumentException("INTERNAL ERROR: node handle is null."); assert (handle != null): "node handle is null";
assert (handle.index >= 0): "node handle too low: " + handle.index;
// the parentNode can be given if an auto-fix in the following case is wanted assert (handle.index < USEDC + FREEC) : "node handle too high: " + handle.index + ", USEDC=" + USEDC + ", FREEC=" + FREEC;
// the parentNode can be given if an auto-fix in the following case
// is wanted
if (handle.index >= USEDC + FREEC) { if (handle.index >= USEDC + FREEC) {
if (parentNode == null) { if (parentNode == null) {
throw new kelondroException(filename, "INTERNAL ERROR, Node/init: node handle index exceeds size. No auto-fix node was submitted. This is a serious failure."); throw new kelondroException(filename, "INTERNAL ERROR, Node/init: node handle index exceeds size. No auto-fix node was submitted. This is a serious failure.");
@ -504,11 +508,11 @@ public class kelondroRecords {
} }
// use given handle // use given handle
this.handle = new Handle(handle.index); this.handle = new Handle(handle.index);
// init the content // init the content
initContent(); initContent();
} }
private void initContent() throws IOException { private void initContent() throws IOException {
// create chunks; read them from file or cache // create chunks; read them from file or cache
@ -573,52 +577,53 @@ public class kelondroRecords {
while (valuewidth-- > 0) targetarray[targetoffset + valuewidth] = 0; while (valuewidth-- > 0) targetarray[targetoffset + valuewidth] = 0;
} else { } else {
System.arraycopy(value, 0, targetarray, targetoffset, Math.min(value.length, valuewidth)); // error? System.arraycopy(value, 0, targetarray, targetoffset, Math.min(value.length, valuewidth)); // error?
if (value.length < valuewidth) if (value.length < valuewidth) {
while (valuewidth-- > value.length) targetarray[targetoffset + valuewidth] = 0; while (valuewidth-- > value.length) targetarray[targetoffset + valuewidth] = 0;
}
} }
} }
protected Handle handle() { protected Handle handle() {
// if this entry has an index, return it // if this entry has an index, return it
if (this.handle.index == NUL) throw new kelondroException(filename, "the entry has no index assigned"); if (this.handle.index == NUL) throw new kelondroException(filename, "the entry has no index assigned");
return new Handle(this.handle.index); return new Handle(this.handle.index);
} }
protected void setOHByte(int i, byte b) { protected void setOHByte(int i, byte b) {
if (i >= OHBYTEC) throw new IllegalArgumentException("setOHByte: wrong index " + i); if (i >= OHBYTEC) throw new IllegalArgumentException("setOHByte: wrong index " + i);
if (this.handle.index == NUL) throw new kelondroException(filename, "setOHByte: no handle assigned"); if (this.handle.index == NUL) throw new kelondroException(filename, "setOHByte: no handle assigned");
this.headChunk[i] = b; this.headChunk[i] = b;
this.headChanged = true; this.headChanged = true;
} }
protected void setOHHandle(int i, Handle handle) { protected void setOHHandle(int i, Handle otherhandle) {
if (i >= OHHANDLEC) throw new IllegalArgumentException("setOHHandle: wrong array size " + i); assert (i < OHHANDLEC): "setOHHandle: wrong array size " + i;
if (this.handle.index == NUL) throw new kelondroException(filename, "setOHHandle: no handle assigned"); assert (this.handle.index != NUL): "setOHHandle: no handle assigned ind file" + filename;
if (handle == null) { if (otherhandle == null) {
NUL2bytes(this.headChunk, OHBYTEC + 4 * i); NUL2bytes(this.headChunk, OHBYTEC + 4 * i);
} else { } else {
if (handle.index > USEDC + FREEC) throw new kelondroException(filename, "INTERNAL ERROR, setOHHandles: handle " + i + " exceeds file size (" + handle.index + " > " + (USEDC + FREEC) + ")"); if (otherhandle.index > USEDC + FREEC) throw new kelondroException(filename, "INTERNAL ERROR, setOHHandles: handle " + i + " exceeds file size (" + handle.index + " > " + (USEDC + FREEC) + ")");
int2bytes(handle.index, this.headChunk, OHBYTEC + 4 * i); int2bytes(otherhandle.index, this.headChunk, OHBYTEC + 4 * i);
} }
this.headChanged = true; this.headChanged = true;
} }
protected byte getOHByte(int i) { protected byte getOHByte(int i) {
if (i >= OHBYTEC) throw new IllegalArgumentException("getOHByte: wrong index " + i); if (i >= OHBYTEC) throw new IllegalArgumentException("getOHByte: wrong index " + i);
if (this.handle.index == NUL) throw new kelondroException(filename, "Cannot load OH values"); if (this.handle.index == NUL) throw new kelondroException(filename, "Cannot load OH values");
return this.headChunk[i]; return this.headChunk[i];
} }
protected Handle getOHHandle(int i) { protected Handle getOHHandle(int i) {
if (this.handle.index == NUL) throw new kelondroException(filename, "Cannot load OH values"); if (this.handle.index == NUL) throw new kelondroException(filename, "Cannot load OH values");
if (i >= OHHANDLEC) throw new kelondroException(filename, "handle index out of bounds: " + i); assert (i < OHHANDLEC): "handle index out of bounds: " + i + " in file " + filename;
int h = bytes2int(this.headChunk, OHBYTEC + 4 * i); int h = bytes2int(this.headChunk, OHBYTEC + 4 * i);
return (h == NUL) ? null : new Handle(h); return (h == NUL) ? null : new Handle(h);
} }
public byte[][] setValues(byte[][] row) throws IOException { public byte[][] setValues(byte[][] row) throws IOException {
// if the index is defined, then write values directly to the file, else only to the object // if the index is defined, then write values directly to the file, else only to the object
byte[][] result = getValues(); // previous value (this loads the values if not already happened) byte[][] result = getValues(); // previous value (this loads the values if not already happened)
// set values // set values
if (this.handle.index != NUL) { if (this.handle.index != NUL) {
@ -631,15 +636,16 @@ public class kelondroRecords {
} }
this.headChanged = true; this.headChanged = true;
this.tailChanged = true; this.tailChanged = true;
return result; // return previous value return result; // return previous value
} }
public byte[] getKey() { public byte[] getKey() {
// read key // read key
return trimCopy(headChunk, overhead, COLWIDTHS[0]); return trimCopy(headChunk, overhead, COLWIDTHS[0]);
} }
public byte[][] getValues() throws IOException {
public byte[][] getValues() throws IOException {
if (this.tailChunk == null) { if (this.tailChunk == null) {
// load all values from the database file // load all values from the database file
this.tailChunk = new byte[tailchunksize]; this.tailChunk = new byte[tailchunksize];
@ -667,7 +673,8 @@ public class kelondroRecords {
} }
public synchronized void commit(int cachePriority) throws IOException { public synchronized void commit(int cachePriority) throws IOException {
// this must be called after all write operations to the node are finished // this must be called after all write operations to the node are
// finished
// place the data to the file // place the data to the file
@ -680,30 +687,36 @@ public class kelondroRecords {
if (this.headChanged) { if (this.headChanged) {
synchronized (entryFile) { synchronized (entryFile) {
entryFile.seek(seekpos(this.handle)); entryFile.seek(seekpos(this.handle));
//System.out.print("#write "); printChunk(this.handle, this.headChunk); System.out.println(); // System.out.print("#write "); printChunk(this.handle,
// this.headChunk); System.out.println();
entryFile.write(this.headChunk); entryFile.write(this.headChunk);
} }
update2Cache(cachePriority); update2Cache(cachePriority);
} }
// save tail // save tail
if ((this.tailChunk != null) && (this.tailChanged)) synchronized (entryFile) { if ((this.tailChunk != null) && (this.tailChanged))
entryFile.seek(seekpos(this.handle) + headchunksize); synchronized (entryFile) {
entryFile.write(this.tailChunk); entryFile.seek(seekpos(this.handle) + headchunksize);
} entryFile.write(this.tailChunk);
}
} }
public synchronized void collapse() { public synchronized void collapse() {
// this must be called after all write and read operations to the node are finished // this must be called after all write and read operations to the
// node are finished
this.headChunk = null; this.headChunk = null;
this.tailChunk = null; this.tailChunk = null;
this.handle = null; this.handle = null;
} }
private byte[] trimCopy(byte[] a, int offset, int length) { private byte[] trimCopy(byte[] a, int offset, int length) {
if (length > a.length - offset) length = a.length - offset; if (length > a.length - offset)
while ((length > 0) && (a[offset + length - 1] == 0)) length--; length = a.length - offset;
if (length == 0) return null; while ((length > 0) && (a[offset + length - 1] == 0))
length--;
if (length == 0)
return null;
byte[] b = new byte[length]; byte[] b = new byte[length];
System.arraycopy(a, offset, b, 0, length); System.arraycopy(a, offset, b, 0, length);
return b; return b;
@ -804,9 +817,9 @@ public class kelondroRecords {
// we simply clear the cache // we simply clear the cache
String error = "cachScore error: " + e.getMessage() + "; cachesize=" + XcacheSize + ", cache.size()=[" + XcacheHeaders[0].size() + "," + XcacheHeaders[1].size() + "," + XcacheHeaders[2].size() + "], cacheScore.size()=" + cacheScore.size(); String error = "cachScore error: " + e.getMessage() + "; cachesize=" + XcacheSize + ", cache.size()=[" + XcacheHeaders[0].size() + "," + XcacheHeaders[1].size() + "," + XcacheHeaders[2].size() + "], cacheScore.size()=" + cacheScore.size();
cacheScore = new kelondroMScoreCluster(); cacheScore = new kelondroMScoreCluster();
XcacheHeaders[0] = new HashMap(); XcacheHeaders[CP_LOW] = new HashMap();
XcacheHeaders[1] = new HashMap(); XcacheHeaders[CP_MEDIUM] = new HashMap();
XcacheHeaders[2] = new HashMap(); XcacheHeaders[CP_HIGH] = new HashMap();
throw new kelondroException(filename, error); throw new kelondroException(filename, error);
} }
@ -829,9 +842,9 @@ public class kelondroRecords {
// store the cache entry // store the cache entry
//XcacheHeaders.remove(cacheHandle); //XcacheHeaders.remove(cacheHandle);
if (priority != CP_LOW) XcacheHeaders[CP_LOW].remove(cacheHandle); if (priority != CP_LOW) XcacheHeaders[CP_LOW].remove(cacheHandle);
if (priority != CP_MEDIUM) XcacheHeaders[CP_MEDIUM].remove(cacheHandle); if (priority != CP_MEDIUM) XcacheHeaders[CP_MEDIUM].remove(cacheHandle);
if (priority != CP_HIGH) XcacheHeaders[CP_HIGH].remove(cacheHandle); if (priority != CP_HIGH) XcacheHeaders[CP_HIGH].remove(cacheHandle);
XcacheHeaders[priority].put(cacheHandle, cacheEntry); XcacheHeaders[priority].put(cacheHandle, cacheEntry);
if ((cacheScore != null) && (priority == CP_HIGH)) { if ((cacheScore != null) && (priority == CP_HIGH)) {
cacheScore.setScore(cacheHandle, (int) ((System.currentTimeMillis() - XcacheStartup) / 1000)); cacheScore.setScore(cacheHandle, (int) ((System.currentTimeMillis() - XcacheStartup) / 1000));
@ -893,117 +906,125 @@ public class kelondroRecords {
} }
public synchronized int columns() { public synchronized int columns() {
return this.COLWIDTHS.length; return this.COLWIDTHS.length;
} }
public synchronized int columnSize(int column) { public synchronized int columnSize(int column) {
if ((column < 0) || (column >= this.COLWIDTHS.length)) return -1; if ((column < 0) || (column >= this.COLWIDTHS.length)) return -1;
return this.COLWIDTHS[column]; return this.COLWIDTHS[column];
} }
private long seekpos(Handle handle) { private long seekpos(Handle handle) {
return POS_NODES + ((long) recordsize * handle.index); assert (handle.index >= 0): "handle index too low: " + handle.index;
assert (handle.index < FREEC + USEDC): "handle index too high:" + handle.index;
return POS_NODES + ((long) recordsize * handle.index);
} }
// additional properties // additional properties
public synchronized int handles() { public synchronized int handles() {
return this.HANDLES.length; return this.HANDLES.length;
} }
protected void setHandle(int pos, Handle handle) throws IOException { protected void setHandle(int pos, Handle handle) throws IOException {
if (pos >= HANDLES.length) throw new IllegalArgumentException("setHandle: handle array exceeded"); if (pos >= HANDLES.length) throw new IllegalArgumentException("setHandle: handle array exceeded");
if (handle == null) handle = new Handle(NUL); if (handle == null) handle = new Handle(NUL);
HANDLES[pos] = handle; synchronized (entryFile) {
entryFile.seek(POS_HANDLES + 4 * pos); HANDLES[pos] = handle;
entryFile.writeInt(handle.index); entryFile.seek(POS_HANDLES + 4 * pos);
entryFile.writeInt(handle.index);
}
} }
protected Handle getHandle(int pos) { protected Handle getHandle(int pos) {
if (pos >= HANDLES.length) throw new IllegalArgumentException("getHandle: handle array exceeded"); if (pos >= HANDLES.length) throw new IllegalArgumentException("getHandle: handle array exceeded");
return (HANDLES[pos].index == NUL) ? null : HANDLES[pos]; return (HANDLES[pos].index == NUL) ? null : HANDLES[pos];
} }
// custom texts // custom texts
public void setText(int pos, byte[] text) throws IOException { public void setText(int pos, byte[] text) throws IOException {
if (pos >= TXTPROPS.length) throw new IllegalArgumentException("setText: text array exceeded"); if (pos >= TXTPROPS.length) throw new IllegalArgumentException("setText: text array exceeded");
if (text.length > TXTPROPW) throw new IllegalArgumentException("setText: text lemgth exceeded"); if (text.length > TXTPROPW) throw new IllegalArgumentException("setText: text lemgth exceeded");
if (text == null) text = new byte[0]; if (text == null) text = new byte[0];
TXTPROPS[pos] = text; synchronized (entryFile) {
entryFile.seek(POS_TXTPROPS + TXTPROPW * pos); TXTPROPS[pos] = text;
entryFile.write(text); entryFile.seek(POS_TXTPROPS + TXTPROPW * pos);
entryFile.write(text);
}
} }
public byte[] getText(int pos) { public byte[] getText(int pos) {
if (pos >= TXTPROPS.length) throw new IllegalArgumentException("getText: text array exceeded"); if (pos >= TXTPROPS.length) throw new IllegalArgumentException("getText: text array exceeded");
return TXTPROPS[pos]; return TXTPROPS[pos];
} }
// Returns true if this map contains no key-value mappings. // Returns true if this map contains no key-value mappings.
public boolean isEmpty() { public boolean isEmpty() {
return (USEDC == 0); return (USEDC == 0);
} }
// Returns the number of key-value mappings in this map. // Returns the number of key-value mappings in this map.
public int size() { public int size() {
return this.USEDC; return this.USEDC;
} }
protected int free() { protected int free() {
return this.FREEC; return this.FREEC;
} }
private void dispose(Handle h) throws IOException { private void dispose(Handle h) throws IOException {
// delete element with handle h // delete element with handle h
// this element is then connected to the deleted-chain and can be re-used // this element is then connected to the deleted-chain and can be
// change counter // re-used change counter
synchronized (entryFile) { synchronized (entryFile) {
USEDC--; entryFile.seek(POS_USEDC); entryFile.writeInt(USEDC); USEDC--;
FREEC++; entryFile.seek(POS_FREEC); entryFile.writeInt(FREEC); entryFile.seek(POS_USEDC); entryFile.writeInt(USEDC);
// change pointer FREEC++;
if (this.FREEH.index == NUL) { entryFile.seek(POS_FREEC); entryFile.writeInt(FREEC);
// the first entry // change pointer
entryFile.seek(seekpos(h)); entryFile.writeInt(NUL); // write null link at end of free-list if (this.FREEH.index == NUL) {
} else { // the first entry
// another entry entryFile.seek(seekpos(h)); entryFile.writeInt(NUL); // write null link at end of free-list
entryFile.seek(seekpos(h)); entryFile.writeInt(this.FREEH.index); // extend free-list } else {
} // another entry
// write new FREEH Handle link entryFile.seek(seekpos(h)); entryFile.writeInt(this.FREEH.index); // extend free-list
this.FREEH = h; }
entryFile.seek(POS_FREEH); entryFile.writeInt(this.FREEH.index); // write new FREEH Handle link
} this.FREEH = h;
entryFile.seek(POS_FREEH); entryFile.writeInt(this.FREEH.index);
}
} }
public void close() throws IOException { public void close() throws IOException {
if (this.entryFile != null) this.entryFile.close(); if (this.entryFile != null) this.entryFile.close();
this.entryFile = null; this.entryFile = null;
} }
public void finalize() { public void finalize() {
try { try {
close(); close();
} catch (IOException e) {} } catch (IOException e) { }
} }
protected static String[] line2args(String line) { protected static String[] line2args(String line) {
// parse the command line // parse the command line
if ((line == null) || (line.length() == 0)) return null; if ((line == null) || (line.length() == 0)) return null;
String args[]; String args[];
StringTokenizer st = new StringTokenizer(line); StringTokenizer st = new StringTokenizer(line);
args = new String[st.countTokens()]; args = new String[st.countTokens()];
for (int i = 0; st.hasMoreTokens(); i++) { for (int i = 0; st.hasMoreTokens(); i++) {
args[i] = st.nextToken(); args[i] = st.nextToken();
} }
st = null; st = null;
return args; return args;
} }
protected static boolean equals(byte[] a, byte[] b) { protected static boolean equals(byte[] a, byte[] b) {
if (a == b) return true; if (a == b) return true;
if ((a == null) || (b == null)) return false; if ((a == null) || (b == null)) return false;
if (a.length != b.length) return false; if (a.length != b.length) return false;
for (int n = 0; n < a.length; n++) if (a[n] != b[n]) return false; for (int n = 0; n < a.length; n++) if (a[n] != b[n]) return false;
return true; return true;
} }
public static byte[] long2bytes(long x, int length) { public static byte[] long2bytes(long x, int length) {
@ -1045,101 +1066,148 @@ public class kelondroRecords {
} }
public void print(boolean records) throws IOException { public void print(boolean records) throws IOException {
System.out.println("REPORT FOR FILE '" + this.filename + "':"); System.out.println("REPORT FOR FILE '" + this.filename + "':");
System.out.println("--"); System.out.println("--");
System.out.println("CONTROL DATA"); System.out.println("CONTROL DATA");
System.out.print( " HANDLES : " + HANDLES.length + " int-values"); System.out.print(" HANDLES : " + HANDLES.length + " int-values");
if (HANDLES.length == 0) System.out.println(); else { if (HANDLES.length == 0)
System.out.print(" {" + HANDLES[0].toString()); System.out.println();
for (int i = 1; i < HANDLES.length; i++) System.out.print(", " + HANDLES[i].toString()); else {
System.out.println("}"); System.out.print(" {" + HANDLES[0].toString());
} for (int i = 1; i < HANDLES.length; i++)
System.out.print( " TXTPROPS : " + TXTPROPS.length + " strings, max length " + TXTPROPW + " bytes"); System.out.print(", " + HANDLES[i].toString());
if (TXTPROPS.length == 0) System.out.println(); else { System.out.println("}");
System.out.print(" {'" + (new String(TXTPROPS[0])).trim()); System.out.print("'"); }
for (int i = 1; i < TXTPROPS.length; i++) System.out.print(", '" + (new String(TXTPROPS[i])).trim() + "'"); System.out.print(" TXTPROPS : " + TXTPROPS.length + " strings, max length " + TXTPROPW + " bytes");
System.out.println("}"); if (TXTPROPS.length == 0)
} System.out.println();
System.out.println(" USEDC : " + this.USEDC); else {
System.out.println(" FREEC : " + this.FREEC); System.out.print(" {'" + (new String(TXTPROPS[0])).trim());
System.out.println(" FREEH : " + FREEH.toString()); System.out.print("'");
System.out.println(" Data Offset: 0x" + Long.toHexString(POS_NODES)); for (int i = 1; i < TXTPROPS.length; i++)
System.out.println("--"); System.out.print(", '" + (new String(TXTPROPS[i])).trim() + "'");
System.out.println("RECORDS"); System.out.println("}");
System.out.print( " Columns : " + columns() + " columns {" + COLWIDTHS[0]); }
for (int i = 1; i < columns(); i++) System.out.print(", " + COLWIDTHS[i]); System.out.println(" USEDC : " + this.USEDC);
System.out.println("}"); System.out.println(" FREEC : " + this.FREEC);
System.out.println(" Overhead : " + this.overhead + " bytes ("+ OHBYTEC + " OH bytes, " + OHHANDLEC + " OH Handles)"); System.out.println(" FREEH : " + FREEH.toString());
System.out.println(" Recordsize : " + this.recordsize + " bytes"); System.out.println(" Data Offset: 0x" + Long.toHexString(POS_NODES));
System.out.println("--"); System.out.println("--");
System.out.println("RECORDS");
System.out.print(" Columns : " + columns() + " columns {" + COLWIDTHS[0]);
for (int i = 1; i < columns(); i++) System.out.print(", " + COLWIDTHS[i]);
System.out.println("}");
System.out.println(" Overhead : " + this.overhead + " bytes (" + OHBYTEC + " OH bytes, " + OHHANDLEC + " OH Handles)");
System.out.println(" Recordsize : " + this.recordsize + " bytes");
System.out.println("--");
printCache(); printCache();
System.out.println("--"); System.out.println("--");
if (!(records)) return; if (!(records)) return;
// print also all records // print also all records
for (int i = 0; i < USEDC + FREEC; i++) System.out.println("NODE: " + new Node(new Handle(i), null, 0).toString()); for (int i = 0; i < USEDC + FREEC; i++)
System.out.println("NODE: " + new Node(new Handle(i), null, 0).toString());
} }
public String toString() { public String toString() {
return size() + " RECORDS IN FILE " + filename; return size() + " RECORDS IN FILE " + filename;
} }
protected class Handle implements Comparable { protected class Handle implements Comparable {
private int index; private int index;
private Handle() throws IOException {
// reserves a new record and returns index of record private Handle() throws IOException {
// the return value is not a seek position // reserves a new record and returns index of record
// the seek position can be retrieved using the seekpos() function // the return value is not a seek position
if (FREEC == 0) { // the seek position can be retrieved using the seekpos() function
// generate new entry synchronized (this) {
index = USEDC + FREEC; if (FREEC == 0) {
USEDC++; entryFile.seek(POS_USEDC); entryFile.writeInt(USEDC); // generate new entry
} else { synchronized (entryFile) {
// re-use record from free-list index = USEDC + FREEC;
USEDC++; entryFile.seek(POS_USEDC); entryFile.writeInt(USEDC); USEDC++;
FREEC--; entryFile.seek(POS_FREEC); entryFile.writeInt(FREEC); entryFile.seek(POS_USEDC); entryFile.writeInt(USEDC);
// take link }
if (FREEH.index == NUL) { } else {
System.out.println("INTERNAL ERROR (DATA INCONSISTENCY): re-use of records failed, lost " + (FREEC + 1) + " records. Affected file: " + filename); // re-use record from free-list
// try to heal.. synchronized (entryFile) {
USEDC = USEDC + FREEC + 1; entryFile.seek(POS_USEDC); entryFile.writeInt(USEDC); USEDC++;
FREEC = 0; entryFile.seek(POS_FREEC); entryFile.writeInt(FREEC); entryFile.seek(POS_USEDC); entryFile.writeInt(USEDC);
index = USEDC - 1; FREEC--;
} else { entryFile.seek(POS_FREEC); entryFile.writeInt(FREEC);
index = FREEH.index; }
// read link to next element to FREEH chain // take link
entryFile.seek(seekpos(FREEH)); FREEH.index = entryFile.readInt(); if (FREEH.index == NUL) {
// write new FREEH link System.out.println("INTERNAL ERROR (DATA INCONSISTENCY): re-use of records failed, lost " + (FREEC + 1) + " records. Affected file: " + filename);
entryFile.seek(POS_FREEH); entryFile.writeInt(FREEH.index); // try to heal..
} synchronized (entryFile) {
} USEDC = USEDC + FREEC + 1;
} entryFile.seek(POS_USEDC); entryFile.writeInt(USEDC);
protected Handle(int index) { FREEC = 0;
this.index = index; entryFile.seek(POS_FREEC); entryFile.writeInt(FREEC);
} index = USEDC - 1;
public String toString() { }
if (index == NUL) return "NULL"; } else {
String s = Integer.toHexString(index); synchronized (entryFile) {
while (s.length() < 4) s = "0" + s; index = FREEH.index;
return s; // read link to next element to FREEH chain
} entryFile.seek(seekpos(FREEH)); FREEH.index = entryFile.readInt();
public boolean equals(Handle h) { // write new FREEH link
return (this.index == h.index); entryFile.seek(POS_FREEH); entryFile.writeInt(FREEH.index);
} }
}
}
}
}
protected Handle(int i) {
assert (i == NUL) || (i >= 0) : "node handle index too low: " + i;
assert (i == NUL) || (i < USEDC + FREEC) : "node handle index too high: " + i + ", USEDC=" + USEDC + ", FREEC=" + FREEC;
this.index = i;
}
public boolean isNUL() {
return index == NUL;
}
public String toString() {
if (index == NUL) return "NULL";
String s = Integer.toHexString(index);
while (s.length() < 4) s = "0" + s;
return s;
}
public boolean equals(Handle h) {
assert (index != NUL);
assert (h.index != NUL);
return (this.index == h.index);
}
public boolean equals(Object h) { public boolean equals(Object h) {
return (this.index == ((Handle) h).index); assert (index != NUL);
} assert (((Handle) h).index != NUL);
return (this.index == ((Handle) h).index);
}
public int compare(Object h0, Object h1) { public int compare(Object h0, Object h1) {
assert (((Handle) h0).index != NUL);
assert (((Handle) h1).index != NUL);
if (((Handle) h0).index < ((Handle) h1).index) return -1; if (((Handle) h0).index < ((Handle) h1).index) return -1;
if (((Handle) h0).index > ((Handle) h1).index) return 1; if (((Handle) h0).index > ((Handle) h1).index) return 1;
return 0; return 0;
} }
public int compareTo(Object h) { // this is needed for a treeMap compare
public int compareTo(Object h) {
// this is needed for a treeMap
assert (index != NUL);
assert (((Handle) h).index != NUL);
if (index < ((Handle) h).index) return -1; if (index < ((Handle) h).index) return -1;
if (index > ((Handle) h).index) return 1; if (index > ((Handle) h).index) return 1;
return 0; return 0;
} }
public int hashCode() { public int hashCode() {
assert (index != NUL);
return this.index; return this.index;
} }
} }

@ -133,7 +133,7 @@ public class kelondroTree extends kelondroRecords implements Comparator, kelondr
} }
// Returns the value to which this map maps the specified key. // Returns the value to which this map maps the specified key.
public synchronized byte[][] get(byte[] key) throws IOException { public byte[][] get(byte[] key) throws IOException {
//System.out.println("kelondroTree.get " + new String(key) + " in " + filename); //System.out.println("kelondroTree.get " + new String(key) + " in " + filename);
Search search = new Search(); Search search = new Search();
search.process(key); search.process(key);
@ -145,7 +145,7 @@ public class kelondroTree extends kelondroRecords implements Comparator, kelondr
} }
} }
public synchronized long[] getLong(byte[] key) throws IOException { public long[] getLong(byte[] key) throws IOException {
byte[][] row = get(key); byte[][] row = get(key);
long[] longs = new long[columns() - 1]; long[] longs = new long[columns() - 1];
if (row == null) { if (row == null) {
@ -1311,8 +1311,8 @@ public class kelondroTree extends kelondroRecords implements Comparator, kelondr
// Returns the comparator used to order this map, // Returns the comparator used to order this map,
// or null if this map uses its keys' natural order. // or null if this map uses its keys' natural order.
public synchronized Comparator comparator() { public Comparator comparator() {
return this; return this;
} }
public static void main(String[] args) { public static void main(String[] args) {

Loading…
Cancel
Save