fCraft.BlockDB.Traverse C# (CSharp) Method

Traverse() public method

Traverses the database, newest to oldest entries, processing each entry with the given IBlockDBQueryProcessor.
processor is null. BlockDB is disabled. The end of FBDB file is reached prematurely (corrupted file, or outside interference). FBDB file is not aligned to 20 bytes (likely corrupted). An I/O error occurrs while trying to read FBDB file from disk.
public Traverse ( [ processor ) : void
processor [ Processor to use for each BlockDBEntry.
return void
        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();
                }
            }
        }