public void Traverse( [NotNull] IBlockDBQueryProcessor processor )
{
if ( processor == null )
throw new ArgumentNullException( "processor" );
if ( !IsEnabled || !IsEnabledGlobally ) {
throw new InvalidOperationException( "Trying to lookup on disabled BlockDB." );
}
IDisposable readLockHandle = null;
try {
if ( !locker.IsReadLockHeld ) {
readLockHandle = locker.WriteLock();
}
if ( isPreloaded ) {
// Entire database is in memory
fixed ( BlockDBEntry* entries = cacheStore ) {
for ( int i = CacheSize - 1; i >= 0; i-- ) {
if ( !processor.ProcessEntry( entries[i] ) ) {
return;
}
}
}
} else {
// Search unflushed cache for matches
if ( LastFlushedIndex < CacheSize ) {
fixed ( BlockDBEntry* entries = cacheStore ) {
for ( int i = CacheSize - 1; i >= LastFlushedIndex; i-- ) {
if ( !processor.ProcessEntry( entries[i] ) ) {
return;
}
}
}
}
// If we still have some searching to do, read the file
if ( !File.Exists( FileName ) )
return;
using ( FileStream fs = OpenRead() ) {
long length = fs.Length;
long bytesReadTotal = 0;
int bufferSize = ( int )Math.Min( SearchBufferSize, length );
byte[] buffer = new byte[bufferSize];
while ( bytesReadTotal < length ) {
// The file is scanned from the end of file towards the beginning
long offset = Math.Max( 0, length - bytesReadTotal - SearchBufferSize );
fs.Seek( offset, SeekOrigin.Begin );
// read a chunk of the .fbdb file into memory, linearly
int bytesToRead = ( int )Math.Min( length - bytesReadTotal, SearchBufferSize );
int bytesLeft = bytesToRead;
int bytesRead = 0;
while ( bytesLeft > 0 ) {
int readPass = fs.Read( buffer, bytesRead, bytesLeft );
if ( readPass == 0 )
throw new EndOfStreamException();
bytesRead += readPass;
bytesLeft -= readPass;
}
bytesReadTotal += bytesRead;
// search a chunk
fixed ( byte* parr = buffer ) {
BlockDBEntry* entries = ( BlockDBEntry* )parr;
int entryCount = bytesRead / sizeof( BlockDBEntry );
if ( bytesRead % sizeof( BlockDBEntry ) != 0 ) {
throw new DataMisalignedException();
}
// iterate over the chunk backwards (newest to oldest)
for ( int i = entryCount - 1; i >= 0; i-- ) {
if ( !processor.ProcessEntry( entries[i] ) ) {
return;
}
}
}
}
}
}
} finally {
if ( readLockHandle != null ) {
readLockHandle.Dispose();
}
}
}