context: /* Copyright (C) 2004 - 2009  Versant Inc.  http://www.db4o.com */
  
  using System;
  using System.IO;
  using Db4objects.Db4o;
  using Db4objects.Db4o.Config;
  using Db4objects.Db4o.Ext;
  using Db4objects.Db4o.Foundation;
  using Db4objects.Db4o.IO;
  using Db4objects.Db4o.Internal;
  using Db4objects.Db4o.Internal.Slots;
  using Sharpen.Lang;
  
  namespace Db4objects.Db4o.Internal
  {
  	/// <exclude></exclude>
  	public class IoAdaptedObjectContainer : LocalObjectContainer, IEmbeddedObjectContainer
  	{
  		private readonly string _fileName;
  
  		private BlockAwareBin _file;
  
  		private volatile BlockAwareBin _backupFile;
  
  		private object _fileLock;
  
  		private readonly IFreespaceFiller _freespaceFiller;
  
  		/// <exception cref="Db4objects.Db4o.Ext.OldFormatException"></exception>
  		internal IoAdaptedObjectContainer(IConfiguration config, string fileName) : base(
  			config)
  		{
  			_fileLock = new object();
  			_fileName = fileName;
  			_freespaceFiller = CreateFreespaceFiller();
  			Open();
  		}
  
  		/// <exception cref="Db4objects.Db4o.Ext.OldFormatException"></exception>
  		/// <exception cref="Db4objects.Db4o.Ext.DatabaseReadOnlyException"></exception>
  		protected sealed override void OpenImpl()
  		{
  			Config4Impl configImpl = ConfigImpl;
  			IStorage storage = configImpl.Storage;
  			bool isNew = !storage.Exists(FileName());
  			if (isNew)
  			{
  				LogMsg(14, FileName());
  				CheckReadOnly();
  				_handlers.OldEncryptionOff();
  			}
  			bool readOnly = configImpl.IsReadOnly();
  			bool lockFile = Debug4.lockFile && configImpl.LockFile() && (!readOnly);
  			if (NeedsLockFileThread())
  			{
  				IBin fileBin = storage.Open(new BinConfiguration(FileName(), false, 0, false, configImpl
  					.BlockSize()));
  				IBin synchronizedBin = new SynchronizedBin(fileBin);
  				_file = new BlockAwareBin(synchronizedBin);
  			}
  			else
  			{
  				IBin bin = storage.Open(new BinConfiguration(FileName(), lockFile, 0, readOnly, configImpl
  					.BlockSize()));
  				if (configImpl.AsynchronousSync())
  				{
  					bin = new ThreadedSyncBin(bin);
  				}
  				_file = new BlockAwareBin(bin);
  			}
  			if (isNew)
  			{
  				ConfigureNewFile();
  				if (configImpl.ReservedStorageSpace() > 0)
  				{
  					Reserve(configImpl.ReservedStorageSpace());
  				}
  				CommitTransaction();
  				WriteHeader(true, false);
  			}
  			else
  			{
  				ReadThis();
  			}
  		}
  
  		/// <exception cref="Db4objects.Db4o.Ext.DatabaseClosedException"></exception>
  		/// <exception cref="Db4objects.Db4o.Ext.Db4oIOException"></exception>
  		public override void Backup(IStorage targetStorage, string path)
  		{
  			WithEnvironment(new _IRunnable_76(this, targetStorage, path));
  		}
  
  		private sealed class _IRunnable_76 : IRunnable
  		{
  			public _IRunnable_76(IoAdaptedObjectContainer _enclosing, IStorage targetStorage, 
  				string path)
  			{
  				this._enclosing = _enclosing;
  				this.targetStorage = targetStorage;
  				this.path = path;
  			}
  
  			public void Run()
  			{
  				lock (this._enclosing._lock)
  				{
  					this._enclosing.CheckClosed();
  					if (this._enclosing._backupFile != null)
  					{
  						throw new BackupInProgressException();
  					}
  					this._enclosing._backupFile = new BlockAwareBin(targetStorage.Open(new BinConfiguration
  						(path, true, this._enclosing._file.Length(), false, this._enclosing._blockConverter
  						.BlocksToBytes(1))));
  				}
  				long pos = 0;
  				byte[] buffer = new byte[8192];
  				while (true)
  				{
  					lock (this._enclosing._lock)
  					{
  						int read = this._enclosing._file.Read(pos, buffer);
  						if (read <= 0)
  						{
  							break;
  						}
  						this._enclosing._backupFile.Write(pos, buffer, read);
  						pos += read;
  					}
  					// Let the database engine continue to do 
  					// some work if it likes to.
  					Runtime4.Sleep(1);
  				}
  				lock (this._enclosing._lock)
  				{
  					try
  					{
  						Db4objects.Db4o.Internal.IoAdaptedObjectContainer.SyncAndClose(this._enclosing._backupFile
  							);
  					}
  					finally
  					{
  						this._enclosing._backupFile = null;
  					}
  				}
  			}
  
  			private readonly IoAdaptedObjectContainer _enclosing;
  
  			private readonly IStorage targetStorage;
  
  			private readonly string path;
  		}
  
  		public override void BlockSize(int size)
  		{
  			CreateBlockConverter(size);
  			_file.BlockSize(size);
  		}
  
  		public override byte BlockSize()
  		{
  			return (byte)_file.BlockSize();
  		}
  
  		protected override void ShutdownDataStorage()
  		{
  			lock (_fileLock)
  			{
  				try
  				{
  					CloseFileHeader();
  				}
  				finally
  				{
  					CloseDatabaseFile();
  				}
  			}
  		}
  
  		private void CloseDatabaseFile()
  		{
  			try
  			{
  				SyncAndClose(_file);
  			}
  			finally
  			{
  				_file = null;
  			}
  		}
  
  		private static void SyncAndClose(IBin bin)
  		{
  			if (bin != null)
  			{
  				try
  				{
  					bin.Sync();
  				}
  				finally
  				{
  					bin.Close();
  				}
  			}
  		}
  
  		private void CloseFileHeader()
  		{
  			try
  			{
  				if (_fileHeader != null)
  				{
  					_fileHeader.Close();
  				}
  			}
  			finally
  			{
  				_fileHeader = null;
  			}
  		}
  
  		public override void CloseTransaction(Transaction transaction, bool isSystemTransaction
  			, bool rollbackOnClose)
  		{
  			transaction.Close(rollbackOnClose);
  		}
  
  		public override void Commit1(Transaction trans)
  		{
  			EnsureLastSlotWritten();
  			base.Commit1(trans);
  		}
  
  		private void CheckXBytes(int newAddress, int newAddressOffset, int length)
  		{
  			if (Debug4.xbytes && Deploy.overwrite)
  			{
  				try
  				{
  					byte[] checkXBytes = new byte[length];
  
gt: 					_file.BlockRead(newAddress, newAddressOffset, checkXBytes);