KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mckoi > database > TransactionSystem


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

24
25 package com.mckoi.database;
26
27 import com.mckoi.store.LoggingBufferManager;
28 import com.mckoi.util.Stats;
29 import com.mckoi.util.StringUtil;
30 import com.mckoi.util.LogWriter;
31 import com.mckoi.debug.*;
32 import com.mckoi.database.control.DBConfig;
33 import java.io.File JavaDoc;
34 import java.io.IOException JavaDoc;
35 import java.io.PrintWriter JavaDoc;
36 import java.io.Writer JavaDoc;
37 import java.util.Date JavaDoc;
38 import java.util.List JavaDoc;
39 import java.util.ArrayList JavaDoc;
40 import java.util.Properties JavaDoc;
41
42 /**
43  * A class that provides information and global functions for the transaction
44  * layer in the engine. Shared information includes configuration details,
45  * logging, etc.
46  *
47  * @author Tobias Downer
48  */

49
50 public class TransactionSystem {
51
52   /**
53    * The stats object that keeps track of database statistics.
54    */

55   private final Stats stats = new Stats();
56
57   /**
58    * A logger to output any debugging messages.
59    * NOTE: This MUST be final, because other objects may retain a reference
60    * to the object. If it is not final, then different objects will be
61    * logging to different places if this reference is changed.
62    */

63   private final DefaultDebugLogger logger;
64
65   /**
66    * The ResourceBundle that contains properties of the entire database
67    * system.
68    */

69   private DBConfig config = null;
70
71   /**
72    * The path in the file system for the database files. Note that this will
73    * be null if the database does not exist in a local file system. For this
74    * reason it's best not to write code that relies on the use of this value.
75    */

76   private File JavaDoc db_path;
77   
78   /**
79    * Set to true if lookup comparison lists are enabled.
80    */

81   private boolean lookup_comparison_list_enabled = false;
82
83   /**
84    * Set to true if the database is in read only mode. This is set from the
85    * configuration file.
86    */

87   private boolean read_only_access = false;
88
89   /**
90    * Set to true if locking checks should be performed each time a table is
91    * accessed.
92    */

93   private boolean table_lock_check = false;
94
95   /**
96    * Set to false if there is conservative index memory storage. If true,
97    * all root selectable schemes are stored behind a soft reference that will
98    * be garbage collected.
99    */

100   private boolean soft_index_storage = false;
101
102   /**
103    * If this is set to true, during boot up the engine will reindex all the
104    * tables that weren't closed. If false, the engine will only reindex the
105    * tables that have unchecked in modifications.
106    */

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

114   private boolean dont_synch_filesystem = false;
115
116   /**
117    * Set to true if the parser should ignore case when searching for a schema,
118    * table or column using an identifier.
119    */

120   private boolean ignore_case_for_identifiers = false;
121
122   /**
123    * Transaction option, if this is true then a transaction error is generated
124    * during commit if a transaction selects data from a table that has
125    * committed changes to it during commit time.
126    * <p>
127    * True by default.
128    */

129   private boolean transaction_error_on_dirty_select = true;
130
131   /**
132    * The DataCellCache that is a shared resource between on database's.
133    */

134   private DataCellCache data_cell_cache = null;
135
136   /**
137    * The list of FunctionFactory objects that handle different functions from
138    * SQL.
139    */

140   private ArrayList JavaDoc function_factory_list;
141
142   /**
143    * The FunctionLookup object that can resolve a FunctionDef object to a
144    * Function object.
145    */

146   private DSFunctionLookup function_lookup;
147
148   /**
149    * The regular expression library bridge for the library we are configured
150    * to use.
151    */

152   private RegexLibrary regex_library;
153
154   /**
155    * The log directory.
156    */

157   private File JavaDoc log_directory;
158
159   /**
160    * A LoggingBufferManager object used to manage pages of ScatteringFileStore
161    * objects in the file system. We can configure the maximum pages and page
162    * size via this object, so we have control over how much memory from the
163    * heap is used for buffering.
164    */

165   private LoggingBufferManager buffer_manager;
166
167   /**
168    * The underlying StoreSystem implementation that encapsulates the behaviour
169    * for storing data persistantly.
170    */

171   private StoreSystem store_system;
172   
173   // ---------- Low level row listeners ----------
174

175   /**
176    * A list of table names and listeners that are notified of add and remove
177    * events in a table.
178    */

179   private ArrayList JavaDoc table_listeners;
180   
181
182   /**
183    * Constructor.
184    */

185   public TransactionSystem() {
186     // Setup generate properties from the JVM.
187
logger = new DefaultDebugLogger();
188     Properties JavaDoc p = System.getProperties();
189     stats.set(0, "Runtime.java.version: " + p.getProperty("java.version"));
190     stats.set(0, "Runtime.java.vendor: " + p.getProperty("java.vendor"));
191     stats.set(0, "Runtime.java.vm.name: " + p.getProperty("java.vm.name"));
192     stats.set(0, "Runtime.os.name: " + p.getProperty("os.name"));
193     stats.set(0, "Runtime.os.arch: " + p.getProperty("os.arch"));
194     stats.set(0, "Runtime.os.version: " + p.getProperty("os.version"));
195     table_listeners = new ArrayList JavaDoc();
196   }
197
198   /**
199    * Parses a file string to an absolute position in the file system. We must
200    * provide the path to the root directory (eg. the directory where the
201    * config bundle is located).
202    */

203   private static File JavaDoc parseFileString(File JavaDoc root_path, String JavaDoc root_info,
204                                       String JavaDoc path_string) {
205     File JavaDoc path = new File JavaDoc(path_string);
206     File JavaDoc res;
207     // If the path is absolute then return the absoluate reference
208
if (path.isAbsolute()) {
209       res = path;
210     }
211     else {
212       // If the root path source is the jvm then just return the path.
213
if (root_info != null &&
214           root_info.equals("jvm")) {
215         return path;
216       }
217       // If the root path source is the configuration file then
218
// concat the configuration path with the path string and return it.
219
else {
220         res = new File JavaDoc(root_path, path_string);
221       }
222     }
223     return res;
224   }
225
226   /**
227    * Sets up the log file from the config information.
228    */

229   private void setupLog(DBConfig config) {
230     String JavaDoc log_path_string = config.getValue("log_path");
231     String JavaDoc root_path_var = config.getValue("root_path");
232     String JavaDoc read_only_access = config.getValue("read_only");
233     String JavaDoc debug_logs = config.getValue("debug_logs");
234     boolean read_only_bool = false;
235     if (read_only_access != null) {
236       read_only_bool = read_only_access.equalsIgnoreCase("enabled");
237     }
238     boolean debug_logs_bool = true;
239     if (debug_logs != null) {
240       debug_logs_bool = debug_logs.equalsIgnoreCase("enabled");
241     }
242
243     // Conditions for not initializing a log directory;
244
// 1. read only access is enabled
245
// 2. log_path is empty or not set
246

247     if (debug_logs_bool && !read_only_bool &&
248         log_path_string != null && !log_path_string.equals("")) {
249       // First set up the debug information in this VM for the 'Debug' class.
250
File JavaDoc log_path = parseFileString(config.currentPath(), root_path_var,
251                                       log_path_string);
252       // If the path doesn't exist the make it.
253
if (!log_path.exists()) {
254         log_path.mkdirs();
255       }
256       // Set the log directory in the DatabaseSystem
257
setLogDirectory(log_path);
258
259       LogWriter f_writer;
260       File JavaDoc debug_log_file;
261       String JavaDoc dlog_file_name = "";
262       try {
263         dlog_file_name = config.getValue("debug_log_file");
264         debug_log_file = new File JavaDoc(log_path.getCanonicalPath(),
265                                   dlog_file_name);
266
267         // Allow log size to grow to 512k and allow 12 archives of the log
268
f_writer = new LogWriter(debug_log_file, 512 * 1024, 12);
269         f_writer.write("**** Debug log started: " +
270                        new Date JavaDoc(System.currentTimeMillis()) + " ****\n");
271         f_writer.flush();
272       }
273       catch (IOException JavaDoc e) {
274         throw new RuntimeException JavaDoc(
275              "Unable to open debug file '" + dlog_file_name +
276              "' in path '" + log_path + "'");
277       }
278       setDebugOutput(f_writer);
279     }
280
281     // If 'debug_logs=disabled', don't write out any debug logs
282
if (!debug_logs_bool) {
283       // Otherwise set it up so the output from the logs goes to a PrintWriter
284
// that doesn't do anything. Basically - this means all log information
285
// will get sent into a black hole.
286
setDebugOutput(new PrintWriter JavaDoc(new Writer() {
287         public void write(int c) throws IOException JavaDoc {
288         }
289         public void write(char cbuf[], int off, int len) throws IOException JavaDoc {
290         }
291         public void write(String JavaDoc str, int off, int len) throws IOException JavaDoc {
292         }
293         public void flush() throws IOException JavaDoc {
294         }
295         public void close() throws IOException JavaDoc {
296         }
297       }));
298     }
299
300     int debug_level = Integer.parseInt(config.getValue("debug_level"));
301     if (debug_level == -1) {
302       setDebugLevel(255);
303     }
304     else {
305       setDebugLevel(debug_level);
306     }
307   }
308   
309   /**
310    * Returns a configuration value, or the default if it's not found.
311    */

312   public final String JavaDoc getConfigString(String JavaDoc property, String JavaDoc default_val) {
313     String JavaDoc v = config.getValue(property);
314     if (v == null) {
315       return default_val;
316     }
317     return v.trim();
318   }
319
320   /**
321    * Returns a configuration value, or the default if it's not found.
322    */

323   public final int getConfigInt(String JavaDoc property, int default_val) {
324     String JavaDoc v = config.getValue(property);
325     if (v == null) {
326       return default_val;
327     }
328     return Integer.parseInt(v);
329   }
330
331   /**
332    * Returns a configuration value, or the default if it's not found.
333    */

334   public final boolean getConfigBoolean(String JavaDoc property, boolean default_val) {
335     String JavaDoc v = config.getValue(property);
336     if (v == null) {
337       return default_val;
338     }
339     return v.trim().equalsIgnoreCase("enabled");
340   }
341
342
343   /**
344    * Given a regular expression string representing a particular library, this
345    * will return the name of the class to use as a bridge between the library
346    * and Mckoi. Returns null if the library name is invalid.
347    */

348   private static String JavaDoc regexStringToClass(String JavaDoc lib) {
349     if (lib.equals("java.util.regexp")) {
350       return "com.mckoi.database.regexbridge.JavaRegex";
351     }
352     else if (lib.equals("org.apache.regexp")) {
353       return "com.mckoi.database.regexbridge.ApacheRegex";
354     }
355     else if (lib.equals("gnu.regexp")) {
356       return "com.mckoi.database.regexbridge.GNURegex";
357     }
358     else {
359       return null;
360     }
361   }
362
363   /**
364    * Inits the TransactionSystem with the configuration properties of the
365    * system.
366    * This can only be called once, and should be called at database boot time.
367    */

368   public void init(DBConfig config) {
369
370     function_factory_list = new ArrayList JavaDoc();
371     function_lookup = new DSFunctionLookup();
372
373     if (config != null) {
374       this.config = config;
375
376       // Set the read_only property
377
read_only_access = getConfigBoolean("read_only", false);
378
379       // Setup the log
380
setupLog(config);
381       
382       // The storage encapsulation that has been configured.
383
String JavaDoc storage_system = getConfigString("storage_system", "v1file");
384
385       boolean is_file_store_mode;
386       
387       // Construct the system store.
388
if (storage_system.equalsIgnoreCase("v1file")) {
389         Debug().write(Lvl.MESSAGE, this,
390                       "Storage System: v1 file storage mode.");
391
392         // The path where the database data files are stored.
393
String JavaDoc database_path = getConfigString("database_path", "./data");
394         // The root path variable
395
String JavaDoc root_path_var = getConfigString("root_path", "jvm");
396
397         // Set the absolute database path
398
db_path = parseFileString(config.currentPath(), root_path_var,
399                                   database_path);
400
401         store_system = new V1FileStoreSystem(this, db_path, read_only_access);
402         is_file_store_mode = true;
403       }
404
405       else if (storage_system.equalsIgnoreCase("v1javaheap")) {
406         Debug().write(Lvl.MESSAGE, this,
407                       "Storage System: v1 Java heap storage mode.");
408         store_system = new V1HeapStoreSystem();
409         is_file_store_mode = false;
410       }
411
412       else {
413         String JavaDoc error_msg = "Unknown storage_system property: " + storage_system;
414         Debug().write(Lvl.ERROR, this, error_msg);
415         throw new RuntimeException JavaDoc(error_msg);
416       }
417
418       // Register the internal function factory,
419
addFunctionFactory(new InternalFunctionFactory());
420
421       String JavaDoc status;
422
423       // Set up the DataCellCache from the values in the configuration
424
int max_cache_size = 0, max_cache_entry_size = 0;
425
426       max_cache_size = getConfigInt("data_cache_size", 0);
427       max_cache_entry_size = getConfigInt("max_cache_entry_size", 0);
428
429       if (max_cache_size >= 4096 &&
430           max_cache_entry_size >= 16 &&
431           max_cache_entry_size < (max_cache_size / 2)) {
432
433         Debug().write(Lvl.MESSAGE, this,
434                 "Internal Data Cache size: " + max_cache_size);
435         Debug().write(Lvl.MESSAGE, this,
436                 "Internal Data Cache max cell size: " + max_cache_entry_size);
437
438         // Find a prime hash size depending on the size of the cache.
439
int hash_size = DataCellCache.closestPrime(max_cache_size / 55);
440
441         // Set up the data_cell_cache
442
data_cell_cache = new DataCellCache(this,
443                             max_cache_size, max_cache_entry_size, hash_size);
444
445       }
446       else {
447         Debug().write(Lvl.MESSAGE, this,
448                     "Internal Data Cache disabled.");
449       }
450
451       // Are lookup comparison lists enabled?
452
// lookup_comparison_list_enabled =
453
// getConfigBoolean("lookup_comparison_list", false);
454
lookup_comparison_list_enabled = false;
455       Debug().write(Lvl.MESSAGE, this,
456                 "lookup_comparison_list = " + lookup_comparison_list_enabled);
457
458       // Should we open the database in read only mode?
459
Debug().write(Lvl.MESSAGE, this,
460                     "read_only = " + read_only_access);
461       if (read_only_access) stats.set(1, "DatabaseSystem.read_only");
462
463 // // Hard Sync file system whenever we update index files?
464
// if (is_file_store_mode) {
465
// dont_synch_filesystem = getConfigBoolean("dont_synch_filesystem", false);
466
// Debug().write(Lvl.MESSAGE, this,
467
// "dont_synch_filesystem = " + dont_synch_filesystem);
468
// }
469

470       // Generate transaction error if dirty selects are detected?
471
transaction_error_on_dirty_select =
472                getConfigBoolean("transaction_error_on_dirty_select", true);
473       Debug().write(Lvl.MESSAGE, this, "transaction_error_on_dirty_select = " +
474                     transaction_error_on_dirty_select);
475
476       // Case insensitive identifiers?
477
ignore_case_for_identifiers =
478                        getConfigBoolean("ignore_case_for_identifiers", false);
479       Debug().write(Lvl.MESSAGE, this,
480               "ignore_case_for_identifiers = " + ignore_case_for_identifiers);
481
482       // ---- Store system setup ----
483

484       // See if this JVM supports the java.nio interface
485
// (first introduced in 1.4)
486
if (is_file_store_mode) {
487         boolean nio_interface_available;
488         try {
489           Class.forName("java.nio.channels.FileChannel");
490           nio_interface_available = true;
491           Debug().write(Lvl.MESSAGE, this,
492                         "Java NIO API is available.");
493         }
494         catch (ClassNotFoundException JavaDoc e) {
495           nio_interface_available = false;
496           Debug().write(Lvl.MESSAGE, this,
497                         "Java NIO API is not available.");
498         }
499
500         // Bug workaround - there are problems with memory mapped NIO under 95/98
501
// which we workaround by disabling NIO support on 95/98.
502
boolean nio_bugged_os;
503         String JavaDoc os_name = System.getProperties().getProperty("os.name");
504         nio_bugged_os = (os_name.equalsIgnoreCase("Windows 95") ||
505                          os_name.equalsIgnoreCase("Windows 98"));
506
507         // Get the safety level of the file system where 10 is the most safe
508
// and 1 is the least safe.
509
int io_safety_level = getConfigInt("io_safety_level", 10);
510         if (io_safety_level < 1 || io_safety_level > 10) {
511           Debug().write(Lvl.MESSAGE, this,
512             "Invalid io_safety_level value. Setting to the most safe level.");
513           io_safety_level = 10;
514         }
515         Debug().write(Lvl.MESSAGE, this,
516                       "io_safety_level = " + io_safety_level);
517
518         // Logging is disabled when safety level is less or equal to 2
519
boolean enable_logging = true;
520         if (io_safety_level <= 2) {
521           Debug().write(Lvl.MESSAGE, this,
522                         "Disabling journaling and file sync.");
523           enable_logging = false;
524         }
525
526         // If the configuration property 'use_nio_if_available' is enabled then
527
// we setup a LoggingBufferManager that uses NIO (default to 'false')
528
boolean use_nio_if_available =
529                                 getConfigBoolean("use_nio_if_available", false);
530         boolean force_use_nio = getConfigBoolean("force_use_nio", false);
531       
532         String JavaDoc api_to_use;
533         int page_size;
534         int max_pages;
535
536         final boolean disable_nio = true;
537         
538         // If NIO interface available and configuration tells us to use NIO and
539
// we are not running on an OS where NIO is buggy, we set the NIO options
540
// here.
541
if ( !disable_nio &&
542              ( force_use_nio ||
543                ( nio_interface_available &&
544                  use_nio_if_available &&
545                  !nio_bugged_os ))) {
546           Debug().write(Lvl.MESSAGE, this,
547                         "Using NIO API for OS memory mapped file access.");
548           page_size = getConfigInt("buffered_nio_page_size", 1024 * 1024);
549           max_pages = getConfigInt("buffered_nio_max_pages", 64);
550           api_to_use = "Java NIO";
551         }
552         else {
553           Debug().write(Lvl.MESSAGE, this,
554                         "Using stardard IO API for heap buffered file access.");
555           page_size = getConfigInt("buffered_io_page_size", 8192);
556           max_pages = getConfigInt("buffered_io_max_pages", 256);
557           api_to_use = "Java IO";
558         }
559
560         // Output this information to the log
561
Debug().write(Lvl.MESSAGE, this,
562                       "[Buffer Manager] Using IO API: " + api_to_use);
563         Debug().write(Lvl.MESSAGE, this,
564                       "[Buffer Manager] Page Size: " + page_size);
565         Debug().write(Lvl.MESSAGE, this,
566                       "[Buffer Manager] Max pages: " + max_pages);
567
568         // Journal path is currently always the same as database path.
569
final File JavaDoc journal_path = db_path;
570         // Max slice size is 1 GB for file scattering class
571
final long max_slice_size = 16384 * 65536;
572         // First file extention is 'koi'
573
final String JavaDoc first_file_ext = "koi";
574
575         // Set up the BufferManager
576
buffer_manager = new LoggingBufferManager(
577               db_path, journal_path, read_only_access, max_pages, page_size,
578               first_file_ext, max_slice_size, Debug(), enable_logging);
579         // ^ This is a big constructor. It sets up the logging manager and
580
// sets a resource store data accessor converter to a scattering
581
// implementation with a max slice size of 1 GB
582

583         // Start the buffer manager.
584
try {
585           buffer_manager.start();
586         }
587         catch (IOException JavaDoc e) {
588           Debug().write(Lvl.ERROR, this, "Error starting buffer manager");
589           Debug().writeException(Lvl.ERROR, e);
590           throw new Error JavaDoc("IO Error: " + e.getMessage());
591         }
592
593       }
594
595       // What regular expression library are we using?
596
// If we want the engine to support other regular expression libraries
597
// then include the additional entries here.
598

599       // Test to see if the regex API exists
600
boolean regex_api_exists;
601       try {
602         Class.forName("java.util.regex.Pattern");
603         regex_api_exists = true;
604       }
605       catch (ClassNotFoundException JavaDoc e) {
606         // Internal API doesn't exist
607
regex_api_exists = false;
608         Debug().write(Lvl.MESSAGE, this,
609                       "Java regex API not available.");
610       }
611
612       String JavaDoc regex_bridge;
613       String JavaDoc lib_used;
614       
615       String JavaDoc force_lib = getConfigString("force_regex_library", null);
616
617       // Are we forcing a particular regular expression library?
618
if (force_lib != null) {
619         lib_used = force_lib;
620         // Convert the library string to a class name
621
regex_bridge = regexStringToClass(force_lib);
622       }
623       else {
624         String JavaDoc lib = getConfigString("regex_library", null);
625         lib_used = lib;
626         // Use the standard Java 1.4 regular expression library if it is found.
627
if (regex_api_exists) {
628           regex_bridge = "com.mckoi.database.regexbridge.JavaRegex";
629         }
630         else if (lib != null) {
631           // Convert the library string to a class name
632
regex_bridge = regexStringToClass(lib);
633         }
634         else {
635           regex_bridge = null;
636         }
637       }
638
639       if (regex_bridge != null) {
640         try {
641           Class JavaDoc c = Class.forName(regex_bridge);
642           regex_library = (RegexLibrary) c.newInstance();
643           Debug().write(Lvl.MESSAGE, this,
644                         "Using regex bridge: " + lib_used);
645         }
646         catch (Throwable JavaDoc e) {
647           Debug().write(Lvl.ERROR, this,
648                       "Unable to load regex bridge: " + regex_bridge);
649           Debug().writeException(Lvl.WARNING, e);
650         }
651       }
652       else {
653         if (lib_used != null) {
654           Debug().write(Lvl.ERROR, this,
655                         "Regex library not known: " + lib_used);
656         }
657         Debug().write(Lvl.MESSAGE, this,
658                       "Regex features disabled.");
659       }
660
661       // ---------- Plug ins ---------
662

663       try {
664         // The 'function_factories' property.
665
String JavaDoc function_factories =
666                                  getConfigString("function_factories", null);
667         if (function_factories != null) {
668           List JavaDoc factories = StringUtil.explode(function_factories, ";");
669           for (int i = 0; i < factories.size(); ++i) {
670             String JavaDoc factory_class = factories.get(i).toString();
671             Class JavaDoc c = Class.forName(factory_class);
672             FunctionFactory fun_factory = (FunctionFactory) c.newInstance();
673             addFunctionFactory(fun_factory);
674             Debug().write(Lvl.MESSAGE, this,
675                     "Successfully added function factory: " + factory_class);
676           }
677         }
678         else {
679           Debug().write(Lvl.MESSAGE, this,
680                       "No 'function_factories' config property found.");
681           // If resource missing, do nothing...
682
}
683       }
684       catch (Throwable JavaDoc e) {
685         Debug().write(Lvl.ERROR, this,
686                 "Error parsing 'function_factories' configuration property.");
687         Debug().writeException(e);
688       }
689
690       // Flush the contents of the function lookup object.
691
flushCachedFunctionLookup();
692
693     }
694
695   }
696
697   /**
698    * Hack - set up the DataCellCache in DatabaseSystem so we can use the
699    * MasterTableDataSource object without having to boot a new DatabaseSystem.
700    */

701   public void setupRowCache(int max_cache_size,
702                             int max_cache_entry_size) {
703     // Set up the data_cell_cache
704
data_cell_cache =
705                new DataCellCache(this, max_cache_size, max_cache_entry_size);
706   }
707
708   /**
709    * Returns true if the database is in read only mode. In read only mode,
710    * any 'write' operations are not permitted.
711    */

712   public boolean readOnlyAccess() {
713     return read_only_access;
714   }
715
716   /**
717    * Returns the path of the database in the local file system if the database
718    * exists within the local file system. If the database is not within the
719    * local file system then null is returned. It is recommended this method
720    * is not used unless for legacy or compatability purposes.
721    */

722   public File JavaDoc getDatabasePath() {
723     return db_path;
724   }
725   
726   /**
727    * Returns true if the database should perform checking of table locks.
728    */

729   public boolean tableLockingEnabled() {
730     return table_lock_check;
731   }
732
733   /**
734    * Returns true if we should generate lookup caches in InsertSearch otherwise
735    * returns false.
736    */

737   public boolean lookupComparisonListEnabled() {
738     return lookup_comparison_list_enabled;
739   }
740
741   /**
742    * Returns true if all table indices are kept behind a soft reference that
743    * can be garbage collected.
744    */

745   public boolean softIndexStorage() {
746     return soft_index_storage;
747   }
748
749   /**
750    * Returns the status of the 'always_reindex_dirty_tables' property.
751    */

752   public boolean alwaysReindexDirtyTables() {
753     return always_reindex_dirty_tables;
754   }
755
756   /**
757    * Returns true if we shouldn't synchronize with the file system when
758    * important indexing information is flushed to the disk.
759    */

760   public boolean dontSynchFileSystem() {
761     return dont_synch_filesystem;
762   }
763
764   /**
765    * Returns true if during commit the engine should look for any selects
766    * on a modified table and fail if they are detected.
767    */

768   public boolean transactionErrorOnDirtySelect() {
769     return transaction_error_on_dirty_select;
770   }
771
772   /**
773    * Returns true if the parser should ignore case when searching for
774    * schema/table/column identifiers.
775    */

776   public boolean ignoreIdentifierCase() {
777     return ignore_case_for_identifiers;
778   }
779
780   /**
781    * Returns the LoggingBufferManager object enabling us to create no file
782    * stores in the file system. This provides access to the buffer scheme that
783    * has been configured.
784    */

785   public LoggingBufferManager getBufferManager() {
786     return buffer_manager;
787   }
788   
789   /**
790    * Returns the regular expression library from the configuration file.
791    */

792   public RegexLibrary getRegexLibrary() {
793     if (regex_library != null) {
794       return regex_library;
795     }
796     throw new Error JavaDoc("No regular expression library found in classpath " +
797                     "and/or in configuration file.");
798   }
799
800   // ---------- Store System encapsulation ----------
801

802   /**
803    * Returns the StoreSystem encapsulation being used in this database.
804    */

805   public final StoreSystem storeSystem() {
806     return store_system;
807   }
808   
809   // ---------- Debug logger methods ----------
810

811   /**
812    * Sets the Writer output for the debug logger.
813    */

814   public final void setDebugOutput(java.io.Writer JavaDoc writer) {
815 // System.out.println("**** Setting debug log output ****" + writer);
816
// System.out.println(logger);
817
logger.setOutput(writer);
818   }
819
820   /**
821    * Sets the debug minimum level that is output to the logger.
822    */

823   public final void setDebugLevel(int level) {
824     logger.setDebugLevel(level);
825   }
826
827   /**
828    * Returns the DebugLogger object that is used to log debug message. This
829    * method must always return a debug logger that we can log to.
830    */

831   public final DebugLogger Debug() {
832     return logger;
833   }
834
835   // ---------- Function factories ----------
836

837   /**
838    * Registers a new FunctionFactory with the database system. The function
839    * factories are used to resolve a function name into a Function object.
840    * Function factories are checked in the order they are added to the database
841    * system.
842    */

843   public void addFunctionFactory(FunctionFactory factory) {
844     synchronized (function_factory_list) {
845       function_factory_list.add(factory);
846     }
847     factory.init();
848   }
849
850   /**
851    * Flushes the 'FunctionLookup' object returned by the getFunctionLookup
852    * method. This should be called if the function factory list has been
853    * modified in some way.
854    */

855   public void flushCachedFunctionLookup() {
856     FunctionFactory[] factories;
857     synchronized (function_factory_list) {
858       factories = (FunctionFactory[]) function_factory_list.toArray(
859                           new FunctionFactory[function_factory_list.size()]);
860     }
861     function_lookup.flushContents(factories);
862   }
863
864   /**
865    * Returns a FunctionLookup object that will search through the function
866    * factories in this database system and find and resolve a function. The
867    * returned object may throw an exception from the 'generateFunction' method
868    * if the FunctionDef is invalid. For example, if the number of parameters
869    * is incorrect or the name can not be found.
870    */

871   public FunctionLookup getFunctionLookup() {
872     return function_lookup;
873   }
874
875   // ---------- System preparers ----------
876

877   /**
878    * Given a Transaction.CheckExpression, this will prepare the expression and
879    * return a new prepared CheckExpression. The default implementation of this
880    * is to do nothing. However, a sub-class of the system choose to prepare
881    * the expression, such as resolving the functions via the function lookup,
882    * and resolving the sub-queries, etc.
883    */

884   public Transaction.CheckExpression prepareTransactionCheckConstraint(
885                  DataTableDef table_def, Transaction.CheckExpression check) {
886
887 // ExpressionPreparer expression_preparer = getFunctionExpressionPreparer();
888
// Resolve the expression to this table and row and evaluate the
889
// check constraint.
890
Expression exp = check.expression;
891     table_def.resolveColumns(ignoreIdentifierCase(), exp);
892 // try {
893
// // Prepare the functions
894
// exp.prepare(expression_preparer);
895
// }
896
// catch (Exception e) {
897
// Debug().writeException(e);
898
// throw new RuntimeException(e.getMessage());
899
// }
900

901     return check;
902   }
903
904   // ---------- Database System Statistics Methods ----------
905

906   /**
907    * Returns a com.mckoi.util.Stats object that can be used to keep track
908    * of database statistics for this VM.
909    */

910   public final Stats stats() {
911     return stats;
912   }
913
914   // ---------- Log directory management ----------
915

916   /**
917    * Sets the log directory. This should preferably be called during
918    * initialization. If the log directory is not set or is set to 'null' then
919    * no logging to files occurs.
920    */

921   public final void setLogDirectory(File JavaDoc log_path) {
922     this.log_directory = log_path;
923   }
924
925   /**
926    * Returns the current log directory or null if no logging should occur.
927    */

928   public final File JavaDoc getLogDirectory() {
929     return log_directory;
930   }
931
932   // ---------- Cache Methods ----------
933

934   /**
935    * Returns a DataCellCache object that is a shared resource between all
936    * database's running on this VM. If this returns 'null' then the internal
937    * cache is disabled.
938    */

939   DataCellCache getDataCellCache() {
940     return data_cell_cache;
941   }
942
943   // ---------- Dispatch methods ----------
944

945   /**
946    * The dispatcher.
947    */

948   private DatabaseDispatcher dispatcher;
949
950   /**
951    * Returns the DatabaseDispatcher object.
952    */

953   private DatabaseDispatcher getDispatcher() {
954     synchronized (this) {
955       if (dispatcher == null) {
956         dispatcher = new DatabaseDispatcher(this);
957       }
958       return dispatcher;
959     }
960   }
961
962   /**
963    * Creates an event object that is passed into 'postEvent' method
964    * to run the given Runnable method after the time has passed.
965    * <p>
966    * The event created here can be safely posted on the event queue as many
967    * times as you like. It's useful to create an event as a persistant object
968    * to service some event. Just post it on the dispatcher when you want
969    * it run!
970    */

971   Object JavaDoc createEvent(Runnable JavaDoc runnable) {
972     return getDispatcher().createEvent(runnable);
973   }
974
975   /**
976    * Adds a new event to be dispatched on the queue after 'time_to_wait'
977    * milliseconds has passed.
978    * <p>
979    * 'event' must be an event object returned via 'createEvent'.
980    */

981   void postEvent(int time_to_wait, Object JavaDoc event) {
982     getDispatcher().postEvent(time_to_wait, event);
983   }
984
985
986   /**
987    * Disposes this object.
988    */

989   public void dispose() {
990     if (buffer_manager != null) {
991       try {
992         // Set a check point
993
store_system.setCheckPoint();
994         // Stop the buffer manager
995
buffer_manager.stop();
996       }
997       catch (IOException JavaDoc e) {
998         System.out.println("Error stopping buffer manager.");
999         e.printStackTrace();
1000      }
1001    }
1002    buffer_manager = null;
1003    regex_library = null;
1004    data_cell_cache = null;
1005    config = null;
1006    log_directory = null;
1007    function_factory_list = null;
1008    store_system = null;
1009    if (dispatcher != null) {
1010      dispatcher.finish();
1011    }
1012// trigger_manager = null;
1013
dispatcher = null;
1014  }
1015
1016
1017  // ---------- Inner classes ----------
1018

1019  /**
1020   * A FunctionLookup implementation that will look up a function from a
1021   * list of FunctionFactory objects provided with.
1022   */

1023  private static class DSFunctionLookup implements FunctionLookup {
1024
1025    private FunctionFactory[] factories;
1026
1027    public synchronized Function generateFunction(FunctionDef function_def) {
1028      for (int i = 0; i < factories.length; ++i) {
1029        Function f = factories[i].generateFunction(function_def);
1030        if (f != null) {
1031          return f;
1032        }
1033      }
1034      return null;
1035    }
1036    
1037    public synchronized boolean isAggregate(FunctionDef function_def) {
1038      for (int i = 0; i < factories.length; ++i) {
1039        FunctionInfo f_info =
1040                         factories[i].getFunctionInfo(function_def.getName());
1041        if (f_info != null) {
1042          return f_info.getType() == FunctionInfo.AGGREGATE;
1043        }
1044      }
1045      return false;
1046    }
1047
1048    public synchronized void flushContents(FunctionFactory[] factories) {
1049      this.factories = factories;
1050    }
1051
1052  }
1053
1054}
1055
Popular Tags