@ -880,359 +880,7 @@ public class kelondroRecords {
System . out . print ( handle . index + ": " ) ;
for ( int j = 0 ; j < chunk . length ; j + + ) System . out . print ( chunk [ j ] + "," ) ;
}
/ *
public class Node {
// 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
// an Node object can be created in two ways:
// 1. instantiation with an index number. After creation the Object does not hold any
// value information until such is retrieved using the getValue() method
// 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
// time it is possible to verify the save state using the saved() predicate.
// Therefore an entry object has three modes:
// a: holding an index information only (saved() = true)
// b: holding value information only (saved() = false)
// 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:
// (i) created with index and after using the getValue() method, or
// (ii) created with values and after calling the save() method
// the method will therefore throw an IllegalStateException when the following
// process step is performed:
// - create the Node with index and call then the save() method
// this case can be decided with
// ((index != NUL) && (values == null))
// 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,
// but its parent/child keys.
private byte [ ] ohBytes = null ; // the overhead bytes, OHBYTEC values
private Handle [ ] ohHandle = null ; // the overhead handles, OHHANDLEC values
private byte [ ] [ ] values = null ; // an array of byte[] nodes is the value vector
private Handle handle = new Handle ( NUL ) ; // index of the entry, by default NUL means undefined
private Node ( ) {
// 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
// without the need to have content in it.
try {
this . handle = new Handle ( NUL ) ;
this . values = new byte [ COLWIDTHS . length ] [ ] ;
for ( int i = 0 ; i < COLWIDTHS . length ; i + + ) this . values [ i ] = null ;
this . ohBytes = null ;
this . ohHandle = null ;
save ( ) ;
} catch ( IOException e ) {
throw new kelondroException ( filename , "kelondro file out of space" ) ;
}
}
private Node ( byte [ ] [ ] v ) {
// this defines an entry, but it does not lead to writing these entry values to the file
// storing this entry can be done using the 'save()' command
if ( v = = null ) throw new IllegalArgumentException ( "Node values = NULL" ) ;
if ( ( v . length ! = COLWIDTHS . length ) | | ( v . length < 1 ) )
throw new IllegalArgumentException ( "Node value vector has wrong length" ) ;
this . values = v ;
this . handle = new Handle ( NUL ) ;
this . ohBytes = null ;
this . ohHandle = null ;
}
private Node ( Handle handle ) {
// this creates an entry with an pre-reserved entry position
// values can be written using the setValues() method
// but we expect that values are already there in the file ready to be read which we do not here
if ( handle = = null ) throw new IllegalArgumentException ( "INTERNAL ERROR: node handle is null." ) ;
if ( handle . index > USEDC + FREEC ) throw new kelondroException ( filename , "INTERNAL ERROR: node handle index exceeds size." ) ;
// set values and read node
this . values = null ;
this . handle . index = handle . index ;
this . ohBytes = null ;
this . ohHandle = null ;
}
private Node ( Handle handle , Node parentNode , int referenceInParent ) {
// this creates an entry with an pre-reserved entry position
// values can be written using the setValues() method
// but we expect that values are already there in the file ready to be read which we do not here
if ( handle = = null ) throw new IllegalArgumentException ( "INTERNAL ERROR: node handle is null." ) ;
// the parentNode can be given if an auto-fix in the following case is wanted
if ( handle . index > USEDC + FREEC ) {
if ( parentNode = = null ) {
throw new kelondroException ( filename , "INTERNAL ERROR: node handle index exceeds size. No auto-fix node was submitted. This is a serious failure." ) ;
} else {
try {
Handle [ ] handles = parentNode . getOHHandle ( ) ;
handles [ referenceInParent ] = null ;
parentNode . setOHHandle ( handles ) ;
throw new kelondroException ( filename , "INTERNAL ERROR: node handle index exceeds size. The bad node has been auto-fixed" ) ;
} catch ( IOException ee ) {
throw new kelondroException ( filename , "INTERNAL ERROR: node handle index exceeds size. It was tried to fix the bad node, but failed with an IOException: " + ee . getMessage ( ) ) ;
}
}
}
// set values and read node
this . values = null ;
this . handle . index = handle . index ;
this . ohBytes = null ;
this . ohHandle = null ;
}
public void finalize ( ) {
ohBytes = null ;
ohHandle = null ;
values = null ;
handle = null ;
}
protected Handle handle ( ) {
// if this entry has an index, return it
if ( this . handle . index = = NUL ) throw new kelondroException ( filename , "the entry has no index assigned" ) ;
return new Handle ( this . handle . index ) ;
}
protected void setOHByte ( byte [ ] b ) throws IOException {
if ( b = = null ) throw new IllegalArgumentException ( "setOHByte: setting null value does not make any sense" ) ;
if ( b . length ! = OHBYTEC ) throw new IllegalArgumentException ( "setOHByte: wrong array size" ) ;
if ( this . handle . index = = NUL ) throw new kelondroException ( filename , "setOHByte: no handle assigned" ) ;
if ( this . ohBytes = = null ) this . ohBytes = new byte [ OHBYTEC ] ;
synchronized ( entryFile ) {
entryFile . seek ( seekpos ( this . handle ) ) ;
for ( int j = 0 ; j < ohBytes . length ; j + + ) {
ohBytes [ j ] = b [ j ] ;
entryFile . writeByte ( b [ j ] ) ;
}
}
updateNodeCache ( ) ;
}
protected void setOHHandle ( Handle [ ] i ) throws IOException {
if ( i = = null ) throw new IllegalArgumentException ( "setOHint: setting null value does not make any sense" ) ;
if ( i . length ! = OHHANDLEC ) throw new IllegalArgumentException ( "setOHHandle: wrong array size" ) ;
if ( this . handle . index = = NUL ) throw new kelondroException ( filename , "setOHHandle: no handle assigned" ) ;
if ( this . ohHandle = = null ) this . ohHandle = new Handle [ OHHANDLEC ] ;
synchronized ( entryFile ) {
entryFile . seek ( seekpos ( this . handle ) + OHBYTEC ) ;
for ( int j = 0 ; j < ohHandle . length ; j + + ) {
ohHandle [ j ] = i [ j ] ;
if ( i [ j ] = = null )
entryFile . writeInt ( NUL ) ;
else
entryFile . writeInt ( i [ j ] . index ) ;
}
}
updateNodeCache ( ) ;
}
protected byte [ ] getOHByte ( ) throws IOException {
if ( ohBytes = = null ) {
if ( this . handle . index = = NUL ) throw new kelondroException ( filename , "Cannot load OH values" ) ;
ohBytes = new byte [ OHBYTEC ] ;
synchronized ( entryFile ) {
entryFile . seek ( seekpos ( this . handle ) ) ;
for ( int j = 0 ; j < ohBytes . length ; j + + ) {
ohBytes [ j ] = entryFile . readByte ( ) ;
}
}
}
return ohBytes ;
}
protected Handle [ ] getOHHandle ( ) throws IOException {
if ( ohHandle = = null ) {
if ( this . handle . index = = NUL ) throw new kelondroException ( filename , "Cannot load OH values" ) ;
ohHandle = new Handle [ OHHANDLEC ] ;
synchronized ( entryFile ) {
entryFile . seek ( seekpos ( this . handle ) + OHBYTEC ) ;
int i ;
for ( int j = 0 ; j < ohHandle . length ; j + + ) {
i = entryFile . readInt ( ) ;
ohHandle [ j ] = ( i = = NUL ) ? null : new Handle ( i ) ;
}
}
}
return ohHandle ;
}
public byte [ ] [ ] setValues ( byte [ ] [ ] row ) throws IOException {
// 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)
if ( this . values = = null ) this . values = new byte [ COLWIDTHS . length ] [ ] ;
for ( int i = 0 ; i < values . length ; i + + ) {
this . values [ i ] = row [ i ] ;
}
if ( this . handle . index ! = NUL ) {
// store data directly to database
synchronized ( entryFile ) {
long seek = seekpos ( this . handle ) + overhead ;
for ( int i = 0 ; i < values . length ; i + + ) {
entryFile . seek ( seek ) ;
if ( values [ i ] = = null ) {
for ( int j = 0 ; j < COLWIDTHS [ i ] ; j + + )
entryFile . writeByte ( 0 ) ;
} else if ( values [ i ] . length > = COLWIDTHS [ i ] ) {
entryFile . write ( values [ i ] , 0 , COLWIDTHS [ i ] ) ;
} else {
entryFile . write ( values [ i ] ) ;
for ( int j = values [ i ] . length ; j < COLWIDTHS [ i ] ; j + + )
entryFile . writeByte ( 0 ) ;
}
seek + = COLWIDTHS [ i ] ;
}
}
updateNodeCache ( ) ;
}
//System.out.print("setValues result: "); for (int i = 0; i < values.length; i++) System.out.print(new String(result[i]) + " "); System.out.println(".");
return result ; // return previous value
}
public byte [ ] getKey ( ) throws IOException {
if ( ( values = = null ) | | ( values [ 0 ] = = null ) ) {
// load from database, but ONLY the key!
if ( this . handle . index = = NUL ) {
throw new kelondroException ( filename , "Cannot load Key" ) ;
} else {
values = new byte [ COLWIDTHS . length ] [ ] ;
values [ 0 ] = new byte [ COLWIDTHS [ 0 ] ] ;
synchronized ( entryFile ) {
entryFile . seek ( seekpos ( this . handle ) + overhead ) ;
entryFile . read ( values [ 0 ] , 0 , values [ 0 ] . length ) ;
}
for ( int i = 1 ; i < COLWIDTHS . length ; i + + ) values [ i ] = null ;
return values [ 0 ] ;
}
} else {
return values [ 0 ] ;
}
}
public byte [ ] [ ] getValues ( ) throws IOException {
if ( ( values = = null ) | | ( values [ 0 ] = = null ) ) {
// load ALL values from database
if ( this . handle . index = = NUL ) {
throw new kelondroException ( filename , "Cannot load values" ) ;
} else {
values = new byte [ COLWIDTHS . length ] [ ] ;
synchronized ( entryFile ) {
long seek = seekpos ( this . handle ) + overhead ;
for ( int i = 0 ; i < COLWIDTHS . length ; i + + ) {
entryFile . seek ( seek ) ;
values [ i ] = new byte [ COLWIDTHS [ i ] ] ;
entryFile . read ( values [ i ] , 0 , values [ i ] . length ) ;
if ( allZero ( values [ i ] ) ) values [ i ] = null ;
seek + = COLWIDTHS [ i ] ;
}
}
return values ;
}
} else if ( ( values . length > 1 ) & & ( values [ 1 ] = = null ) ) {
// only the key has been read; load the remaining
synchronized ( entryFile ) {
long seek = seekpos ( this . handle ) + overhead + COLWIDTHS [ 0 ] ;
for ( int i = 1 ; i < COLWIDTHS . length ; i + + ) {
entryFile . seek ( seek ) ;
values [ i ] = new byte [ COLWIDTHS [ i ] ] ;
entryFile . read ( values [ i ] , 0 , values [ i ] . length ) ;
if ( allZero ( values [ i ] ) ) values [ i ] = null ;
seek + = COLWIDTHS [ i ] ;
}
}
return values ;
} else {
return values ;
}
}
protected synchronized void save ( ) throws IOException {
// this is called when an entry was defined with values only and not by retrieving with an index
// if this happens, nothing of the internal array values have been written to the file
// then writing to the file is done here
// can only be called if the index has not been defined yet
if ( this . handle . index ! = NUL ) {
throw new kelondroException ( filename , "double assignement of handles" ) ;
}
// create new index by expanding the file at the end
// or by recycling used records
this . handle = new Handle ( ) ;
// place the data to the file
//if ((values == null) || ((values != null) && (values.length > 1) && (values[1] == null))) {
if ( values = = null ) {
// there is nothing to save
throw new kelondroException ( filename , "no values to save" ) ;
}
entryFile . seek ( seekpos ( this . handle ) ) ;
if ( ohBytes = = null ) { for ( int i = 0 ; i < OHBYTEC ; i + + ) entryFile . writeByte ( 0 ) ; }
else { for ( int i = 0 ; i < OHBYTEC ; i + + ) entryFile . writeByte ( ohBytes [ i ] ) ; }
if ( ohHandle = = null ) { for ( int i = 0 ; i < OHHANDLEC ; i + + ) entryFile . writeInt ( 0 ) ; }
else { for ( int i = 0 ; i < OHHANDLEC ; i + + ) entryFile . writeInt ( ohHandle [ i ] . index ) ; }
long seek = seekpos ( this . handle ) + overhead ;
for ( int i = 0 ; i < values . length ; i + + ) {
entryFile . seek ( seek ) ;
if ( values [ i ] = = null ) {
for ( int j = 0 ; j < COLWIDTHS [ i ] ; j + + ) entryFile . writeByte ( 0 ) ;
} else if ( values [ i ] . length > = COLWIDTHS [ i ] ) {
entryFile . write ( values [ i ] , 0 , COLWIDTHS [ i ] ) ;
} else {
entryFile . write ( values [ i ] ) ;
for ( int j = values [ i ] . length ; j < COLWIDTHS [ i ] ; j + + ) entryFile . writeByte ( 0 ) ;
}
seek = seek + COLWIDTHS [ i ] ;
}
}
private boolean allZero ( byte [ ] a ) {
for ( int i = 0 ; i < a . length ; i + + ) if ( a [ i ] ! = 0 ) return false ;
return true ;
}
public String toString ( ) {
if ( this . handle . index = = NUL ) return "NULL" ;
String s = Integer . toHexString ( this . handle . index ) ;
while ( s . length ( ) < 4 ) s = "0" + s ;
try {
byte [ ] b = getOHByte ( ) ;
for ( int i = 0 ; i < b . length ; i + + ) s = s + ":b" + b [ i ] ;
Handle [ ] h = getOHHandle ( ) ;
for ( int i = 0 ; i < h . length ; i + + ) if ( h [ i ] = = null ) s = s + ":hNULL" ; else s = s + ":h" + h [ i ] . toString ( ) ;
byte [ ] [ ] content = getValues ( ) ;
for ( int i = 0 ; i < content . length ; i + + ) s = s + ":" + ( new String ( content [ i ] ) ) . trim ( ) ;
} catch ( IOException e ) {
s = s + ":***LOAD ERROR***:" + e . getMessage ( ) ;
}
return s ;
}
private void updateNodeCache ( ) {
if ( this . handle = = null ) return ;
if ( this . values = = null ) return ;
if ( this . ohBytes = = null ) return ;
if ( this . ohHandle = = null ) return ;
if ( XcacheSize ! = 0 ) {
synchronized ( XcacheHeaders ) {
// remember size to evaluate a cache size check need
int sizeBefore = XcacheHeaders . size ( ) ;
//long memBefore = Runtime.getRuntime().freeMemory();
// generate cache entry
byte [ ] [ ] cacheValue ;
if ( values = = null ) {
cacheValue = null ;
} else {
cacheValue = new byte [ values . length ] [ ] ;
cacheValue [ 0 ] = values [ 0 ] ;
for ( int i = 1 ; i < values . length ; i + + ) cacheValue [ i ] = null ;
}
Node cacheNode = new Node ( cacheValue ) ;
cacheNode . handle = this . handle ;
cacheNode . ohBytes = this . ohBytes ;
cacheNode . ohHandle = this . ohHandle ;
// store the cache entry
boolean newentry = XcacheHeaders . put ( cacheNode . handle , cacheNode ) = = null ;
XcacheScore . setScore ( cacheNode . handle , ( int ) ( ( System . currentTimeMillis ( ) - XcacheStartup ) / 1000 ) ) ;
// delete the cache entry
cacheNode = null ;
//System.out.println("kelondroRecords cache4" + filename + ": cache record size = " + (memBefore - Runtime.getRuntime().freeMemory()) + " bytes" + ((newentry) ? " new" : ""));
// check cache size
if ( XcacheHeaders . size ( ) > sizeBefore ) checkCacheSpace ( ) ;
//System.out.println("kelondroRecords cache4" + filename + ": " + XcacheHeaders.size() + " entries, " + XcacheSize + " allowed.");
}
}
}
}
* /
public synchronized int columns ( ) {
return this . COLWIDTHS . length ;
}