⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 log.cs

📁 C#数据库中间层处理,支持主流数据库,如sql、oracle等
💻 CS
📖 第 1 页 / 共 2 页
字号:
/*
 * Log.cs
 *
 * Copyright (c) 2001, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This package is based on HypersonicSQL, originally developed by Thomas Mueller.
 *
 * C# port by Mark Tutt
 *
 */
namespace SharpHSQL
{
	using System;
	using System.Xml;
	using System.Collections;
	using System.IO;
	using System.Threading;

	/**
	 * <P>This class is responsible for most file handling.
	 * A HSQL database consists of a .properties file, a
	 * .script file (contains a SQL script), a
	 * .data file (contains data of cached tables) and a
	 * .backup file (contains the compressed .data file)
	 *
	 * <P>This is an example of the .properties file. The version and the
	 * modified properties are automatically created by the database and
	 * should not be changed manually:
	 * <pre>
	 * modified=no
	 * version=1.3
	 * </pre>
	 * The following lines are optional, this means they are not
	 * created automatically by the database, but they are interpreted
	 * if they exist in the .script file. They have to be created
	 * manually if required. If they don't exist the default is used.
	 * This are the defaults of the database 'test':
	 * <pre>
	 * script=test.script
	 * data=test.data
	 * backup=test.backup
	 * readonly=false
	 * </pre>
	 */
	class Log
	{
		private static int COPY_BLOCK_SIZE = 1 << 16;  // block size for copying data
		private string		       sName;
		private Database	       dDatabase;
		private Channel	           cSystem;
		private StreamWriter	   wScript;
		private string	           sFileProperties;
		private string	           sFileScript;
		private string	           sFileCache;
		private string	           sFileBackup;
		private string			   sModified;
		private string			   sVersion;
		private bool	           bRestoring;
		private bool	           bReadOnly;
		private int		           iLogSize =	200;  // default: .script file is max 200 MB big
		private int		           iLogCount;
		private Thread	           tRunner;
		private bool               bNeedFlush;
		private bool               bWriteDelay;
		private int		           mLastId;
		public Cache		               cCache;

		/**
		 * Constructor declaration
		 *
		 *
		 * @param db
		 * @param system
		 * @param name
		 */
		public Log(Database db, Channel system, string name) 
		{
			dDatabase = db;
			cSystem = system;
			sName = name;
			sFileProperties = sName + ".cfg";
			sFileScript = sName + ".log";
			sFileCache = sName + ".data";
			sFileBackup = sName + ".backup";
		}

		/**
		 * Method declaration
		 *
		 */
		public void run() 
		{
			while (tRunner != null) 
			{
				try 
				{
					//					tRunner.sleep(1000);

					if (bNeedFlush) 
					{
						wScript.Flush();

						bNeedFlush = false;
					}

					// todo: try to do Cache.cleanUp() here, too
				} 
				catch (Exception e) 
				{

					// ignore exceptions; may be InterruptedException or IOException
				}
			}
		}

		/**
		 * Method declaration
		 *
		 *
		 * @param delay
		 */
		public void setWriteDelay(bool delay) 
		{
			bWriteDelay = delay;
		}

		/**
		 * Method declaration
		 *
		 *
		 * @return
		 *
		 * @throws Exception
		 */
		public bool open() 
		{
			bool newdata = false;

			if (Trace.TRACE) 
			{
				Trace.trace();
			}

			if (!(new File(sFileProperties)).Exists) 
			{
				create();
				// this is a new database
				newdata = true;
			}

			// todo: some parts are not necessary for read-only access
			loadProperties();


			if (bReadOnly == true)
			{
				dDatabase.setReadOnly();

				cCache = new Cache(sFileCache);

				cCache.open(true);
				runScript();

				return false;
			}

			bool needbackup = false;

			if (sModified.Equals("yes-new-files")) 
			{
				renameNewToCurrent(sFileScript);
				renameNewToCurrent(sFileBackup);
			} 
			else if (sModified.Equals("yes")) 
			{
				if (isAlreadyOpen()) 
				{
					throw Trace.error(Trace.DATABASE_ALREADY_IN_USE);
				}

				// recovering after a crash (or forgot to close correctly)
				restoreBackup();

				needbackup = true;
			}

			sModified = "yes";
			saveProperties();

			cCache = new Cache(sFileCache);

			cCache.open(false);
			runScript();

			if (needbackup) 
			{
				close(false);
 			    sModified = "yes";
				saveProperties();
				cCache.open(false);
			}

			openScript();

			// this is a existing database
			return newdata;
		}

		/**
		 * Method declaration
		 *
		 */
		public void stop() 
		{
			tRunner = null;
		}

		/**
		 * Method declaration
		 *
		 *
		 * @param compact
		 *
		 * @throws Exception
		 */
		public void close(bool compact) 
		{
		
	
			if (Trace.TRACE) 
			{
				Trace.trace();
			}

			if (bReadOnly) 
			{
				return;
			}

			// no more scripting
			closeScript();

			// create '.script.new' (for this the cache may be still required)
			writeScript(compact);

			// flush the cache (important: after writing the script)
			cCache.flush();

			// create '.backup.new' using the '.data'
			backup();

			// we have the new files
			sModified = "yes-new-files";
			saveProperties();

			// old files can be removed and new files renamed
			renameNewToCurrent(sFileScript);
			renameNewToCurrent(sFileBackup);

			// now its done completely
			sModified = "no";
			saveProperties();
			closeProperties();

			if (compact) 
			{

				// stop the runner thread of this process (just for security)
				stop();

				// delete the .data so then a new file is created
				(new File(sFileCache)).Delete();
				(new File(sFileBackup)).Delete();

				// all files are closed now; simply open & close this database
				Database db = new Database(sName);

				db.getLog().close(false);
			}
		}

		/**
		 * Method declaration
		 *
		 *
		 * @throws Exception
		 */
		public void checkpoint() 
		{
			close(false);
			sModified = "yes";
			saveProperties();
			cCache.open(false);
			openScript();
		}

		/**
		 * Method declaration
		 *
		 *
		 * @param mb
		 */
		public void setLogSize(int mb) 
		{
			iLogSize = mb;
		}

		/**
		 * Method declaration
		 *
		 *
		 * @param c
		 * @param s
		 *
		 * @throws Exception
		 */
		public void write(Channel c, string s) 
		{
			if (bRestoring || s == null || s.Equals("")) 
			{
				return;
			}

			if (!bReadOnly) 
			{
				int id = 0;

				if (c != null) 
				{
					id = c.getId();
				}

				if (id != mLastId) 
				{
					s = "/*C" + id + "*/" + s;
					mLastId = id;
				}

				try 
				{
					writeLine(wScript, s);

					if (bWriteDelay) 
					{
						bNeedFlush = true;
					} 
					else 
					{
						wScript.Flush();
					}
				} 
				catch (IOException e) 
				{
					Trace.error(Trace.FILE_IO_ERROR, sFileScript);
				}

				if (iLogSize > 0 && iLogCount++ > 100) 
				{
					iLogCount = 0;

					if ((new File(sFileScript)).Length > iLogSize * 1024 * 1024) 
					{
						checkpoint();
					}
				}
			}

		}

		/**
		 * Method declaration
		 *
		 *
		 * @throws Exception
		 */
		public void shutdown() 
		{
			tRunner = null;

			cCache.shutdown();
			closeScript();
			closeProperties();
		}

		/**
		 * Method declaration
		 *
		 *
		 * @param db
		 * @param file
		 * @param full
		 * @param channel
		 *
		 * @throws Exception
		 */
		public static void scriptToFile(Database db, string file, bool full,
			Channel channel) 
		{
			if ((new File(file)).Exists) 
			{

				// there must be no such file; overwriting not allowed for security
				throw Trace.error(Trace.FILE_IO_ERROR, file);
			}

			try 
			{
				DateTime   time = DateTime.Now;

				// only ddl commands; needs not so much memory
				Result r;

				if (full) 
				{

					// no drop, no insert, and no positions for cached tables
					r = db.getScript(false, false, false, channel);
				} 
				else 
				{

					// no drop, no insert, but positions for cached tables
					r = db.getScript(false, false, true, channel);
				}

				Record     n = r.rRoot;
				StreamWriter w = new StreamWriter(file);	

				while (n != null) 
				{
					writeLine(w, (string) n.data[0]);

					n = n.next;
				}

				// inserts are done separetely to save memory
				ArrayList tables = db.getTables();

				for (int i = 0; i < tables.Count; i++) 
				{
					Table t = (Table) tables[i];

					// cached tables have the index roots set in the ddl script
					if (full ||!t.isCached()) 
					{
						Index primary = t.getPrimaryIndex();
						Node  x = primary.first();

						while (x != null) 
						{
							writeLine(w, t.getInsertStatement(x.getData()));

							x = primary.next(x);
						}
					}
				}

				w.Close();

				TimeSpan execution = DateTime.Now.Subtract(time);

				if (Trace.TRACE) 
				{
					Trace.trace(execution.TotalMilliseconds.ToInt64());
				}
			} 
			catch (IOException e) 
			{
				Trace.error(Trace.FILE_IO_ERROR, file + " " + e);
			}
		}

		/**
		 * Method declaration
		 *
		 *
		 * @param file
		 */
		private void renameNewToCurrent(string file) 
		{

			// even if it crashes here, recovering is no problem
			if ((new File(file + ".new")).Exists) 
			{

				// if we have a new file
				// delete the old (maybe already deleted)
				(new File(file)).Delete();

				// rename the new to the current
				new File(file + ".new").MoveTo(file);
			}
		}

		/**
		 * Method declaration
		 *
		 *
		 * @throws Exception
		 */
		private void closeProperties() 
		{
			try 
			{
				if (Trace.TRACE) 
				{
					Trace.trace();
				}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -