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

📄 log.java

📁 Java写的含有一个jdbc驱动的小型数据库数据库引擎
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * Log.java
 *
 * 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.
 *
 */
package org.hsqldb;

import java.sql.*;
import java.io.*;
import java.util.*;
import java.util.zip.*;

/**
 * <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 implements Runnable {
    private final static int COPY_BLOCK_SIZE =
	1 << 16;			     // block size for copying data
    private FileInputStream  fProperties;    // kept open until closed
    private Properties       pProperties;
    private String	     sName;
    private Database	     dDatabase;
    private Channel	     cSystem;
    private Writer	     wScript;
    private String	     sFileProperties;
    private String	     sFileScript;
    private String	     sFileCache;
    private String	     sFileBackup;
    private boolean	     bRestoring;
    private boolean	     bReadOnly;
    private int		     iLogSize =
	200;				     // default: .script file is max 200 MB big
    private int		     iLogCount;
    private Thread	     tRunner;
    private volatile boolean bNeedFlush;
    private volatile boolean bWriteDelay;
    private int		     mLastId;
    Cache		     cCache;

    /**
     * Constructor declaration
     *
     *
     * @param db
     * @param system
     * @param name
     */
    Log(Database db, Channel system, String name) throws SQLException {
	dDatabase = db;
	cSystem = system;
	sName = name;
	sFileProperties = sName + ".properties";
	pProperties = new Properties();
	tRunner = new Thread(this);

	tRunner.start();
    }

    /**
     * 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
     */
    void setWriteDelay(boolean delay) {
	bWriteDelay = delay;
    }

    /**
     * Method declaration
     *
     *
     * @return
     *
     * @throws SQLException
     */
    boolean open() throws SQLException {
	if (Trace.TRACE) {
	    Trace.trace();
	}

	if (!(new File(sFileProperties)).exists()) {
	    create();
	    open();

	    // this is a new database
	    return true;
	}

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

	sFileScript = pProperties.getProperty("script", sName + ".script");
	sFileCache = pProperties.getProperty("data", sName + ".data");
	sFileBackup = pProperties.getProperty("backup", sName + ".backup");

	String  version = pProperties.getProperty("version", "1.0");
// fredt@users.sourceforge.net begin changes for 1.61
// enable opening older version databases, disable opening newer version
// the first three characters are compared so that version 1.60 can open
// version 1.62 databases but not version 1.72 databases

//	boolean check = version.equals(jdbcDriver.VERSION);
	boolean check = version.substring(0,3).compareTo(jdbcDriver.VERSION) <= 0;
   // save as the current version
   pProperties.setProperty("version", jdbcDriver.VERSION);
// fredt@users.sourceforge.net end changes for 1.61

	Trace.check(check, Trace.WRONG_DATABASE_FILE_VERSION);

	if (pProperties.getProperty("readonly", "false").equals("true")) {
	    bReadOnly = true;

	    dDatabase.setReadOnly();

	    cCache = new Cache(sFileCache);

	    cCache.open(true);
	    runScript();

	    return false;
	}

	boolean needbackup = false;
	String  state = pProperties.getProperty("modified", "no");

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

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

	    needbackup = true;
	}

	pProperties.put("modified", "yes");
	saveProperties();

	cCache = new Cache(sFileCache);

	cCache.open(false);
	runScript();

	if (needbackup) {
	    close(false);
	    pProperties.put("modified", "yes");
	    saveProperties();
	    cCache.open(false);
	}

	openScript();

	// this is a existing database
	return false;
    }

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

    /**
     * Method declaration
     *
     *
     * @param compact
     *
     * @throws SQLException
     */
    void close(boolean compact) throws SQLException {
	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
	pProperties.put("modified", "yes-new-files");
	saveProperties();

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

	// now its done completely
	pProperties.put("modified", "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 SQLException
     */
    void checkpoint() throws SQLException {
	close(false);
	pProperties.put("modified", "yes");
	saveProperties();
	cCache.open(false);
	openScript();
    }

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

    /**
     * Method declaration
     *
     *
     * @param c
     * @param s
     *
     * @throws SQLException
     */
    void write(Channel c, String s) throws SQLException {
	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 SQLException
     */
    void shutdown() throws SQLException {
	tRunner = null;

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

    /**
     * Method declaration
     *
     *
     * @param db
     * @param file
     * @param full
     * @param channel
     *
     * @throws SQLException
     */
    static void scriptToFile(Database db, String file, boolean full,
			     Channel channel) throws SQLException {
	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 {
	    long   time = System.currentTimeMillis();

	    // 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;
	    FileWriter w = new FileWriter(file);

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

		n = n.next;
	    }

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

	    for (int i = 0; i < tables.size(); i++) {
		Table t = (Table) tables.elementAt(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();

	    time = System.currentTimeMillis() - time;

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

⌨️ 快捷键说明

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