KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ozoneDB > core > Env


1 // You can redistribute this software and/or modify it under the terms of
2
// the Ozone Core License version 1 published by ozone-db.org.
3
//
4
// The original code and portions created by SMB are
5
// Copyright (C) 1997-@year@ by SMB GmbH. All rights reserved.
6
//
7
// $Id: Env.java,v 1.13.2.2 2003/12/21 16:01:23 per_nyfelt Exp $
8

9 package org.ozoneDB.core;
10
11 import java.io.*;
12 import java.lang.reflect.Constructor JavaDoc;
13 import java.util.StringTokenizer JavaDoc;
14
15 import org.ozoneDB.Database;
16 import org.ozoneDB.DxLib.*;
17 import org.ozoneDB.Setup;
18 import org.ozoneDB.core.admin.AdminManager;
19 import org.ozoneDB.core.dr.DeadlockRecognition;
20 import org.ozoneDB.core.dr.EdgeChasing;
21 import org.ozoneDB.OzoneInterface;
22 import org.ozoneDB.util.*;
23
24
25 /**
26  * Env is the environment of a ozone database server. Currently there
27  * is only one environment allowed per JVM. A server environment can be
28  * initialized by the a Server or by a LocalDatabase.
29  *
30  *
31  * @author <a HREF="http://www.softwarebuero.de/">SMB</a>
32  * @author <a HREF="http://www.medium.net/">Medium.net</a>
33  * @author Per Nyfelt
34  * @version $Revision: 1.13.2.2 $Date: 2003/12/21 16:01:23 $
35  */

36 public final class Env {
37
38     /**
39      Wether ozone should do selfChecks at different code locations.
40      If set to true, diagnostic messages are printed out
41      in case something unusual or bad has been detected.
42      If set to false, ozone will run at full speed.
43
44      This is a kind of "poor man"s assertion facility as long as
45      ozone should be compileable by javac older than from JDK1.4
46      TODO now that we require 1.4 this can be upgraded to use asserts instead
47      */

48     public final static boolean selfCheck = true;
49
50     // constant members ***********************************
51
public final static String JavaDoc VERSION = "@version@";
52     public final static String JavaDoc OS_DIR = "ostab";
53     public final static String JavaDoc STATE_FILE = "state.properties";
54     public final static String JavaDoc CONFIG_FILE = "config.properties";
55     public final static String JavaDoc DATA_DIR = "data" + File.separator;
56     public final static String JavaDoc STATS_DIR = "stats";
57
58     /**
59      * AdminPort and InvokeServer accepts and admin requests
60      */

61     public final static int ACCEPT_THREAD_PRIORITY = Thread.NORM_PRIORITY + 2;
62
63     /**
64      * Thread priority of normal transaction.
65      */

66     public final static int TRANSACTION_THREAD_PRIORITY = Thread.NORM_PRIORITY;
67
68     public final static int TRANSACTION_MUTEX_PRIORITY = TRANSACTION_THREAD_PRIORITY + 1;
69
70     /**
71      * Thread priority deadlock recognition.
72      */

73     public final static int DEADLOCK_THREAD_PRIORITY = Thread.NORM_PRIORITY;
74
75     /**
76      * Priority of the server thread (Server.main())
77      */

78     public final static int SERVER_THREAD_PRIORITY = Thread.NORM_PRIORITY + 2;
79
80
81     // class members **************************************
82

83     /**
84      * The one and only ozone environment of this VM.
85      */

86     public static Env theEnv;
87
88     protected static OzoneSecurityManager securityManager;
89
90
91     // instance members ***********************************
92

93     protected File databaseDir;
94
95     /**
96      * Holds the content of the 'state.properties' file. After
97      * changing the content the state must be written to disk to make
98      * changes persistent.
99      */

100     public Setup state;
101
102     /**
103      * Holds the content of the 'config.properties' config file.
104      */

105     public Setup config;
106
107     public LogWriter logWriter;
108
109     /**
110      * This indicates that we are about to shutdown.
111      */

112     public boolean shuttingdown = false;
113
114     /*
115      * The total memory of this VM.
116      */

117     protected long totalMemory;
118
119     /*
120      * The amount of memory that should be kept free.
121      */

122     protected long keepMemory;
123
124     /**
125      * Interface for the database objects inside the server.
126      */

127     public Database database;
128
129     private DxBag components;
130
131     public KeyGenerator keyGenerator;
132
133     public AdminManager adminManager;
134
135     public ClassManager classManager;
136
137     public TransactionManager transactionManager;
138
139     public StoreManager storeManager;
140
141     public UserManager userManager;
142
143     protected LocalClientTracker localClientTracker;
144
145     protected GarbageCollector garbageCollector;
146
147     protected InvokeServer invokeServer;
148
149     protected DeadlockThread deadlockThread;
150
151     protected DeadlockRecognition dr;
152
153
154     // class methods **************************************
155

156     /**
157      * Returns the environment of the current thread. Useful for objects that
158      * do not store the enviroment itself like ObjectContainer.
159      *
160      *
161      * @return The environment of the current thread or null if called outside
162      * the server.
163      */

164     public static Env currentEnv() {
165         return theEnv;
166     }
167
168
169     // instance methods ***********************************
170

171     /**
172      * Construct a new ozone server environment.
173      *
174      *
175      * @param dirName Directory of the database.
176      * @param debugLevel the debug level that should be used,
177      * overriding the entry in config.properties. If null then the
178      * config.properties entry will be used.
179      */

180     public Env(String JavaDoc dirName, String JavaDoc debugLevel) throws Exception JavaDoc {
181         if (theEnv != null) {
182             throw new Exception JavaDoc("ozone environment (Env) already initialized for this VM");
183         }
184
185         try {
186             // give the engine its environment first but don't forget to
187
// reset it if we catch an exception
188
theEnv = this;
189
190             //dir = new String( dirName ) + File.separator;
191
databaseDir = new File(dirName + File.separator);
192             if (!databaseDir.isDirectory()) {
193                 throw new Exception JavaDoc("No database found at '" + databaseDir + "'.");
194             }
195             checkJavaVersion();
196
197             initSetup();
198             initLogs(debugLevel);
199
200             getLogWriter().newEntry(this, "Ozone version @version@", LogWriter.INFO);
201             getLogWriter().newEntry(this, "Copyright (C) 1997-@year@ The Ozone Database Project", LogWriter.INFO);
202             getLogWriter().newEntry(this, "contains libraries from the Apache Software Foundation", LogWriter.INFO);
203             getLogWriter().newEntry(this, "contains libraries from SUN microsystems", LogWriter.INFO);
204             getLogWriter().newEntry(this, "contains libraries from the W3C", LogWriter.INFO);
205             getLogWriter().newEntry(this, "contains libraries from Exoffice, Inc.", LogWriter.INFO);
206             getLogWriter().newEntry(this, "contains libraries (JavaClass) from Markus Dahm ", LogWriter.INFO);
207             getLogWriter().newEntry(this, "Copyright (C) under owner's respective terms.", LogWriter.INFO);
208
209             if (System.getSecurityManager() == null) {
210                 securityManager = new OzoneSecurityManager();
211                 System.setSecurityManager(securityManager);
212             }
213
214             calcMemory();
215
216             components = new DxArrayBag(16);
217
218             localClientTracker = new LocalClientTracker();
219
220             garbageCollector = new GarbageCollector(this);
221             components.add(garbageCollector);
222             garbageCollector.startup();
223
224             keyGenerator = new KeyGenerator(this);
225             components.add(keyGenerator);
226             keyGenerator.startup();
227
228             database = new Database(this);
229
230             classManager = new ClassManager(this);
231             components.add(classManager);
232             classManager.startup();
233
234             // UserManager has to be initialized before the recovery
235
userManager = new UserManager(this);
236             components.add(userManager);
237             userManager.startup();
238
239             transactionManager = new TransactionManager(this);
240             components.add(transactionManager);
241             transactionManager.startup();
242
243             // initialize the storeManager
244
String JavaDoc storeClassName = config.stringProperty(Setup.STORE, "org.ozoneDB.core.storage.wizardStore.WizardStore");
245             // todo: uncommented until verified when this should be removed
246
// We should not use Class.forName since it breaks hot deployment of classes
247
//Class storeClass = Class.forName(storeClassName);
248
Class JavaDoc storeClass = classManager.classForName(storeClassName);
249             if (storeClass == null) {
250                 getLogWriter().newEntry(this, "Store not found: " + storeClassName, LogWriter.ERROR);
251                 System.exit(1);
252             }
253             Constructor JavaDoc ctor = storeClass.getConstructor(new Class JavaDoc[]{Env.class});
254             storeManager = (StoreManager) ctor.newInstance(new Object JavaDoc[]{this});
255             storeManager.init(this);
256             components.add(storeManager);
257             storeManager.startup();
258
259             // initialize adminManager
260
adminManager = new AdminManager(this);
261             components.add(adminManager);
262             adminManager.startup();
263         } catch (Exception JavaDoc e) {
264             theEnv = null;
265             if (logWriter != null) {
266                 logWriter.newEntry(this, "Unable to initialize server.", e, LogWriter.ERROR);
267             } else {
268                 System.out.println("Unable to initialize server.");
269                 e.printStackTrace();
270             }
271             throw e;
272         }
273     }
274
275     /** Makes sure the server is running at the required minimum version level */
276     private void checkJavaVersion() throws Exception JavaDoc {
277         String JavaDoc javaVersion = System.getProperty("java.version");
278         StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(javaVersion, ".");
279
280         int majorVersion = 0;
281         if (tokenizer.hasMoreTokens()) {
282             majorVersion = Integer.parseInt(tokenizer.nextToken());
283         }
284         int minorVersion = 0;
285         if (tokenizer.hasMoreTokens()) {
286             minorVersion = Integer.parseInt(tokenizer.nextToken());
287         }
288
289         if (majorVersion == 1 && minorVersion < 4) {
290             throw new Exception JavaDoc("Java version 1.4 or higher is required to run the server");
291         }
292     }
293
294
295     public void shutdown() {
296         shuttingdown = true;
297         try {
298             logWriter.newEntry(this, "shutdown...", LogWriter.INFO);
299
300             // if (storageFrame != null) {
301
// storageFrame.dispose();
302
// storageFrame = null;
303
// logWriter.newEntry (this, "ozonometer closed.", LogWriter.INFO);
304
// }
305
if (invokeServer != null) {
306                 invokeServer.shutdown();
307                 invokeServer = null;
308             }
309             if (deadlockThread != null) {
310                 //TODO: find another way to do this, stop() is deprecated
311
deadlockThread.stopRunning();
312                 deadlockThread = null;
313                 logWriter.newEntry(this, "Deadlock recognition stopped.", LogWriter.INFO);
314             }
315
316             transactionManager.shutdown();
317             transactionManager = null;
318
319             storeManager.shutdown();
320             storeManager = null;
321
322             userManager.shutdown();
323             userManager = null;
324
325             classManager.shutdown();
326             classManager = null;
327
328             keyGenerator.shutdown();
329             keyGenerator = null;
330
331             garbageCollector.shutdown();
332             garbageCollector = null;
333
334             storeSetup();
335
336             components = null;
337
338             logWriter.newEntry(this, "Halted.", LogWriter.INFO);
339             theEnv = null;
340         } catch (Exception JavaDoc e) {
341             fatalError(null, "Env.shutdown(): " + e.toString(), e);
342         }
343     }
344
345
346     public void startExternalEventProcessing() throws Exception JavaDoc {
347         try {
348             invokeServer = new InvokeServer(this, portNum());
349             invokeServer.startup();
350             invokeServer.accept();
351             logWriter.newEntry(this, "external event processing started", LogWriter.INFO);
352         } catch (Exception JavaDoc e) {
353             logWriter.newEntry(this,
354                                "Client port (" + portNum() + ") or admin port (" + adminPortNum() + ") are already in use.", e,
355                                LogWriter.ERROR);
356             throw e;
357         }
358     }
359
360
361     public void startDeadlockRecognition() {
362         logWriter.newEntry(this, "deadlock recognition started", LogWriter.INFO);
363         deadlockThread = new DeadlockThread(3000, transactionManager);
364         deadlockThread.setPriority(DEADLOCK_THREAD_PRIORITY);
365         deadlockThread.setDaemon(true);
366         deadlockThread.start();
367     }
368
369
370     /**
371      * Initialize the setup (state and config) of this server environment. When
372      * searching specific property look in setup file first, then in the
373      * properties file, then use defaults, then use System properties.
374      */

375     protected void initSetup() throws Exception JavaDoc {
376         Setup defaults = new Setup(this);
377         defaults.fillWithOzoneDefaults();
378
379         FileInputStream configIn = new FileInputStream(new File(databaseDir, CONFIG_FILE));
380         FileInputStream stateIn = new FileInputStream(new File(databaseDir, STATE_FILE));
381         try {
382             config = new Setup(this, defaults);
383             config.load(configIn);
384             config.addProperties(System.getProperties(), "ozoneDB.");
385             config.addProperties(System.getProperties(), "org.ozoneDB.");
386             //config.print( System.out, "ozoneDB.", " " );
387
// config.addObserver( this );
388

389             state = new Setup(this);
390             state.load(stateIn);
391             // state.addObserver( this );
392
} finally {
393             configIn.close();
394             stateIn.close();
395         }
396     }
397
398
399     public boolean isComponentStateChanged() {
400         boolean hasChanged = false;
401
402         DxIterator it = components.iterator();
403         while (it.next() != null) {
404             ServerComponent component = (ServerComponent) it.object();
405             if (component.hasChanged()) {
406                 hasChanged = true;
407             }
408         }
409         return hasChanged;
410     }
411
412
413     /**
414      * Save the setup (state and config) of the current server environment.
415      */

416     protected synchronized void storeSetup() {
417         logWriter.newEntry(this, "storeSetup()... ", LogWriter.DEBUG);
418
419         try {
420             // having all components updating their properties
421
DxIterator it = components.iterator();
422             while (it.next() != null) {
423                 ServerComponent component = (ServerComponent) it.object();
424                 if (component.hasChanged()) {
425                     logWriter.newEntry(this, " changed component: " + component, LogWriter.DEBUG);
426                     component.save();
427                     component.clearChanged();
428                 }
429             }
430
431             // actually save properties to disk
432
OutputStream stateOut = new BufferedOutputStream(new FileOutputStream(new File(databaseDir, STATE_FILE)));
433             OutputStream configOut = new BufferedOutputStream(new FileOutputStream(new File(databaseDir, CONFIG_FILE)));
434             try {
435                 // save state
436
state.store(stateOut, "Ozone Server State File.\n#Do not edit!");
437
438                 // save config
439
StringBuffer JavaDoc head = new StringBuffer JavaDoc(1024);
440                 head.append("Ozone Server Config File.\n");
441                 head.append("#\n");
442                 head.append("# Do not use comments. This file will be overwritten,\n");
443                 head.append("# if the config changes. See the ozone documentation\n");
444                 head.append("# for details about the properties and their values.\n");
445                 head.append("#\n");
446                 head.append("\n");
447                 head.append("# The below are not set to a default value so they are shown here as exmples \n");
448                 head.append("# of what can be set, see the configuration docs for details \n");
449                 head.append("# "+ Setup.TOTAL_MEMORY + "=16777216" +"\n");
450                 head.append("# "+ Setup.MIN_FREE_MEMORY + "=4194304" +"\n");
451                 config.store(configOut, head.toString());
452             } finally {
453                 stateOut.close();
454                 configOut.close();
455             }
456         } catch (Exception JavaDoc e) {
457             fatalError(this, "Unable to store server state.", e);
458         }
459     }
460
461
462     /**
463      * Initialize server logging. There are two LogTargets: stdout and file.
464      * Which log messages are written to which target is specified in the
465      * config file. If the server runs in debug mode, debug
466      * messages are written to each target.
467      * If debugLevelName is set to null the setting from the config.properties file is used
468      */

469     protected void initLogs(String JavaDoc debugLevelName) throws Exception JavaDoc {
470
471         if (debugLevelName == null) {
472             String JavaDoc defaultLevel = OzoneDebugLevel.INFO_STR;
473             debugLevelName = config.getProperty(Setup.LOG_LEVEL, defaultLevel);
474         }
475         System.out.println("logging level set to " + debugLevelName);
476         logWriter = new LogWriterLog4JImpl(databaseDir, OzoneDebugLevel.toLevel(debugLevelName));
477
478     }
479
480     /**
481      * Fires an error message and exits the VM
482      */

483     public void fatalError(Object JavaDoc sender, String JavaDoc msg, Exception JavaDoc e) {
484         logWriter.newEntry(sender, msg, e, LogWriter.ERROR);
485         // FIXME: shutdown???
486
if (theEnv != null) {
487             theEnv.shutdown();
488         }
489         System.exit(1);
490     }
491
492
493     public String JavaDoc getDatabaseDir() {
494         return databaseDir.getAbsolutePath() + File.separator;
495     }
496
497     public int dbID() {
498         return config.intProperty(Setup.DB_ID, -1);
499     }
500
501
502     public int portNum() {
503         return config.intProperty(Setup.PORT, -1);
504     }
505
506
507     public int adminPortNum() {
508         return config.intProperty(Setup.ADMIN_PORT, -1);
509     }
510
511
512     /**
513      * Factory method to create or re-use a DR object.
514      */

515     public DeadlockRecognition deadlockRecognition() {
516         if (dr == null) {
517             dr = new EdgeChasing(this);
518         }
519         return dr;
520     }
521
522
523     /**
524      * Initialize the internal memory counter so that freeMemory() returns
525      * correct results.
526      */

527     protected void calcMemory() {
528         Runtime JavaDoc rt = Runtime.getRuntime();
529
530         // suggested by Leo, might get cluster caching to work again
531
totalMemory = config.longProperty(Setup.TOTAL_MEMORY, -1);
532         //long totalMemory = config.longProperty(Setup.TOTAL_MEMORY, -1);
533

534         /*
535             Computing totalMemory this way is bad.
536             The reason is, that the reserved VM memory is increased to
537             maximum. This is not bad itself (despite the long startup time
538             induced due to swapout required to get to maximum possible memory).
539             It is bad, that after reaching maximum memory, the JavaVM thinks
540             that all that memory once reached is memory to be used. But because
541             this is only virtual memory, the JavaVM thus creates massive
542             swapping on using all the available memory, scattering all memory
543             accesses across the reserved memory area.
544
545             If the reserved memory area is smaller (as this is usually the case after
546             startup of a Java application), less real RAM is required, less swapping
547             will occur, with the same application running.
548
549             Because the behaviour is bad, we only revert to it if we do not get
550             any value set by the user for total memory.
551         */

552         if (totalMemory < 0) {
553             logWriter.newEntry(this, "checking memory... ", LogWriter.INFO);
554             try {
555                 DxBag bag = new DxArrayBag();
556                 for (; ;) {
557                     bag.add(new byte[100000]);
558                 }
559             } catch (OutOfMemoryError JavaDoc e) {
560                 totalMemory = rt.totalMemory();
561             }
562         }
563
564         long absoluteMinimumFreeMemoryRequest = config.longProperty(Setup.MIN_FREE_MEMORY, -1);
565
566         if (absoluteMinimumFreeMemoryRequest < 0) {
567             keepMemory = Math.min(4000000L, totalMemory / 10);
568         } else {
569             keepMemory = absoluteMinimumFreeMemoryRequest;
570         }
571
572         rt.gc();
573
574         logWriter.newEntry(this, " total: " + totalMemory, LogWriter.INFO);
575         logWriter.newEntry(this, " free : " + rt.freeMemory(), LogWriter.INFO);
576         logWriter.newEntry(this, " keep : " + keepMemory, LogWriter.INFO);
577     }
578
579
580     /**
581      * Return the amount of *total* free memory in the system. The results
582      * returned by Runtime.freeMemory() may change overtime and so its
583      * useless for ozone.
584      */

585     public long freeMemory() {
586         Runtime JavaDoc rt = Runtime.getRuntime();
587         long hiddenMemory = totalMemory - rt.totalMemory();
588
589         // keep xMB free at least
590
return Math.max(rt.freeMemory() + hiddenMemory - keepMemory, 0);
591     }
592
593     public LogWriter getLogWriter() {
594         return logWriter;
595     }
596
597     public TransactionManager getTransactionManager() {
598         return transactionManager;
599     }
600
601     public Setup getState() {
602         return state;
603     }
604
605     public InvokeServer getInvokeServer() {
606         return invokeServer;
607     }
608
609     public StoreManager getStoreManager() {
610         return storeManager;
611     }
612
613     public UserManager getUserManager() {
614         return userManager;
615     }
616
617     public GarbageCollector getGarbageCollector() {
618         return garbageCollector;
619     }
620
621     public LocalClientTracker getLocalClientTracker() {
622         return localClientTracker;
623     }
624
625     public OzoneInterface getDatabase() {
626         return database;
627     }
628 }
629
630
631 // :indentSize=4:tabSize=4:noTabs=true:
632
Popular Tags