Source Code Cross Referenced for Datafile.java in  » Database-DBMS » Quadcap-Embeddable-Database » com » quadcap » sql » file » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » Quadcap Embeddable Database » com.quadcap.sql.file 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package com.quadcap.sql.file;
002:
003:        /* Copyright 1999 - 2003 Quadcap Software.  All rights reserved.
004:         *
005:         * This software is distributed under the Quadcap Free Software License.
006:         * This software may be used or modified for any purpose, personal or
007:         * commercial.  Open Source redistributions are permitted.  Commercial
008:         * redistribution of larger works derived from, or works which bundle
009:         * this software requires a "Commercial Redistribution License"; see
010:         * http://www.quadcap.com/purchase.
011:         *
012:         * Redistributions qualify as "Open Source" under  one of the following terms:
013:         *   
014:         *    Redistributions are made at no charge beyond the reasonable cost of
015:         *    materials and delivery.
016:         *
017:         *    Redistributions are accompanied by a copy of the Source Code or by an
018:         *    irrevocable offer to provide a copy of the Source Code for up to three
019:         *    years at the cost of materials and delivery.  Such redistributions
020:         *    must allow further use, modification, and redistribution of the Source
021:         *    Code under substantially the same terms as this license.
022:         *
023:         * Redistributions of source code must retain the copyright notices as they
024:         * appear in each source code file, these license terms, and the
025:         * disclaimer/limitation of liability set forth as paragraph 6 below.
026:         *
027:         * Redistributions in binary form must reproduce this Copyright Notice,
028:         * these license terms, and the disclaimer/limitation of liability set
029:         * forth as paragraph 6 below, in the documentation and/or other materials
030:         * provided with the distribution.
031:         *
032:         * The Software is provided on an "AS IS" basis.  No warranty is
033:         * provided that the Software is free of defects, or fit for a
034:         * particular purpose.  
035:         *
036:         * Limitation of Liability. Quadcap Software shall not be liable
037:         * for any damages suffered by the Licensee or any third party resulting
038:         * from use of the Software.
039:         */
040:
041:        import java.io.ByteArrayOutputStream;
042:        import java.io.BufferedInputStream;
043:        import java.io.File;
044:        import java.io.FileOutputStream;
045:        import java.io.IOException;
046:        import java.io.InputStream;
047:        import java.io.OutputStream;
048:        import java.io.RandomAccessFile;
049:
050:        //#ifdef JDK14
051:        import java.nio.channels.FileChannel;
052:        import java.nio.channels.FileLock; //#endif
053:
054:        import java.util.HashMap;
055:        import java.util.Iterator;
056:        import java.util.Properties;
057:
058:        import com.quadcap.sql.lock.Lock;
059:        import com.quadcap.sql.lock.LockManager;
060:        import com.quadcap.sql.lock.LockMode;
061:        import com.quadcap.sql.lock.Transaction;
062:        import com.quadcap.sql.lock.TransactionObserver;
063:
064:        import com.quadcap.sql.types.Value;
065:
066:        import com.quadcap.util.collections.LongIterator;
067:        import com.quadcap.util.collections.LongMap;
068:
069:        import com.quadcap.util.ConfigNumber;
070:        import com.quadcap.util.ConfigString;
071:        import com.quadcap.util.Debug;
072:        import com.quadcap.util.Util;
073:
074:        /**
075:         * This class brings together the various file-level components of the
076:         * structured (SQL) database.
077:         *
078:         * @author Stan Bailes
079:         */
080:        abstract public class Datafile {
081:            protected boolean inMemory = false;
082:            String fileName;
083:
084:            protected DatafileRoot root;
085:            File dbRootDir;
086:            File tempDir;
087:            String url;
088:            protected String origFileName;
089:
090:            // "datafile"
091:            protected BlockFile file;
092:
093:            // "scratch"
094:            protected BlockFile tempFile;
095:
096:            // "log" file
097:            Log log;
098:
099:            // read/write table locks
100:            LockManager locks = null;
101:
102:            // Original connection properties
103:            Properties props;
104:
105:            static {
106:                try {
107:                    Class.forName("com.quadcap.sql.io.Extern");
108:                } catch (Throwable t) {
109:                }
110:            }
111:
112:            /** True if we've locked the lockfile */
113:            private FileChannel lockChannel = null;
114:            private FileLock lockLock = null;
115:
116:            protected boolean readOnly = false;
117:            protected byte[] temp = new byte[256];
118:
119:            protected Object fileLock = new Object();
120:
121:            private int tempFileRefCount = 0;
122:
123:            abstract public void maybeBackup() throws IOException;
124:
125:            abstract public void readRoot() throws IOException;
126:
127:            abstract public void createRoot(String fileName, Properties props)
128:                    throws IOException;
129:
130:            abstract public void flushRoot() throws IOException;
131:
132:            abstract public long getNextTransId() throws IOException;
133:
134:            abstract public void bootFromRoot(boolean restart)
135:                    throws IOException;
136:
137:            /**
138:             * Minimum cache size: 256K, with 8K blocks.  The minimum is
139:             * dependent on various factors, including query type (joins
140:             * need more cache, for example) and concurrency level.
141:             *
142:             * Simple applications which are primarily single threaded will
143:             * be able to get by with 32 blocks or so.
144:             */
145:            static final int MIN_CACHE = 32;
146:
147:            /**
148:             * Reasonable cache size: 4MB (8K blocks).  This cache size should
149:             * support a moderate load; 8-10 busy threads...
150:             */
151:            static final int GOOD_CACHE = 256;
152:
153:            /**
154:             * Reasonable scratch cache default
155:             */
156:            static final int SCRATCH_CACHE_DEFAULT = 64;
157:
158:            /*{com.quadcap.util.Config-vars.xml-1000}
159:             * <config-var>
160:             *   <config-name>qed.blockSize</config-name>
161:             *   <config-dflt>8192</config-dflt>
162:             *   <config-desc>The database block size.</config-desc>
163:             * </config-var>
164:             */
165:            static final int BLOCK_SIZE = ConfigNumber.find("qed.blockSize",
166:                    Integer.toString(8192)).intValue();
167:            int blockSize = BLOCK_SIZE;
168:
169:            /*{com.quadcap.util.Config-vars.xml-1001}
170:             * <config-var>
171:             *   <config-name>qed.cacheSize</config-name>
172:             *   <config-dflt>256 blocks</config-dflt>
173:             *   <config-desc>The database cache size.  A certain number of blocks
174:             *      are cached in an LRU cache;  this parameter controls the size
175:             *      of this cache.  32 is probably a the minimum for a single-threaded
176:             *      application; more threads increase cache requirements.
177:             *   </config-desc>
178:             * </config-var>
179:             */
180:            final ConfigNumber cacheSize = ConfigNumber.find("qed.cacheSize",
181:                    Integer.toString(GOOD_CACHE * BLOCK_SIZE));
182:            int CACHE_SIZE = Math.max(MIN_CACHE, cacheSize.intValue()
183:                    / BLOCK_SIZE);
184:
185:            /*{com.quadcap.util.Config-vars.xml-1002}
186:             * <config-var>
187:             *   <config-name>qed.scratchCacheSize</config-name>
188:             *   <config-dflt>32 blocks</config-dflt>
189:             *   <config-desc>The "temporary" file cache size.  A certain number of
190:             *          blocks in the scratch file (used for temporary tables and
191:             *          indexes) are cached in an LRU cache;  this parameter controls
192:             *          the size of this cache.
193:             *   </config-desc>
194:             * </config-var>
195:             */
196:            final ConfigNumber scratchCacheSize = ConfigNumber.find(
197:                    "qed.scratchCacheSize", Integer
198:                            .toString(SCRATCH_CACHE_DEFAULT * BLOCK_SIZE));
199:            int SCRATCH_CACHE_SIZE = Math.max(MIN_CACHE, scratchCacheSize
200:                    .intValue()
201:                    / BLOCK_SIZE);
202:
203:            /*{com.quadcap.util.Config-vars.xml-1003}
204:             * <config-var>
205:             *   <config-name>qed.defaultMode</config-name>
206:             *   <config-dflt>rw</config-dflt>
207:             *   <config-desc>The default database 'mode'.  Either 'r' or 'rw'
208:             *    </config-desc>
209:             * </config-var>
210:             */
211:            final ConfigString defaultMode = ConfigString.find(
212:                    "qed.defaultMode", "rw");
213:
214:            /*{com.quadcap.util.Config-vars.xml-1004}
215:             * <config-var>
216:             *   <config-name>qed.isCaseSensitive</config-name>
217:             *   <config-dflt>true</config-dflt>
218:             *   <config-desc>A boolean flag specifying whether string (VARCHAR)
219:             *      items are case-sensitive.
220:             *    </config-desc>
221:             * </config-var>
222:             */
223:            static final ConfigString caseSensitive = ConfigString.find(
224:                    "qed.isCaseSensitive", "true");
225:            // XXX This should *NOT* be static, but expediency forces it
226:            // XXX to be so for now.
227:            public static boolean isCaseSensitive = caseSensitive.toString()
228:                    .equalsIgnoreCase("true");
229:
230:            /**
231:             * Construct a new Datafile object, from the specified filename and mode.
232:             */
233:
234:            /*{com.quadcap.sql.Datafile-conn.xml-0}
235:             *
236:             * <config>
237:             */
238:
239:            /*{com.quadcap.sql.Datafile-conn.xml-999999}
240:             *
241:             * </config>
242:             */
243:
244:            public Datafile() {
245:            }
246:
247:            public void init(String url, String fileName, Properties props)
248:                    throws IOException {
249:                this .fileName = fileName;
250:                this .inMemory = props.getProperty("memoryOnly", "")
251:                        .equalsIgnoreCase("true");
252:                boolean nullStore = props.getProperty("cacheOnly", "")
253:                        .equalsIgnoreCase("true");
254:                if (inMemory || nullStore) {
255:                    initMemoryDatabase(url, fileName, props);
256:                } else {
257:                    initFileDatabase(url, fileName, props);
258:                }
259:            }
260:
261:            public void initMemoryDatabase(String url, String fileName,
262:                    Properties props) throws IOException {
263:                this .inMemory = true;
264:                this .props = (Properties) props.clone();
265:                this .url = url;
266:                this .origFileName = fileName;
267:                this .readOnly = false;
268:
269:                String ics = props.getProperty("isCaseSensitive", caseSensitive
270:                        .toString());
271:                isCaseSensitive = ics.equalsIgnoreCase("true");
272:                Value.isCaseSensitive = isCaseSensitive;
273:                String bs = props.getProperty("blockSize");
274:                if (bs != null) {
275:                    blockSize = Integer.parseInt(bs);
276:                }
277:                String cs = props.getProperty("cacheSize");
278:                if (cs != null) {
279:                    CACHE_SIZE = Integer.parseInt(cs) / blockSize;
280:                }
281:                this .locks = new LockManager();
282:
283:                this .file = new BlockFile(fileName, "rw", props, blockSize,
284:                        CACHE_SIZE);
285:                this .fileLock = this .file.getLock();
286:                createRoot(fileName, props);
287:                try {
288:                    this .log = new Log3();
289:                } catch (Throwable t) {
290:                    throw new DatafileException("Error creating logger", t);
291:                }
292:                log.init(this , true, props);
293:                file.setLog(log);
294:
295:                //log.restoreBlocks();
296:                bootFromRoot(false);
297:            }
298:
299:            public void initFileDatabase(String url, String fileName,
300:                    Properties props) throws IOException {
301:                this .props = (Properties) props.clone();
302:                this .url = url;
303:                this .origFileName = fileName;
304:                fileName = new File(fileName).getAbsolutePath();
305:                this .dbRootDir = new File(fileName);
306:                boolean newDb = false;
307:                /*{com.quadcap.sql.Datafile-conn.xml-10}
308:                 * <config-var>
309:                 *   <config-name>mode</config-name>
310:                 *   <config-dflt>from Config: qed.defaultMode</config-dflt>
311:                 *   <config-desc>Read-only or read-write access to the database:
312:                 *      <ul>
313:                 *        <li><code><b>rw</b></code>: Read-write (the default)</li>
314:                 *        <li><code><b>r</b></code>:
315:                 *            Read-only, intended for deployment on read-only media
316:                 *        </li>
317:                 *      </ul>
318:                 *   </config-desc>
319:                 * </config-var>
320:                 */
321:                String mode = props.getProperty("mode", defaultMode.toString());
322:                this .readOnly = mode.equalsIgnoreCase("r");
323:
324:                /*{com.quadcap.sql.Datafile-conn.xml-11}
325:                 * <config-var>
326:                 *   <config-name>isCaseSensitive</config-name>
327:                 *   <config-dflt>from Config: qed.isCaseSensitive</config-dflt>
328:                 *   <config-desc>A boolean flag specifying whether string (VARCHAR)
329:                 *      items are case-sensitive.
330:                 *   </config-desc>
331:                 * </config-var>
332:                 */
333:                String ics = props.getProperty("isCaseSensitive", caseSensitive
334:                        .toString());
335:                isCaseSensitive = ics.equalsIgnoreCase("true");
336:                Value.isCaseSensitive = isCaseSensitive;
337:
338:                /*{com.quadcap.sql.Datafile-conn.xml-12}
339:                 * <config-var>
340:                 *   <config-name>create</config-name>
341:                 *   <config-dflt>false</config-dflt>
342:                 *   <config-desc>If <code>"true"</code>, the database will be
343:                 *      created if it doesn't already exist. 
344:                 *   </config-desc>
345:                 * </config-var>
346:                 */
347:                String create = props.getProperty("create", "false");
348:                if (!dbRootDir.isDirectory()) {
349:                    if (readOnly) {
350:                        throw new IOException("Can't open database: "
351:                                + fileName);
352:                    }
353:                    if (!create.equalsIgnoreCase("true")) {
354:                        throw new IOException("Can't open database: "
355:                                + fileName);
356:                    }
357:                    newDb = true;
358:                    if (!dbRootDir.mkdirs()) {
359:                        throw new IOException("Can't create directory: "
360:                                + fileName);
361:                    }
362:                }
363:
364:                /*{com.quadcap.sql.Datafile-conn.xml-13}
365:                 * <config-var>
366:                 *   <config-name>blockSize</config-name>
367:                 *   <config-dflt>from Config:
368:                 *                qed.blockSize</config-dflt>
369:                 *   <config-desc>The database block size, which must be a
370:                 *      power of two.
371:                 *      Maximum size: 32768, Minimum recommended size: 4096.
372:                 *   </config-desc>
373:                 * </config-var>
374:                 */
375:                String bs = props.getProperty("blockSize");
376:                if (bs != null) {
377:                    blockSize = Integer.parseInt(bs);
378:                }
379:
380:                /*{com.quadcap.sql.Datafile-conn.xml-14}
381:                 * <config-var>
382:                 *   <config-name>cacheSize</config-name>
383:                 *   <config-dflt>from Config:
384:                 *                qed.cacheSize</config-dflt>
385:                 *   <config-desc>The database cache size.  A certain number of blocks
386:                 *      are cached in an LRU cache;  this parameter controls the size
387:                 *      of this cache.</config-desc>
388:                 * </config-var>
389:                 */
390:                String cs = props.getProperty("cacheSize");
391:                if (cs != null) {
392:                    CACHE_SIZE = Integer.parseInt(cs) / blockSize;
393:                }
394:
395:                /*{com.quadcap.sql.Datafile-conn.xml-15}
396:                 * <config-var>
397:                 *   <config-name>scratchCacheSize</config-name>
398:                 *   <config-dflt>from Config:
399:                 *                qed.scratchCacheSize</config-dflt>
400:                 *   <config-desc>The database scratch cache size, used for caching access
401:                 *      to the database temporary (or "scratch") file.
402:                 *      A certain number of blocks are cached in an LRU cache;
403:                 *      this parameter controls the size
404:                 *      of this cache.</config-desc>
405:                 * </config-var>
406:                 */
407:                String scs = props.getProperty("scratchCacheSize");
408:                if (scs != null) {
409:                    SCRATCH_CACHE_SIZE = Integer.parseInt(scs) / blockSize;
410:                }
411:
412:                /*{com.quadcap.sql.Datafile-conn.xml-16}
413:                 * <config-var>
414:                 *   <config-name>useLockFile</config-name>
415:                 *   <config-dflt>true</config-dflt>
416:                 *   <config-desc>A boolean.  If <b>true</b>, a lock file will
417:                 *      be used to protect from database corruption which might
418:                 *      result from multiple processes accessing the same database
419:                 *      simultaneously.</config-desc>
420:                 * </config-var>
421:                 */
422:                String lf = props.getProperty("useLockFile", "true");
423:                boolean useLockFile = lf.equalsIgnoreCase("true");
424:
425:                try {
426:                    File g = new File(dbRootDir, "datafile");
427:                    if (!g.exists()) {
428:                        if (readOnly) {
429:                            throw new IOException("Can't open database: "
430:                                    + fileName);
431:                        }
432:                        newDb = true;
433:                    }
434:
435:                    if (!readOnly && useLockFile) {
436:                        File k = new File(dbRootDir, "lockfile");
437:                        //#ifdef JDK14
438:                        lockChannel = new RandomAccessFile(k, "rw")
439:                                .getChannel();
440:                        lockLock = lockChannel.tryLock();
441:                        if (lockLock == null) {
442:                            /*{com.quadcap.sql.Datafile-conn.xml-18}
443:                             * <config-var>
444:                             *   <config-name>force</config-name>
445:                             *   <config-dflt>false</config-dflt>
446:                             *   <config-desc>QED uses a lockfile to prevent multiple
447:                             *      JVMs from accessing the database files
448:                             *      simultaneously, which could lead to database
449:                             *      corruption.  When the JVM exits normally, this
450:                             *      lockfile is deleted.  If the JVM exits abnormally
451:                             *      the lockfile may be left behind, and subsequent
452:                             *      attempts to access the database will fail because
453:                             *      of the old lockfile.  If <b>force</b> is
454:                             *      <code>true</code>, the database connection will
455:                             *      succeed even if the lockfile is present.
456:                             *      This option should be used with extreme care,
457:                             *      since if there really is another process accessing
458:                             *      the database, corruption may result.</config-desc>
459:                             * </config-var>
460:                             */
461:                            String force = props.getProperty("force", "false");
462:                            if (!force.equalsIgnoreCase("true")) {
463:                                throw new IOException(
464:                                        "lockfile already exists.  Maybe another "
465:                                                + "process is accessing the database?");
466:                            }
467:                        }
468:                        //#endif
469:                    }
470:                    makeTempDirectory(props);
471:                    this .locks = new LockManager();
472:
473:                    String gFileName = g.getAbsolutePath();
474:                    this .file = new BlockFile(gFileName, mode, props,
475:                            blockSize, CACHE_SIZE);
476:                    this .fileLock = this .file.getLock();
477:                    if (!newDb) {
478:                        try {
479:                            readRoot();
480:                        } catch (IOException ex) {
481:                            if (ex.toString().indexOf("magic") > 0) {
482:                                throw new IOException(
483:                                        "Database Connection Failed: Possible bad authorization");
484:                            } else {
485:                                throw ex;
486:                            }
487:                        }
488:                    } else {
489:                        createRoot(fileName, props);
490:                    }
491:                    if (!readOnly) {
492:                        /*{com.quadcap.sql.Datafile-conn.xml-20}
493:                         * <config-var>
494:                         *   <config-name>logger</config-name>
495:                         *   <config-dflt>2</config-dflt>
496:                         *   <config-desc>If no transaction logging is required
497:                         *   (i.e., no rollback or recovery), then use '0'.
498:                         *   Otherwise, use '2', (the default)</config-desc>
499:                         * </config-var>
500:                         */
501:                        String ls = props.getProperty("logger");
502:                        if (ls == null)
503:                            ls = "2";
504:                        this .log = (Log) (Class
505:                                .forName("com.quadcap.sql.file.Log" + ls)
506:                                .newInstance());
507:                        log.init(this , newDb, props);
508:                        file.setLog(log);
509:                        if (!newDb) {
510:                            log.restoreBlocks();
511:                            file.revert();
512:                        }
513:                    }
514:                    bootFromRoot(!newDb);
515:                    if (!newDb) {
516:                        log.restart();
517:                    }
518:                    if (!readOnly) {
519:                        log.start();
520:                    }
521:                    log.checkpoint();
522:                } catch (IOException e) {
523:                    if (newDb && !readOnly)
524:                        deleteHalfBakedDir();
525:                    throw e;
526:                } catch (RuntimeException e) {
527:                    if (newDb && !readOnly)
528:                        deleteHalfBakedDir();
529:                    throw new DatafileException(e);
530:                } catch (Exception e) {
531:                    if (newDb && !readOnly)
532:                        deleteHalfBakedDir();
533:                    throw new DatafileException(e);
534:                }
535:            }
536:
537:            // i am a factor.  but at least I have a name!
538:            final private void deleteHalfBakedDir() {
539:                new File(dbRootDir, "datafile").delete();
540:                new File(dbRootDir, "lockfile").delete();
541:            }
542:
543:            /**
544:             * Accessor for my underlying file
545:             */
546:            public BlockFile getFile() {
547:                return file;
548:            }
549:
550:            /**
551:             * Return the JDBC URL used to connect to this database.
552:             */
553:            public String getURL() {
554:                return url;
555:            }
556:
557:            /**
558:             * Return a File representing the database root directory
559:             */
560:            File getDbRootDir() {
561:                return dbRootDir;
562:            }
563:
564:            /**
565:             * Return a File representing the database scratch/temp root directory
566:             */
567:            File getScratchDir() {
568:                return tempDir;
569:            }
570:
571:            /**
572:             * Accessor for the datbase's lock manager
573:             */
574:            public LockManager getLockManager() {
575:                return locks;
576:            }
577:
578:            /**
579:             * Accessor for file lock
580:             */
581:            public Object getFileLock() {
582:                return fileLock;
583:            }
584:
585:            /**
586:             * Is db read only?
587:             */
588:            public boolean isReadOnly() {
589:                return readOnly;
590:            }
591:
592:            /**
593:             * Return the specified persistent object from the store
594:             * @param ref the block number of the object's root
595:             * @return the object
596:             * @exception IOException may be thrown
597:             */
598:            public Object getObject(long ref) throws IOException {
599:                return file.getObject(ref);
600:            }
601:
602:            /**
603:             * Write a new object to the store and return its reference
604:             * @param obj the object
605:             * @return the block number of the object's root
606:             * @exception IOException may be thrown
607:             */
608:            public long putObject(Object obj) throws IOException {
609:                return file.putObject(obj);
610:            }
611:
612:            /**
613:             * Write a new version of a persistent object to the store.
614:             * @param blockNum the address of the object's root page in the store
615:             * @param obj the new object value
616:             *
617:             * @exception IOException may be thrown
618:             */
619:            public void updateObject(long seg, Object obj) throws IOException {
620:                file.updateObject(seg, obj);
621:            }
622:
623:            /**
624:             * Remove an object from the store
625:             * @param ref the block number of the object's root
626:             *
627:             * @exception IOException may be thrown
628:             */
629:            public void removeObject(long ref) throws IOException {
630:                file.removeObject(ref);
631:            }
632:
633:            /**
634:             * Hook which allows the scratch files to be written to a separate
635:             * directory.  Useful when you want to mount the data files read only
636:             */
637:            final void makeTempDirectory(Properties props) throws IOException {
638:                /*{com.quadcap.sql.Datafile-conn.xml-22}
639:                 * <config-var>
640:                 *   <config-name>scratchDir</config-name>
641:                 *   <config-dflt><i>database directory</i></config-dflt>
642:                 *   <config-desc>
643:                 *      Specify the directory where scratch files are written.  This
644:                 *      option is most useful in conjunction with <code>mode=r</code>,
645:                 *      where the database files can be located on read-only media,
646:                 *      and the scratch directory can be located separately.
647:                 *   </config-desc>
648:                 * </config-var>
649:                 */
650:                if (!inMemory) {
651:                    String tmpDirName = props.getProperty("scratchDir",
652:                            dbRootDir.getAbsolutePath());
653:                    this .tempDir = new File(tmpDirName);
654:                    if (!tempDir.isDirectory()) {
655:                        if (!tempDir.mkdirs()) {
656:                            throw new IOException(
657:                                    "Can't create temp directory: "
658:                                            + tmpDirName);
659:                        }
660:                    }
661:                }
662:            }
663:
664:            /**
665:             * The temporary file can be used for storage of non-transactionally-secure
666:             * data
667:             */
668:            public BlockFile getTempFile() throws IOException {
669:                return getTempFile(true);
670:            }
671:
672:            public BlockFile getTempFile(boolean incr) throws IOException {
673:                synchronized (fileLock) {
674:                    if (tempFile == null) {
675:                        if (inMemory) {
676:                            this .tempFile = new BlockFile(
677:                                    fileName + ".scratch", "rw", props,
678:                                    blockSize, SCRATCH_CACHE_SIZE);
679:                        } else {
680:                            File f = new File(tempDir, "scratch");
681:                            this .tempFile = new BlockFile(f.getAbsolutePath(),
682:                                    "rw", props, blockSize, SCRATCH_CACHE_SIZE);
683:                        }
684:                        this .tempFileRefCount = 0;
685:                    }
686:                    //Debug.println("Datafile.getTempFile(" + tempFileRefCount +
687:                    //              (incr ? (" -> " + (tempFileRefCount+1)) : "") +
688:                    //              ") @\n" + Util.stackTrace());
689:                    if (incr)
690:                        tempFileRefCount++;
691:                }
692:                return tempFile;
693:            }
694:
695:            public void releaseTempFile() {
696:                synchronized (fileLock) {
697:                    //Debug.println("Datafile.releaseTempFile(" + tempFileRefCount +
698:                    //              " -> " + (tempFileRefCount-1) + ") @\n" +
699:                    //              Util.stackTrace());
700:                    if (--tempFileRefCount == 0) {
701:                        clearTempFile();
702:                    }
703:                }
704:            }
705:
706:            /**
707:             * When nothing is happening, get rid of this guy.  Who needs him, eh?
708:             */
709:            void clearTempFile() {
710:                if (tempFile != null) {
711:                    //Debug.println("clearTempFile"); // XXX
712:                    if (inMemory) {
713:                        tempFile = null;
714:                    } else if (true) {
715:                        try {
716:                            tempFile.close();
717:                        } catch (Throwable e8) {
718:                        } finally {
719:                            tempFile = null;
720:                        }
721:                        try {
722:                            new File(dbRootDir, "scratch").delete();
723:                        } catch (Throwable e9) {
724:                        }
725:                    }
726:                }
727:            }
728:
729:            /**
730:             * Close the database.  Sync and close the physical file(s),
731:             * delete the tempfile(s) and lockfile.  Kill the database
732:             * reference monitor thread.
733:             */
734:            public void close() {
735:                if (file != null) {
736:                    //#ifdef TRACE
737:                    if (Trace.bit(12)) {
738:                        Debug.println("Datafile.close(" + dbRootDir.getPath()
739:                                + ")");
740:                    }
741:                    //#endif
742:                    try {
743:                        if (log != null) {
744:                            log.checkpoint();
745:                            log.sync();
746:                            log.close();
747:                            log.remove();
748:                        }
749:                    } catch (Throwable e8) {
750:                        Debug.print(e8);
751:                    } finally {
752:                        log = null;
753:                    }
754:
755:                    clearTempFile();
756:
757:                    try {
758:                        if (file != null)
759:                            file.close();
760:                    } catch (Throwable e2) {
761:                    }
762:
763:                    file = null;
764:                    try {
765:                        //#ifdef JDK14
766:                        if (lockLock != null) {
767:                            lockLock.release();
768:                            if (lockChannel != null)
769:                                lockChannel.close();
770:                            //new File(dbRootDir, "lockfile").delete();
771:                        }
772:                        //#endif
773:                    } catch (Throwable t) {
774:                    } finally {
775:                        //#ifdef JDK14
776:                        lockLock = null;
777:                        lockChannel = null;
778:                        //#endif
779:                    }
780:                }
781:            }
782:
783:            /**
784:             * Helper to create a new transaction, and optionally to write the
785:             * BEGIN_TRANSACTION log entry.
786:             */
787:            public final Transaction makeTransaction(boolean writeLog)
788:                    throws IOException {
789:                Transaction trans = null;
790:                long transId = -1;
791:                synchronized (fileLock) {
792:                    transId = getNextTransId();
793:                    trans = locks.getTransaction(transId);
794:                }
795:                if (writeLog) {
796:                    log.addEntry(new LogEntry(transId,
797:                            LogEntry.BEGIN_TRANSACTION));
798:                }
799:                return trans;
800:            }
801:
802:            /**
803:             * Commit the transaction
804:             */
805:            public void commitTransaction(Transaction trans) throws IOException {
806:                long transId = trans.getTransactionId();
807:                log.addEntry(new LogEntry(transId, LogEntry.COMMIT));
808:                log.flushLog();
809:                releaseLocks(trans);
810:            }
811:
812:            /**
813:             * Rollback the transaction
814:             */
815:            public void rollbackTransaction(Transaction trans)
816:                    throws IOException {
817:                log.rollbackTransaction(trans);
818:                commitTransaction(trans);
819:            }
820:
821:            /**
822:             * Rollback the specified statement.
823:             */
824:            public void rollbackStatement(Transaction trans, int stmtId)
825:                    throws IOException {
826:                log.rollbackStatement(trans, stmtId);
827:            }
828:
829:            /**
830:             * Remove the transaction for the given connection from the
831:             * 'active transactions' table.  Flush the log?
832:             */
833:            public void releaseLocks(Transaction trans) {
834:                locks.releaseTransaction(trans);
835:            }
836:
837:            /**
838:             * Find the specified transaction
839:             */
840:            public Transaction findTransaction(long transId) throws IOException {
841:                Transaction t = locks.findTransaction(transId);
842:                return t;
843:            }
844:
845:            /**
846:             * Return the log for this database
847:             */
848:            public final Log getLog() {
849:                return log;
850:            }
851:
852:            /**
853:             * If we get finalized, and haven't closed yet, then we should try.
854:             */
855:            public void finalize() throws Throwable {
856:                close();
857:                super .finalize();
858:            }
859:
860:            /**
861:             * Return the total size of the datafile, in bytes
862:             */
863:            public long getSize() {
864:                return file.getSize();
865:            }
866:
867:            /**
868:             * Reset the temp file (on checkpoint)
869:             */
870:            public void checkpoint(boolean truncate, boolean fastSync)
871:                    throws IOException {
872:                synchronized (fileLock) {
873:                    if (tempFile != null) {
874:                        tempFile.flush(fastSync);
875:                    }
876:                }
877:            }
878:
879:            public void checkpointHandler(LongMap activeTransactions)
880:                    throws IOException {
881:            }
882:
883:            //#ifdef DEBUG
884:            /**
885:             * Return a displayable representation for debugging purposes
886:             */
887:            public String toString() {
888:                String u = url;
889:                if (u.startsWith("jdbc:qed:"))
890:                    u = u.substring(9);
891:                int idx = u.indexOf(';');
892:                if (idx > 0)
893:                    u = u.substring(0, idx);
894:                return u;
895:            }
896:
897:            //#endif
898:
899:            public void doStep(Transaction t, LogEntry e) throws IOException,
900:                    DatafileException {
901:                log.addEntry(e);
902:                e.redo(t, this );
903:            }
904:
905:            public boolean inRecovery() throws IOException {
906:                return log != null && log.inRecovery();
907:            }
908:
909:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.