@ -80,21 +80,21 @@ public class HeapReader {
this . file = new CachedFileWriter ( this . heapFile ) ;
this . file = new CachedFileWriter ( this . heapFile ) ;
// read or initialize the index
// read or initialize the index
fingerprintFileIdx = null ;
this . fingerprintFileIdx = null ;
fingerprintFileGap = null ;
this . fingerprintFileGap = null ;
if ( initIndexReadDump ( ) ) {
if ( initIndexReadDump ( ) ) {
// verify that everything worked just fine
// verify that everything worked just fine
// pick some elements of the index
// pick some elements of the index
Iterator < byte [ ] > i = this . index . keys ( true , null ) ;
Iterator < byte [ ] > i = this . index . keys ( true , null ) ;
int c = 3 ;
int c = 3 ;
byte [ ] b , b1 = new byte [ index. row ( ) . primaryKeyLength ] ;
byte [ ] b , b1 = new byte [ this . index. row ( ) . primaryKeyLength ] ;
long pos ;
long pos ;
boolean ok = true ;
boolean ok = true ;
while ( i . hasNext ( ) & & c - - > 0 ) {
while ( i . hasNext ( ) & & c - - > 0 ) {
b = i . next ( ) ;
b = i . next ( ) ;
pos = this . index . get ( b ) ;
pos = this . index . get ( b ) ;
file. seek ( pos + 4 ) ;
this . file. seek ( pos + 4 ) ;
file. readFully ( b1 , 0 , b1 . length ) ;
this . file. readFully ( b1 , 0 , b1 . length ) ;
if ( ! this . ordering . equal ( b , b1 ) ) {
if ( ! this . ordering . equal ( b , b1 ) ) {
ok = false ;
ok = false ;
break ;
break ;
@ -122,7 +122,7 @@ public class HeapReader {
}
}
public long mem ( ) {
public long mem ( ) {
return index. mem ( ) ; // don't add the memory for free here since then the asserts for memory management don't work
return this . index. mem ( ) ; // don't add the memory for free here since then the asserts for memory management don't work
}
}
public void trim ( ) {
public void trim ( ) {
@ -181,7 +181,7 @@ public class HeapReader {
// check saturation
// check saturation
int [ ] saturation = this . index . saturation ( ) ;
int [ ] saturation = this . index . saturation ( ) ;
Log . logInfo ( "HeapReader" , "saturation of " + this . fingerprintFileIdx . getName ( ) + ": keylength = " + saturation [ 0 ] + ", vallength = " + saturation [ 1 ] + ", possible saving: " + ( ( this . keylength - saturation [ 0 ] + 8 - saturation [ 1 ] ) * index. size ( ) / 1024 / 1024 ) + " MB" ) ;
Log . logInfo ( "HeapReader" , "saturation of " + this . fingerprintFileIdx . getName ( ) + ": keylength = " + saturation [ 0 ] + ", vallength = " + saturation [ 1 ] + ", possible saving: " + ( ( this . keylength - saturation [ 0 ] + 8 - saturation [ 1 ] ) * this . index. size ( ) / 1024 / 1024 ) + " MB" ) ;
// read the gap file:
// read the gap file:
try {
try {
@ -239,31 +239,32 @@ public class HeapReader {
private void initIndexReadFromHeap ( ) throws IOException {
private void initIndexReadFromHeap ( ) throws IOException {
// this initializes the this.index object by reading positions from the heap file
// this initializes the this.index object by reading positions from the heap file
Log . logInfo ( "HeapReader" , "generating index for " + heapFile. toString ( ) + ", " + ( file. length ( ) / 1024 / 1024 ) + " MB. Please wait." ) ;
Log . logInfo ( "HeapReader" , "generating index for " + this . heapFile. toString ( ) + ", " + ( this . file. length ( ) / 1024 / 1024 ) + " MB. Please wait." ) ;
this . free = new Gap ( ) ;
this . free = new Gap ( ) ;
HandleMap . initDataConsumer indexready = HandleMap . asynchronusInitializer ( this . name ( ) + ".initializer" , keylength, this . ordering , 8 , Math . max ( 10 , ( int ) ( Runtime . getRuntime ( ) . freeMemory ( ) / ( 10 * 1024 * 1024 ) ) ) ) ;
HandleMap . initDataConsumer indexready = HandleMap . asynchronusInitializer ( this . name ( ) + ".initializer" , this . keylength, this . ordering , 8 , Math . max ( 10 , ( int ) ( Runtime . getRuntime ( ) . freeMemory ( ) / ( 10 * 1024 * 1024 ) ) ) ) ;
byte [ ] key = new byte [ keylength] ;
byte [ ] key = new byte [ this . keylength] ;
int reclen ;
int reclen ;
long seek = 0 ;
long seek = 0 ;
if ( this . file . length ( ) > 0 ) {
loop : while ( true ) { // don't test available() here because this does not work for files > 2GB
loop : while ( true ) { // don't test available() here because this does not work for files > 2GB
try {
try {
// go to seek position
// go to seek position
file. seek ( seek ) ;
this . file. seek ( seek ) ;
// read length of the following record without the length of the record size bytes
// read length of the following record without the length of the record size bytes
reclen = file. readInt ( ) ;
reclen = this . file. readInt ( ) ;
//assert reclen > 0 : " reclen == 0 at seek pos " + seek;
//assert reclen > 0 : " reclen == 0 at seek pos " + seek;
if ( reclen = = 0 ) {
if ( reclen = = 0 ) {
// very bad file inconsistency
// very bad file inconsistency
Log . logSevere ( "HeapReader" , "reclen == 0 at seek pos " + seek + " in file " + heapFile) ;
Log . logSevere ( "HeapReader" , "reclen == 0 at seek pos " + seek + " in file " + this . heapFile) ;
this . file . setLength ( seek ) ; // delete everything else at the remaining of the file :-(
this . file . setLength ( seek ) ; // delete everything else at the remaining of the file :-(
break loop ;
break loop ;
}
}
// read key
// read key
file. readFully ( key , 0 , key . length ) ;
this . file. readFully ( key , 0 , key . length ) ;
} catch ( final IOException e ) {
} catch ( final IOException e ) {
// EOF reached
// EOF reached
@ -273,23 +274,24 @@ public class HeapReader {
// check if this record is empty
// check if this record is empty
if ( key = = null | | key [ 0 ] = = 0 ) {
if ( key = = null | | key [ 0 ] = = 0 ) {
// it is an empty record, store to free list
// it is an empty record, store to free list
if ( reclen > 0 ) free. put ( seek , reclen ) ;
if ( reclen > 0 ) this . free. put ( seek , reclen ) ;
} else {
} else {
if ( this . ordering . wellformed ( key ) ) {
if ( this . ordering . wellformed ( key ) ) {
indexready . consume ( key , seek ) ;
indexready . consume ( key , seek ) ;
key = new byte [ keylength] ;
key = new byte [ this . keylength] ;
} else {
} else {
// free the lost space
// free the lost space
free. put ( seek , reclen ) ;
this . free. put ( seek , reclen ) ;
file. seek ( seek + 4 ) ;
this . file. seek ( seek + 4 ) ;
Arrays . fill ( key , ( byte ) 0 ) ;
Arrays . fill ( key , ( byte ) 0 ) ;
file. write ( key ) ; // mark the place as empty record
this . file. write ( key ) ; // mark the place as empty record
Log . logWarning ( "HeapReader" , "BLOB " + heapFile. getName ( ) + ": skiped not wellformed key " + UTF8 . String ( key ) + " at seek pos " + seek ) ;
Log . logWarning ( "HeapReader" , "BLOB " + this . heapFile. getName ( ) + ": skiped not wellformed key " + UTF8 . String ( key ) + " at seek pos " + seek ) ;
}
}
}
}
// new seek position
// new seek position
seek + = 4L + reclen ;
seek + = 4L + reclen ;
}
}
}
indexready . finish ( ) ;
indexready . finish ( ) ;
// finish the index generation
// finish the index generation
@ -300,13 +302,13 @@ public class HeapReader {
} catch ( ExecutionException e ) {
} catch ( ExecutionException e ) {
Log . logException ( e ) ;
Log . logException ( e ) ;
}
}
Log . logInfo ( "HeapReader" , "finished index generation for " + heapFile . toString ( ) + ", " + index . size ( ) + " entries, " + free. size ( ) + " gaps." ) ;
Log . logInfo ( "HeapReader" , "finished index generation for " + this . heapFile . toString ( ) + ", " + this . index . size ( ) + " entries, " + this . free. size ( ) + " gaps." ) ;
}
}
private void mergeFreeEntries ( ) throws IOException {
private void mergeFreeEntries ( ) throws IOException {
// try to merge free entries
// try to merge free entries
if ( free. size ( ) > 1 ) {
if ( this . free. size ( ) > 1 ) {
int merged = 0 ;
int merged = 0 ;
Map . Entry < Long , Integer > lastFree , nextFree ;
Map . Entry < Long , Integer > lastFree , nextFree ;
final Iterator < Map . Entry < Long , Integer > > i = this . free . entrySet ( ) . iterator ( ) ;
final Iterator < Map . Entry < Long , Integer > > i = this . free . entrySet ( ) . iterator ( ) ;
@ -328,7 +330,7 @@ public class HeapReader {
lastFree = nextFree ;
lastFree = nextFree ;
}
}
}
}
Log . logInfo ( "HeapReader" , "BLOB " + heapFile. toString ( ) + ": merged " + merged + " free records" ) ;
Log . logInfo ( "HeapReader" , "BLOB " + this . heapFile. toString ( ) + ": merged " + merged + " free records" ) ;
if ( merged > 0 ) deleteFingerprint ( ) ;
if ( merged > 0 ) deleteFingerprint ( ) ;
}
}
}
}
@ -347,14 +349,14 @@ public class HeapReader {
* /
* /
public int size ( ) {
public int size ( ) {
if ( this . index = = null ) return 0 ;
if ( this . index = = null ) return 0 ;
synchronized ( index) {
synchronized ( this . index) {
return ( this . index = = null ) ? 0 : this . index . size ( ) ;
return ( this . index = = null ) ? 0 : this . index . size ( ) ;
}
}
}
}
public boolean isEmpty ( ) {
public boolean isEmpty ( ) {
if ( this . index = = null ) return true ;
if ( this . index = = null ) return true ;
synchronized ( index) {
synchronized ( this . index) {
return this . index . isEmpty ( ) ;
return this . index . isEmpty ( ) ;
}
}
}
}
@ -365,12 +367,12 @@ public class HeapReader {
* @return true if the key exists , false otherwise
* @return true if the key exists , false otherwise
* /
* /
public boolean containsKey ( byte [ ] key ) {
public boolean containsKey ( byte [ ] key ) {
assert index ! = null ;
assert this . index ! = null ;
key = normalizeKey ( key ) ;
key = normalizeKey ( key ) ;
synchronized ( this . index ) {
synchronized ( this . index ) {
// check if the file index contains the key
// check if the file index contains the key
return index. get ( key ) > = 0 ;
return this . index. get ( key ) > = 0 ;
}
}
}
}
@ -387,7 +389,7 @@ public class HeapReader {
* /
* /
protected synchronized byte [ ] firstKey ( ) throws IOException {
protected synchronized byte [ ] firstKey ( ) throws IOException {
synchronized ( this . index ) {
synchronized ( this . index ) {
return index. smallestKey ( ) ;
return this . index. smallestKey ( ) ;
}
}
}
}
@ -400,7 +402,7 @@ public class HeapReader {
* /
* /
protected byte [ ] first ( ) throws IOException , RowSpaceExceededException {
protected byte [ ] first ( ) throws IOException , RowSpaceExceededException {
synchronized ( this . index ) {
synchronized ( this . index ) {
byte [ ] key = index. smallestKey ( ) ;
byte [ ] key = this . index. smallestKey ( ) ;
if ( key = = null ) return null ;
if ( key = = null ) return null ;
return get ( key ) ;
return get ( key ) ;
}
}
@ -415,7 +417,7 @@ public class HeapReader {
* /
* /
protected byte [ ] lastKey ( ) throws IOException {
protected byte [ ] lastKey ( ) throws IOException {
synchronized ( this . index ) {
synchronized ( this . index ) {
return index. largestKey ( ) ;
return this . index. largestKey ( ) ;
}
}
}
}
@ -428,7 +430,7 @@ public class HeapReader {
* /
* /
protected byte [ ] last ( ) throws IOException , RowSpaceExceededException {
protected byte [ ] last ( ) throws IOException , RowSpaceExceededException {
synchronized ( this . index ) {
synchronized ( this . index ) {
byte [ ] key = index. largestKey ( ) ;
byte [ ] key = this . index. largestKey ( ) ;
if ( key = = null ) return null ;
if ( key = = null ) return null ;
return get ( key ) ;
return get ( key ) ;
}
}
@ -446,20 +448,20 @@ public class HeapReader {
synchronized ( this . index ) {
synchronized ( this . index ) {
// check if the index contains the key
// check if the index contains the key
final long pos = index. get ( key ) ;
final long pos = this . index. get ( key ) ;
if ( pos < 0 ) return null ;
if ( pos < 0 ) return null ;
// access the file and read the container
// access the file and read the container
file. seek ( pos ) ;
this . file. seek ( pos ) ;
final int len = file . readInt ( ) - index. row ( ) . primaryKeyLength ;
final int len = this . file . readInt ( ) - this . index. row ( ) . primaryKeyLength ;
if ( len < 0 ) {
if ( len < 0 ) {
// database file may be corrupted and should be deleted :-((
// database file may be corrupted and should be deleted :-((
Log . logSevere ( "HeapReader" , "file " + file. file ( ) + " corrupted at " + pos + ": negative len. len = " + len + ", pk.len = " + index. row ( ) . primaryKeyLength ) ;
Log . logSevere ( "HeapReader" , "file " + this . file. file ( ) + " corrupted at " + pos + ": negative len. len = " + len + ", pk.len = " + this . index. row ( ) . primaryKeyLength ) ;
// to get lazy over that problem (who wants to tell the user to stop operation and delete the file???) we work on like the entry does not exist
// to get lazy over that problem (who wants to tell the user to stop operation and delete the file???) we work on like the entry does not exist
index. remove ( key ) ;
this . index. remove ( key ) ;
return null ;
return null ;
}
}
long memr = len + index. row ( ) . primaryKeyLength + 64 ;
long memr = len + this . index. row ( ) . primaryKeyLength + 64 ;
if ( MemoryControl . available ( ) < memr ) {
if ( MemoryControl . available ( ) < memr ) {
if ( ! MemoryControl . request ( memr , true ) ) throw new RowSpaceExceededException ( memr , "HeapReader.get()/check" ) ; // not enough memory available for this blob
if ( ! MemoryControl . request ( memr , true ) ) throw new RowSpaceExceededException ( memr , "HeapReader.get()/check" ) ; // not enough memory available for this blob
}
}
@ -467,17 +469,17 @@ public class HeapReader {
// read the key
// read the key
byte [ ] keyf ;
byte [ ] keyf ;
try {
try {
keyf = new byte [ index. row ( ) . primaryKeyLength ] ;
keyf = new byte [ this . index. row ( ) . primaryKeyLength ] ;
} catch ( OutOfMemoryError e ) {
} catch ( OutOfMemoryError e ) {
throw new RowSpaceExceededException ( index. row ( ) . primaryKeyLength , "HeapReader.get()/keyf" ) ;
throw new RowSpaceExceededException ( this . index. row ( ) . primaryKeyLength , "HeapReader.get()/keyf" ) ;
}
}
file. readFully ( keyf , 0 , keyf . length ) ;
this . file. readFully ( keyf , 0 , keyf . length ) ;
if ( ! this . ordering . equal ( key , keyf ) ) {
if ( ! this . ordering . equal ( key , keyf ) ) {
// verification of the indexed access failed. we must re-read the index
// verification of the indexed access failed. we must re-read the index
Log . logSevere ( "HeapReader" , "indexed verification access failed for " + heapFile. toString ( ) ) ;
Log . logSevere ( "HeapReader" , "indexed verification access failed for " + this . heapFile. toString ( ) ) ;
// this is a severe operation, it should never happen.
// this is a severe operation, it should never happen.
// remove entry from index because keeping that element in the index would not make sense
// remove entry from index because keeping that element in the index would not make sense
index. remove ( key ) ;
this . index. remove ( key ) ;
// nothing to return
// nothing to return
return null ;
return null ;
// but if the process ends in this state, it would completely fail
// but if the process ends in this state, it would completely fail
@ -492,7 +494,7 @@ public class HeapReader {
} catch ( OutOfMemoryError e ) {
} catch ( OutOfMemoryError e ) {
throw new RowSpaceExceededException ( len , "HeapReader.get()/blob" ) ;
throw new RowSpaceExceededException ( len , "HeapReader.get()/blob" ) ;
}
}
file. readFully ( blob , 0 , blob . length ) ;
this . file. readFully ( blob , 0 , blob . length ) ;
return blob ;
return blob ;
}
}
@ -512,12 +514,12 @@ public class HeapReader {
protected boolean checkKey ( byte [ ] key , final long pos ) throws IOException {
protected boolean checkKey ( byte [ ] key , final long pos ) throws IOException {
key = normalizeKey ( key ) ;
key = normalizeKey ( key ) ;
file. seek ( pos ) ;
this . file. seek ( pos ) ;
file. readInt ( ) ; // skip the size value
this . file. readInt ( ) ; // skip the size value
// read the key
// read the key
final byte [ ] keyf = new byte [ index. row ( ) . primaryKeyLength ] ;
final byte [ ] keyf = new byte [ this . index. row ( ) . primaryKeyLength ] ;
file. readFully ( keyf , 0 , keyf . length ) ;
this . file. readFully ( keyf , 0 , keyf . length ) ;
return this . ordering . equal ( key , keyf ) ;
return this . ordering . equal ( key , keyf ) ;
}
}
@ -532,12 +534,12 @@ public class HeapReader {
synchronized ( this . index ) {
synchronized ( this . index ) {
// check if the index contains the key
// check if the index contains the key
final long pos = index. get ( key ) ;
final long pos = this . index. get ( key ) ;
if ( pos < 0 ) return - 1 ;
if ( pos < 0 ) return - 1 ;
// access the file and read the size of the container
// access the file and read the size of the container
file. seek ( pos ) ;
this . file. seek ( pos ) ;
return file . readInt ( ) - index. row ( ) . primaryKeyLength ;
return this . file . readInt ( ) - this . index. row ( ) . primaryKeyLength ;
}
}
}
}
@ -546,20 +548,20 @@ public class HeapReader {
* /
* /
public void close ( boolean writeIDX ) {
public void close ( boolean writeIDX ) {
synchronized ( this . index ) {
synchronized ( this . index ) {
if ( file ! = null )
if ( this . file ! = null )
try {
try {
file. close ( ) ;
this . file. close ( ) ;
} catch ( IOException e ) {
} catch ( IOException e ) {
Log . logException ( e ) ;
Log . logException ( e ) ;
}
}
file = null ;
this . file = null ;
if ( writeIDX & & index ! = null & & free ! = null & & ( index . size ( ) > 3 | | free. size ( ) > 3 ) ) {
if ( writeIDX & & this . index ! = null & & this . free ! = null & & ( this . index . size ( ) > 3 | | this . free. size ( ) > 3 ) ) {
// now we can create a dump of the index and the gap information
// now we can create a dump of the index and the gap information
// to speed up the next start
// to speed up the next start
try {
try {
String fingerprint = fingerprintFileHash ( this . heapFile ) ;
String fingerprint = fingerprintFileHash ( this . heapFile ) ;
if ( fingerprint = = null ) {
if ( fingerprint = = null ) {
Log . logSevere ( "HeapReader" , "cannot write a dump for " + heapFile. getName ( ) + ": fingerprint is null" ) ;
Log . logSevere ( "HeapReader" , "cannot write a dump for " + this . heapFile. getName ( ) + ": fingerprint is null" ) ;
} else {
} else {
File newFingerprintFileGap = HeapWriter . fingerprintGapFile ( this . heapFile , fingerprint ) ;
File newFingerprintFileGap = HeapWriter . fingerprintGapFile ( this . heapFile , fingerprint ) ;
if ( this . fingerprintFileGap ! = null & &
if ( this . fingerprintFileGap ! = null & &
@ -568,12 +570,12 @@ public class HeapReader {
Log . logInfo ( "HeapReader" , "using existing gap dump instead of writing a new one: " + this . fingerprintFileGap . getName ( ) ) ;
Log . logInfo ( "HeapReader" , "using existing gap dump instead of writing a new one: " + this . fingerprintFileGap . getName ( ) ) ;
} else {
} else {
long start = System . currentTimeMillis ( ) ;
long start = System . currentTimeMillis ( ) ;
free. dump ( newFingerprintFileGap ) ;
this . free. dump ( newFingerprintFileGap ) ;
Log . logInfo ( "HeapReader" , "wrote a dump for the " + this . free . size ( ) + " gap entries of " + heapFile. getName ( ) + " in " + ( System . currentTimeMillis ( ) - start ) + " milliseconds." ) ;
Log . logInfo ( "HeapReader" , "wrote a dump for the " + this . free . size ( ) + " gap entries of " + this . heapFile. getName ( ) + " in " + ( System . currentTimeMillis ( ) - start ) + " milliseconds." ) ;
}
}
}
}
free. clear ( ) ;
this . free. clear ( ) ;
free = null ;
this . free = null ;
if ( fingerprint ! = null ) {
if ( fingerprint ! = null ) {
File newFingerprintFileIdx = HeapWriter . fingerprintIndexFile ( this . heapFile , fingerprint ) ;
File newFingerprintFileIdx = HeapWriter . fingerprintIndexFile ( this . heapFile , fingerprint ) ;
if ( this . fingerprintFileIdx ! = null & &
if ( this . fingerprintFileIdx ! = null & &
@ -582,20 +584,20 @@ public class HeapReader {
Log . logInfo ( "HeapReader" , "using existing idx dump instead of writing a new one: " + this . fingerprintFileIdx . getName ( ) ) ;
Log . logInfo ( "HeapReader" , "using existing idx dump instead of writing a new one: " + this . fingerprintFileIdx . getName ( ) ) ;
} else {
} else {
long start = System . currentTimeMillis ( ) ;
long start = System . currentTimeMillis ( ) ;
index. dump ( newFingerprintFileIdx ) ;
this . index. dump ( newFingerprintFileIdx ) ;
Log . logInfo ( "HeapReader" , "wrote a dump for the " + this . index . size ( ) + " index entries of " + heapFile. getName ( ) + " in " + ( System . currentTimeMillis ( ) - start ) + " milliseconds." ) ;
Log . logInfo ( "HeapReader" , "wrote a dump for the " + this . index . size ( ) + " index entries of " + this . heapFile. getName ( ) + " in " + ( System . currentTimeMillis ( ) - start ) + " milliseconds." ) ;
}
}
}
}
index. close ( ) ;
this . index. close ( ) ;
index = null ;
this . index = null ;
} catch ( IOException e ) {
} catch ( IOException e ) {
Log . logException ( e ) ;
Log . logException ( e ) ;
}
}
}
}
if ( free ! = null ) free. clear ( ) ;
if ( this . free ! = null ) this . free. clear ( ) ;
free = null ;
this . free = null ;
if ( index ! = null ) index. close ( ) ;
if ( this . index ! = null ) this . index. close ( ) ;
index = null ;
this . index = null ;
}
}
}
}
@ -672,18 +674,20 @@ public class HeapReader {
this . blobFile = blobFile ;
this . blobFile = blobFile ;
}
}
@Override
public CloneableIterator < Entry < byte [ ] , byte [ ] > > clone ( Object modifier ) {
public CloneableIterator < Entry < byte [ ] , byte [ ] > > clone ( Object modifier ) {
// if the entries iterator is cloned, close the file!
// if the entries iterator is cloned, close the file!
if ( is ! = null ) try { is. close ( ) ; } catch ( final IOException e ) { }
if ( this . is ! = null ) try { this . is. close ( ) ; } catch ( final IOException e ) { }
is = null ;
this . is = null ;
try {
try {
return new entries ( blobFile , keylen) ;
return new entries ( this . blobFile , this . keylen) ;
} catch ( IOException e ) {
} catch ( IOException e ) {
Log . logException ( e ) ;
Log . logException ( e ) ;
return null ;
return null ;
}
}
}
}
@Override
public Map . Entry < byte [ ] , byte [ ] > next0 ( ) {
public Map . Entry < byte [ ] , byte [ ] > next0 ( ) {
try {
try {
byte b ;
byte b ;
@ -692,14 +696,14 @@ public class HeapReader {
byte [ ] key ;
byte [ ] key ;
final int keylen1 = this . keylen - 1 ;
final int keylen1 = this . keylen - 1 ;
while ( true ) {
while ( true ) {
len = is. readInt ( ) ;
len = this . is. readInt ( ) ;
if ( len = = 0 ) continue ; // rare, but possible: zero length record (takes 4 bytes)
if ( len = = 0 ) continue ; // rare, but possible: zero length record (takes 4 bytes)
b = is. readByte ( ) ; // read a single by te to check for empty record
b = this . is. readByte ( ) ; // read a single by te to check for empty record
if ( b = = 0 ) {
if ( b = = 0 ) {
// this is empty
// this is empty
// read some more bytes to consume the empty record
// read some more bytes to consume the empty record
if ( len > 1 ) {
if ( len > 1 ) {
if ( len - 1 ! = is. skipBytes ( len - 1 ) ) { // all that is remaining
if ( len - 1 ! = this . is. skipBytes ( len - 1 ) ) { // all that is remaining
Log . logWarning ( "HeapReader" , "problem skiping " + + len + " bytes in " + this . blobFile . getName ( ) ) ;
Log . logWarning ( "HeapReader" , "problem skiping " + + len + " bytes in " + this . blobFile . getName ( ) ) ;
return null ;
return null ;
}
}
@ -709,13 +713,13 @@ public class HeapReader {
// we are now ahead of remaining this.keylen - 1 bytes of the key
// we are now ahead of remaining this.keylen - 1 bytes of the key
key = new byte [ this . keylen ] ;
key = new byte [ this . keylen ] ;
key [ 0 ] = b ; // the first entry that we know already
key [ 0 ] = b ; // the first entry that we know already
if ( is. read ( key , 1 , keylen1 ) < keylen1 ) return null ; // read remaining key bytes
if ( this . is. read ( key , 1 , keylen1 ) < keylen1 ) return null ; // read remaining key bytes
// so far we have read this.keylen - 1 + 1 = this.keylen bytes.
// so far we have read this.keylen - 1 + 1 = this.keylen bytes.
// there must be a remaining number of len - this.keylen bytes left for the BLOB
// there must be a remaining number of len - this.keylen bytes left for the BLOB
if ( len < this . keylen ) return null ; // a strange case that can only happen in case of corrupted data
if ( len < this . keylen ) return null ; // a strange case that can only happen in case of corrupted data
try {
try {
payload = new byte [ len - this . keylen ] ; // the remaining record entries
payload = new byte [ len - this . keylen ] ; // the remaining record entries
if ( is. read ( payload ) < payload . length ) return null ;
if ( this . is. read ( payload ) < payload . length ) return null ;
return new entry ( key , payload ) ;
return new entry ( key , payload ) ;
} catch ( OutOfMemoryError e ) {
} catch ( OutOfMemoryError e ) {
// the allocation of memory for the payload may fail
// the allocation of memory for the payload may fail
@ -731,8 +735,8 @@ public class HeapReader {
}
}
public void close ( ) {
public void close ( ) {
if ( is ! = null ) try { is. close ( ) ; } catch ( final IOException e ) { }
if ( this . is ! = null ) try { this . is. close ( ) ; } catch ( final IOException e ) { }
is = null ;
this . is = null ;
}
}
@Override
@Override
@ -750,17 +754,20 @@ public class HeapReader {
this . b = b ;
this . b = b ;
}
}
@Override
public byte [ ] getKey ( ) {
public byte [ ] getKey ( ) {
return s;
return this . s;
}
}
@Override
public byte [ ] getValue ( ) {
public byte [ ] getValue ( ) {
return b;
return this . b;
}
}
@Override
public byte [ ] setValue ( byte [ ] value ) {
public byte [ ] setValue ( byte [ ] value ) {
byte [ ] b1 = b;
byte [ ] b1 = this . b;
b = value ;
this . b = value ;
return b1 ;
return b1 ;
}
}
}
}