All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.mckoi.database.TransactionSystem Maven / Gradle / Ivy

Go to download

A full SQL database system with JDBC driver that can be embedded in a Java application or operate as a stand-alone server with clients connecting via TCP/IP.

The newest version!
/**
 * com.mckoi.database.TransactionSystem  24 Mar 2002
 *
 * Mckoi SQL Database ( http://www.mckoi.com/database )
 * Copyright (C) 2000, 2001, 2002  Diehl and Associates, Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * Version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License Version 2 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * Version 2 along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * Change Log:
 * 
 * 
 */

package com.mckoi.database;

import com.mckoi.store.LoggingBufferManager;
import com.mckoi.util.Stats;
import com.mckoi.util.StringUtil;
import com.mckoi.util.LogWriter;
import com.mckoi.debug.*;
import com.mckoi.database.control.DBConfig;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.Properties;

/**
 * A class that provides information and global functions for the transaction
 * layer in the engine.  Shared information includes configuration details,
 * logging, etc.
 *
 * @author Tobias Downer
 */

public class TransactionSystem {

  /**
   * The stats object that keeps track of database statistics.
   */
  private final Stats stats = new Stats();

  /**
   * A logger to output any debugging messages.
   * NOTE: This MUST be final, because other objects may retain a reference
   *   to the object.  If it is not final, then different objects will be
   *   logging to different places if this reference is changed.
   */
  private final DefaultDebugLogger logger;

  /**
   * The ResourceBundle that contains properties of the entire database
   * system.
   */
  private DBConfig config = null;

  /**
   * The path in the file system for the database files.  Note that this will
   * be null if the database does not exist in a local file system.  For this
   * reason it's best not to write code that relies on the use of this value.
   */
  private File db_path;
  
  /**
   * Set to true if lookup comparison lists are enabled.
   */
  private boolean lookup_comparison_list_enabled = false;

  /**
   * Set to true if the database is in read only mode.  This is set from the
   * configuration file.
   */
  private boolean read_only_access = false;

  /**
   * Set to true if locking checks should be performed each time a table is
   * accessed.
   */
  private boolean table_lock_check = false;

  /**
   * Set to false if there is conservative index memory storage.  If true,
   * all root selectable schemes are stored behind a soft reference that will
   * be garbage collected.
   */
  private boolean soft_index_storage = false;

  /**
   * If this is set to true, during boot up the engine will reindex all the
   * tables that weren't closed.  If false, the engine will only reindex the
   * tables that have unchecked in modifications.
   */
  private boolean always_reindex_dirty_tables = false;

  /**
   * Set to true if the file handles should NOT be synchronized with the
   * system file IO when the indices are written.  If this is true, then the
   * database is not as fail safe, however File IO performance is improved.
   */
  private boolean dont_synch_filesystem = false;

  /**
   * Set to true if the parser should ignore case when searching for a schema,
   * table or column using an identifier.
   */
  private boolean ignore_case_for_identifiers = false;

  /**
   * Transaction option, if this is true then a transaction error is generated
   * during commit if a transaction selects data from a table that has
   * committed changes to it during commit time.
   * 

* True by default. */ private boolean transaction_error_on_dirty_select = true; /** * The DataCellCache that is a shared resource between on database's. */ private DataCellCache data_cell_cache = null; /** * The list of FunctionFactory objects that handle different functions from * SQL. */ private ArrayList function_factory_list; /** * The FunctionLookup object that can resolve a FunctionDef object to a * Function object. */ private DSFunctionLookup function_lookup; /** * The regular expression library bridge for the library we are configured * to use. */ private RegexLibrary regex_library; /** * The log directory. */ private File log_directory; /** * A LoggingBufferManager object used to manage pages of ScatteringFileStore * objects in the file system. We can configure the maximum pages and page * size via this object, so we have control over how much memory from the * heap is used for buffering. */ private LoggingBufferManager buffer_manager; /** * The underlying StoreSystem implementation that encapsulates the behaviour * for storing data persistantly. */ private StoreSystem store_system; // ---------- Low level row listeners ---------- /** * A list of table names and listeners that are notified of add and remove * events in a table. */ private ArrayList table_listeners; /** * Constructor. */ public TransactionSystem() { // Setup generate properties from the JVM. logger = new DefaultDebugLogger(); Properties p = System.getProperties(); stats.set(0, "Runtime.java.version: " + p.getProperty("java.version")); stats.set(0, "Runtime.java.vendor: " + p.getProperty("java.vendor")); stats.set(0, "Runtime.java.vm.name: " + p.getProperty("java.vm.name")); stats.set(0, "Runtime.os.name: " + p.getProperty("os.name")); stats.set(0, "Runtime.os.arch: " + p.getProperty("os.arch")); stats.set(0, "Runtime.os.version: " + p.getProperty("os.version")); table_listeners = new ArrayList(); } /** * Parses a file string to an absolute position in the file system. We must * provide the path to the root directory (eg. the directory where the * config bundle is located). */ private static File parseFileString(File root_path, String root_info, String path_string) { File path = new File(path_string); File res; // If the path is absolute then return the absoluate reference if (path.isAbsolute()) { res = path; } else { // If the root path source is the jvm then just return the path. if (root_info != null && root_info.equals("jvm")) { return path; } // If the root path source is the configuration file then // concat the configuration path with the path string and return it. else { res = new File(root_path, path_string); } } return res; } /** * Sets up the log file from the config information. */ private void setupLog(DBConfig config) { String log_path_string = config.getValue("log_path"); String root_path_var = config.getValue("root_path"); String read_only_access = config.getValue("read_only"); String debug_logs = config.getValue("debug_logs"); boolean read_only_bool = false; if (read_only_access != null) { read_only_bool = read_only_access.equalsIgnoreCase("enabled"); } boolean debug_logs_bool = true; if (debug_logs != null) { debug_logs_bool = debug_logs.equalsIgnoreCase("enabled"); } // Conditions for not initializing a log directory; // 1. read only access is enabled // 2. log_path is empty or not set if (debug_logs_bool && !read_only_bool && log_path_string != null && !log_path_string.equals("")) { // First set up the debug information in this VM for the 'Debug' class. File log_path = parseFileString(config.currentPath(), root_path_var, log_path_string); // If the path doesn't exist the make it. if (!log_path.exists()) { log_path.mkdirs(); } // Set the log directory in the DatabaseSystem setLogDirectory(log_path); LogWriter f_writer; File debug_log_file; String dlog_file_name = ""; try { dlog_file_name = config.getValue("debug_log_file"); debug_log_file = new File(log_path.getCanonicalPath(), dlog_file_name); // Allow log size to grow to 512k and allow 12 archives of the log f_writer = new LogWriter(debug_log_file, 512 * 1024, 12); f_writer.write("**** Debug log started: " + new Date(System.currentTimeMillis()) + " ****\n"); f_writer.flush(); } catch (IOException e) { throw new RuntimeException( "Unable to open debug file '" + dlog_file_name + "' in path '" + log_path + "'"); } setDebugOutput(f_writer); } // If 'debug_logs=disabled', don't write out any debug logs if (!debug_logs_bool) { // Otherwise set it up so the output from the logs goes to a PrintWriter // that doesn't do anything. Basically - this means all log information // will get sent into a black hole. setDebugOutput(new PrintWriter(new Writer() { public void write(int c) throws IOException { } public void write(char cbuf[], int off, int len) throws IOException { } public void write(String str, int off, int len) throws IOException { } public void flush() throws IOException { } public void close() throws IOException { } })); } int debug_level = Integer.parseInt(config.getValue("debug_level")); if (debug_level == -1) { setDebugLevel(255); } else { setDebugLevel(debug_level); } } /** * Returns a configuration value, or the default if it's not found. */ public final String getConfigString(String property, String default_val) { String v = config.getValue(property); if (v == null) { return default_val; } return v.trim(); } /** * Returns a configuration value, or the default if it's not found. */ public final int getConfigInt(String property, int default_val) { String v = config.getValue(property); if (v == null) { return default_val; } return Integer.parseInt(v); } /** * Returns a configuration value, or the default if it's not found. */ public final boolean getConfigBoolean(String property, boolean default_val) { String v = config.getValue(property); if (v == null) { return default_val; } return v.trim().equalsIgnoreCase("enabled"); } /** * Given a regular expression string representing a particular library, this * will return the name of the class to use as a bridge between the library * and Mckoi. Returns null if the library name is invalid. */ private static String regexStringToClass(String lib) { if (lib.equals("java.util.regexp")) { return "com.mckoi.database.regexbridge.JavaRegex"; } else if (lib.equals("org.apache.regexp")) { return "com.mckoi.database.regexbridge.ApacheRegex"; } else if (lib.equals("gnu.regexp")) { return "com.mckoi.database.regexbridge.GNURegex"; } else { return null; } } /** * Inits the TransactionSystem with the configuration properties of the * system. * This can only be called once, and should be called at database boot time. */ public void init(DBConfig config) { function_factory_list = new ArrayList(); function_lookup = new DSFunctionLookup(); if (config != null) { this.config = config; // Set the read_only property read_only_access = getConfigBoolean("read_only", false); // Setup the log setupLog(config); // The storage encapsulation that has been configured. String storage_system = getConfigString("storage_system", "v1file"); boolean is_file_store_mode; // Construct the system store. if (storage_system.equalsIgnoreCase("v1file")) { Debug().write(Lvl.MESSAGE, this, "Storage System: v1 file storage mode."); // The path where the database data files are stored. String database_path = getConfigString("database_path", "./data"); // The root path variable String root_path_var = getConfigString("root_path", "jvm"); // Set the absolute database path db_path = parseFileString(config.currentPath(), root_path_var, database_path); store_system = new V1FileStoreSystem(this, db_path, read_only_access); is_file_store_mode = true; } else if (storage_system.equalsIgnoreCase("v1javaheap")) { Debug().write(Lvl.MESSAGE, this, "Storage System: v1 Java heap storage mode."); store_system = new V1HeapStoreSystem(); is_file_store_mode = false; } else { String error_msg = "Unknown storage_system property: " + storage_system; Debug().write(Lvl.ERROR, this, error_msg); throw new RuntimeException(error_msg); } // Register the internal function factory, addFunctionFactory(new InternalFunctionFactory()); String status; // Set up the DataCellCache from the values in the configuration int max_cache_size = 0, max_cache_entry_size = 0; max_cache_size = getConfigInt("data_cache_size", 0); max_cache_entry_size = getConfigInt("max_cache_entry_size", 0); if (max_cache_size >= 4096 && max_cache_entry_size >= 16 && max_cache_entry_size < (max_cache_size / 2)) { Debug().write(Lvl.MESSAGE, this, "Internal Data Cache size: " + max_cache_size); Debug().write(Lvl.MESSAGE, this, "Internal Data Cache max cell size: " + max_cache_entry_size); // Find a prime hash size depending on the size of the cache. int hash_size = DataCellCache.closestPrime(max_cache_size / 55); // Set up the data_cell_cache data_cell_cache = new DataCellCache(this, max_cache_size, max_cache_entry_size, hash_size); } else { Debug().write(Lvl.MESSAGE, this, "Internal Data Cache disabled."); } // Are lookup comparison lists enabled? // lookup_comparison_list_enabled = // getConfigBoolean("lookup_comparison_list", false); lookup_comparison_list_enabled = false; Debug().write(Lvl.MESSAGE, this, "lookup_comparison_list = " + lookup_comparison_list_enabled); // Should we open the database in read only mode? Debug().write(Lvl.MESSAGE, this, "read_only = " + read_only_access); if (read_only_access) stats.set(1, "DatabaseSystem.read_only"); // // Hard Sync file system whenever we update index files? // if (is_file_store_mode) { // dont_synch_filesystem = getConfigBoolean("dont_synch_filesystem", false); // Debug().write(Lvl.MESSAGE, this, // "dont_synch_filesystem = " + dont_synch_filesystem); // } // Generate transaction error if dirty selects are detected? transaction_error_on_dirty_select = getConfigBoolean("transaction_error_on_dirty_select", true); Debug().write(Lvl.MESSAGE, this, "transaction_error_on_dirty_select = " + transaction_error_on_dirty_select); // Case insensitive identifiers? ignore_case_for_identifiers = getConfigBoolean("ignore_case_for_identifiers", false); Debug().write(Lvl.MESSAGE, this, "ignore_case_for_identifiers = " + ignore_case_for_identifiers); // ---- Store system setup ---- // See if this JVM supports the java.nio interface // (first introduced in 1.4) if (is_file_store_mode) { boolean nio_interface_available; try { Class.forName("java.nio.channels.FileChannel"); nio_interface_available = true; Debug().write(Lvl.MESSAGE, this, "Java NIO API is available."); } catch (ClassNotFoundException e) { nio_interface_available = false; Debug().write(Lvl.MESSAGE, this, "Java NIO API is not available."); } // Bug workaround - there are problems with memory mapped NIO under 95/98 // which we workaround by disabling NIO support on 95/98. boolean nio_bugged_os; String os_name = System.getProperties().getProperty("os.name"); nio_bugged_os = (os_name.equalsIgnoreCase("Windows 95") || os_name.equalsIgnoreCase("Windows 98")); // Get the safety level of the file system where 10 is the most safe // and 1 is the least safe. int io_safety_level = getConfigInt("io_safety_level", 10); if (io_safety_level < 1 || io_safety_level > 10) { Debug().write(Lvl.MESSAGE, this, "Invalid io_safety_level value. Setting to the most safe level."); io_safety_level = 10; } Debug().write(Lvl.MESSAGE, this, "io_safety_level = " + io_safety_level); // Logging is disabled when safety level is less or equal to 2 boolean enable_logging = true; if (io_safety_level <= 2) { Debug().write(Lvl.MESSAGE, this, "Disabling journaling and file sync."); enable_logging = false; } // If the configuration property 'use_nio_if_available' is enabled then // we setup a LoggingBufferManager that uses NIO (default to 'false') boolean use_nio_if_available = getConfigBoolean("use_nio_if_available", false); boolean force_use_nio = getConfigBoolean("force_use_nio", false); String api_to_use; int page_size; int max_pages; final boolean disable_nio = true; // If NIO interface available and configuration tells us to use NIO and // we are not running on an OS where NIO is buggy, we set the NIO options // here. if ( !disable_nio && ( force_use_nio || ( nio_interface_available && use_nio_if_available && !nio_bugged_os ))) { Debug().write(Lvl.MESSAGE, this, "Using NIO API for OS memory mapped file access."); page_size = getConfigInt("buffered_nio_page_size", 1024 * 1024); max_pages = getConfigInt("buffered_nio_max_pages", 64); api_to_use = "Java NIO"; } else { Debug().write(Lvl.MESSAGE, this, "Using stardard IO API for heap buffered file access."); page_size = getConfigInt("buffered_io_page_size", 8192); max_pages = getConfigInt("buffered_io_max_pages", 256); api_to_use = "Java IO"; } // Output this information to the log Debug().write(Lvl.MESSAGE, this, "[Buffer Manager] Using IO API: " + api_to_use); Debug().write(Lvl.MESSAGE, this, "[Buffer Manager] Page Size: " + page_size); Debug().write(Lvl.MESSAGE, this, "[Buffer Manager] Max pages: " + max_pages); // Journal path is currently always the same as database path. final File journal_path = db_path; // Max slice size is 1 GB for file scattering class final long max_slice_size = 16384 * 65536; // First file extention is 'koi' final String first_file_ext = "koi"; // Set up the BufferManager buffer_manager = new LoggingBufferManager( db_path, journal_path, read_only_access, max_pages, page_size, first_file_ext, max_slice_size, Debug(), enable_logging); // ^ This is a big constructor. It sets up the logging manager and // sets a resource store data accessor converter to a scattering // implementation with a max slice size of 1 GB // Start the buffer manager. try { buffer_manager.start(); } catch (IOException e) { Debug().write(Lvl.ERROR, this, "Error starting buffer manager"); Debug().writeException(Lvl.ERROR, e); throw new Error("IO Error: " + e.getMessage()); } } // What regular expression library are we using? // If we want the engine to support other regular expression libraries // then include the additional entries here. // Test to see if the regex API exists boolean regex_api_exists; try { Class.forName("java.util.regex.Pattern"); regex_api_exists = true; } catch (ClassNotFoundException e) { // Internal API doesn't exist regex_api_exists = false; Debug().write(Lvl.MESSAGE, this, "Java regex API not available."); } String regex_bridge; String lib_used; String force_lib = getConfigString("force_regex_library", null); // Are we forcing a particular regular expression library? if (force_lib != null) { lib_used = force_lib; // Convert the library string to a class name regex_bridge = regexStringToClass(force_lib); } else { String lib = getConfigString("regex_library", null); lib_used = lib; // Use the standard Java 1.4 regular expression library if it is found. if (regex_api_exists) { regex_bridge = "com.mckoi.database.regexbridge.JavaRegex"; lib_used = "java.util.regexp"; } // else if (lib_used != null) { // regex_bridge = regexStringToClass(lib_used); // } else { regex_bridge = null; lib_used = null; } } if (regex_bridge != null) { try { Class c = Class.forName(regex_bridge); regex_library = (RegexLibrary) c.newInstance(); Debug().write(Lvl.MESSAGE, this, "Using regex bridge: " + lib_used); } catch (Throwable e) { Debug().write(Lvl.ERROR, this, "Unable to load regex bridge: " + regex_bridge); Debug().writeException(Lvl.WARNING, e); } } else { if (lib_used != null) { Debug().write(Lvl.ERROR, this, "Regex library not known: " + lib_used); } Debug().write(Lvl.MESSAGE, this, "Regex features disabled."); } // ---------- Plug ins --------- try { // The 'function_factories' property. String function_factories = getConfigString("function_factories", null); if (function_factories != null) { List factories = StringUtil.explode(function_factories, ";"); for (int i = 0; i < factories.size(); ++i) { String factory_class = factories.get(i).toString(); Class c = Class.forName(factory_class); FunctionFactory fun_factory = (FunctionFactory) c.newInstance(); addFunctionFactory(fun_factory); Debug().write(Lvl.MESSAGE, this, "Successfully added function factory: " + factory_class); } } else { Debug().write(Lvl.MESSAGE, this, "No 'function_factories' config property found."); // If resource missing, do nothing... } } catch (Throwable e) { Debug().write(Lvl.ERROR, this, "Error parsing 'function_factories' configuration property."); Debug().writeException(e); } // Flush the contents of the function lookup object. flushCachedFunctionLookup(); } } /** * Hack - set up the DataCellCache in DatabaseSystem so we can use the * MasterTableDataSource object without having to boot a new DatabaseSystem. */ public void setupRowCache(int max_cache_size, int max_cache_entry_size) { // Set up the data_cell_cache data_cell_cache = new DataCellCache(this, max_cache_size, max_cache_entry_size); } /** * Returns true if the database is in read only mode. In read only mode, * any 'write' operations are not permitted. */ public boolean readOnlyAccess() { return read_only_access; } /** * Returns the path of the database in the local file system if the database * exists within the local file system. If the database is not within the * local file system then null is returned. It is recommended this method * is not used unless for legacy or compatability purposes. */ public File getDatabasePath() { return db_path; } /** * Returns true if the database should perform checking of table locks. */ public boolean tableLockingEnabled() { return table_lock_check; } /** * Returns true if we should generate lookup caches in InsertSearch otherwise * returns false. */ public boolean lookupComparisonListEnabled() { return lookup_comparison_list_enabled; } /** * Returns true if all table indices are kept behind a soft reference that * can be garbage collected. */ public boolean softIndexStorage() { return soft_index_storage; } /** * Returns the status of the 'always_reindex_dirty_tables' property. */ public boolean alwaysReindexDirtyTables() { return always_reindex_dirty_tables; } /** * Returns true if we shouldn't synchronize with the file system when * important indexing information is flushed to the disk. */ public boolean dontSynchFileSystem() { return dont_synch_filesystem; } /** * Returns true if during commit the engine should look for any selects * on a modified table and fail if they are detected. */ public boolean transactionErrorOnDirtySelect() { return transaction_error_on_dirty_select; } /** * Returns true if the parser should ignore case when searching for * schema/table/column identifiers. */ public boolean ignoreIdentifierCase() { return ignore_case_for_identifiers; } /** * Returns the LoggingBufferManager object enabling us to create no file * stores in the file system. This provides access to the buffer scheme that * has been configured. */ public LoggingBufferManager getBufferManager() { return buffer_manager; } /** * Returns the regular expression library from the configuration file. */ public RegexLibrary getRegexLibrary() { if (regex_library != null) { return regex_library; } throw new Error("No regular expression library found in classpath " + "and/or in configuration file."); } // ---------- Store System encapsulation ---------- /** * Returns the StoreSystem encapsulation being used in this database. */ public final StoreSystem storeSystem() { return store_system; } // ---------- Debug logger methods ---------- /** * Sets the Writer output for the debug logger. */ public final void setDebugOutput(java.io.Writer writer) { // System.out.println("**** Setting debug log output ****" + writer); // System.out.println(logger); logger.setOutput(writer); } /** * Sets the debug minimum level that is output to the logger. */ public final void setDebugLevel(int level) { logger.setDebugLevel(level); } /** * Returns the DebugLogger object that is used to log debug message. This * method must always return a debug logger that we can log to. */ public final DebugLogger Debug() { return logger; } // ---------- Function factories ---------- /** * Registers a new FunctionFactory with the database system. The function * factories are used to resolve a function name into a Function object. * Function factories are checked in the order they are added to the database * system. */ public void addFunctionFactory(FunctionFactory factory) { synchronized (function_factory_list) { function_factory_list.add(factory); } factory.init(); } /** * Flushes the 'FunctionLookup' object returned by the getFunctionLookup * method. This should be called if the function factory list has been * modified in some way. */ public void flushCachedFunctionLookup() { FunctionFactory[] factories; synchronized (function_factory_list) { factories = (FunctionFactory[]) function_factory_list.toArray( new FunctionFactory[function_factory_list.size()]); } function_lookup.flushContents(factories); } /** * Returns a FunctionLookup object that will search through the function * factories in this database system and find and resolve a function. The * returned object may throw an exception from the 'generateFunction' method * if the FunctionDef is invalid. For example, if the number of parameters * is incorrect or the name can not be found. */ public FunctionLookup getFunctionLookup() { return function_lookup; } // ---------- System preparers ---------- /** * Given a Transaction.CheckExpression, this will prepare the expression and * return a new prepared CheckExpression. The default implementation of this * is to do nothing. However, a sub-class of the system choose to prepare * the expression, such as resolving the functions via the function lookup, * and resolving the sub-queries, etc. */ public Transaction.CheckExpression prepareTransactionCheckConstraint( DataTableDef table_def, Transaction.CheckExpression check) { // ExpressionPreparer expression_preparer = getFunctionExpressionPreparer(); // Resolve the expression to this table and row and evaluate the // check constraint. Expression exp = check.expression; table_def.resolveColumns(ignoreIdentifierCase(), exp); // try { // // Prepare the functions // exp.prepare(expression_preparer); // } // catch (Exception e) { // Debug().writeException(e); // throw new RuntimeException(e.getMessage()); // } return check; } // ---------- Database System Statistics Methods ---------- /** * Returns a com.mckoi.util.Stats object that can be used to keep track * of database statistics for this VM. */ public final Stats stats() { return stats; } // ---------- Log directory management ---------- /** * Sets the log directory. This should preferably be called during * initialization. If the log directory is not set or is set to 'null' then * no logging to files occurs. */ public final void setLogDirectory(File log_path) { this.log_directory = log_path; } /** * Returns the current log directory or null if no logging should occur. */ public final File getLogDirectory() { return log_directory; } // ---------- Cache Methods ---------- /** * Returns a DataCellCache object that is a shared resource between all * database's running on this VM. If this returns 'null' then the internal * cache is disabled. */ DataCellCache getDataCellCache() { return data_cell_cache; } // ---------- Dispatch methods ---------- /** * The dispatcher. */ private DatabaseDispatcher dispatcher; /** * Returns the DatabaseDispatcher object. */ private DatabaseDispatcher getDispatcher() { synchronized (this) { if (dispatcher == null) { dispatcher = new DatabaseDispatcher(this); } return dispatcher; } } /** * Creates an event object that is passed into 'postEvent' method * to run the given Runnable method after the time has passed. *

* The event created here can be safely posted on the event queue as many * times as you like. It's useful to create an event as a persistant object * to service some event. Just post it on the dispatcher when you want * it run! */ Object createEvent(Runnable runnable) { return getDispatcher().createEvent(runnable); } /** * Adds a new event to be dispatched on the queue after 'time_to_wait' * milliseconds has passed. *

* 'event' must be an event object returned via 'createEvent'. */ void postEvent(int time_to_wait, Object event) { getDispatcher().postEvent(time_to_wait, event); } /** * Disposes this object. */ public void dispose() { if (buffer_manager != null) { try { // Set a check point store_system.setCheckPoint(); // Stop the buffer manager buffer_manager.stop(); } catch (IOException e) { System.out.println("Error stopping buffer manager."); e.printStackTrace(); } } buffer_manager = null; regex_library = null; data_cell_cache = null; config = null; log_directory = null; function_factory_list = null; store_system = null; if (dispatcher != null) { dispatcher.finish(); } // trigger_manager = null; dispatcher = null; } // ---------- Inner classes ---------- /** * A FunctionLookup implementation that will look up a function from a * list of FunctionFactory objects provided with. */ private static class DSFunctionLookup implements FunctionLookup { private FunctionFactory[] factories; public synchronized Function generateFunction(FunctionDef function_def) { for (int i = 0; i < factories.length; ++i) { Function f = factories[i].generateFunction(function_def); if (f != null) { return f; } } return null; } public synchronized boolean isAggregate(FunctionDef function_def) { for (int i = 0; i < factories.length; ++i) { FunctionInfo f_info = factories[i].getFunctionInfo(function_def.getName()); if (f_info != null) { return f_info.getType() == FunctionInfo.AGGREGATE; } } return false; } public synchronized void flushContents(FunctionFactory[] factories) { this.factories = factories; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy