Source Code Cross Referenced for BaseDiskTable.java in  » Database-DBMS » axion » org » axiondb » engine » tables » 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 » axion » org.axiondb.engine.tables 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $Id: BaseDiskTable.java,v 1.36 2005/12/22 09:02:31 ahimanikya Exp $
0003:         * =======================================================================
0004:         * Copyright (c) 2002-2005 Axion Development Team.  All rights reserved.
0005:         *
0006:         * Redistribution and use in source and binary forms, with or without
0007:         * modification, are permitted provided that the following conditions
0008:         * are met:
0009:         *
0010:         * 1. Redistributions of source code must retain the above
0011:         *    copyright notice, this list of conditions and the following
0012:         *    disclaimer.
0013:         *
0014:         * 2. Redistributions in binary form must reproduce the above copyright
0015:         *    notice, this list of conditions and the following disclaimer in
0016:         *    the documentation and/or other materials provided with the
0017:         *    distribution.
0018:         *
0019:         * 3. The names "Tigris", "Axion", nor the names of its contributors may
0020:         *    not be used to endorse or promote products derived from this
0021:         *    software without specific prior written permission.
0022:         *
0023:         * 4. Products derived from this software may not be called "Axion", nor
0024:         *    may "Tigris" or "Axion" appear in their names without specific prior
0025:         *    written permission.
0026:         *
0027:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0028:         * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0029:         * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
0030:         * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0031:         * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0032:         * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0033:         * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0034:         * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0035:         * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0036:         * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0037:         * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0038:         * =======================================================================
0039:         */
0040:
0041:        package org.axiondb.engine.tables;
0042:
0043:        import java.io.DataInputStream;
0044:        import java.io.DataOutputStream;
0045:        import java.io.File;
0046:        import java.io.FilenameFilter;
0047:        import java.io.IOException;
0048:        import java.io.ObjectInputStream;
0049:        import java.io.ObjectOutputStream;
0050:        import java.util.Iterator;
0051:        import java.util.NoSuchElementException;
0052:
0053:        import org.apache.commons.collections.primitives.ArrayIntList;
0054:        import org.apache.commons.collections.primitives.ArrayUnsignedIntList;
0055:        import org.apache.commons.collections.primitives.IntCollection;
0056:        import org.apache.commons.collections.primitives.IntIterator;
0057:        import org.apache.commons.collections.primitives.IntList;
0058:        import org.apache.commons.logging.Log;
0059:        import org.apache.commons.logging.LogFactory;
0060:        import org.axiondb.AxionException;
0061:        import org.axiondb.Column;
0062:        import org.axiondb.Constraint;
0063:        import org.axiondb.DataType;
0064:        import org.axiondb.Database;
0065:        import org.axiondb.Index;
0066:        import org.axiondb.IndexLoader;
0067:        import org.axiondb.Row;
0068:        import org.axiondb.RowCollection;
0069:        import org.axiondb.RowIterator;
0070:        import org.axiondb.Sequence;
0071:        import org.axiondb.Table;
0072:        import org.axiondb.TableFactory;
0073:        import org.axiondb.engine.rowiterators.BaseRowIterator;
0074:        import org.axiondb.event.RowEvent;
0075:        import org.axiondb.event.RowInsertedEvent;
0076:        import org.axiondb.io.AxionFileSystem;
0077:        import org.axiondb.io.BufferedDataInputStream;
0078:        import org.axiondb.io.BufferedDataOutputStream;
0079:        import org.axiondb.io.FileUtil;
0080:        import org.axiondb.types.LOBType;
0081:        import org.axiondb.util.ExceptionConverter;
0082:
0083:        /**
0084:         * Abstract base disk-resident implementation of {@link Table}.
0085:         * <code>BaseDiskTable</code> manages the column meta-data for a disk-based table.
0086:         * 
0087:         * @version $Revision: 1.36 $ $Date: 2005/12/22 09:02:31 $
0088:         * @author Chuck Burdick
0089:         * @author Rodney Waldhoff
0090:         * @author Ahimanikya Satapathy
0091:         */
0092:        public abstract class BaseDiskTable extends BaseTable implements  Table {
0093:
0094:            //------------------------------------------------------------- Constructors
0095:
0096:            public BaseDiskTable(String name, Database db, TableFactory factory)
0097:                    throws AxionException {
0098:                super (name);
0099:                _dbdir = db.getDBDirectory();
0100:                _readOnly = db.isReadOnly();
0101:                createOrLoadTableFiles(name, db, factory);
0102:            }
0103:
0104:            //  ----------------------------------------------------------------- public
0105:            public void addColumn(Column col) throws AxionException {
0106:                addColumn(col, true);
0107:            }
0108:
0109:            public void addColumn(Column col, boolean metaUpdateNeeded)
0110:                    throws AxionException {
0111:                resetLobColumn(col);
0112:                super .addColumn(col);
0113:                if (metaUpdateNeeded) {
0114:                    writeMetaFile();
0115:                }
0116:            }
0117:
0118:            public void addConstraint(Constraint constraint)
0119:                    throws AxionException {
0120:                super .addConstraint(constraint);
0121:                writeMetaFile();
0122:            }
0123:
0124:            public void applyDeletes(IntCollection rowIds)
0125:                    throws AxionException {
0126:                synchronized (this ) {
0127:                    applyDeletesToIndices(rowIds);
0128:                    applyDeletesToRows(rowIds);
0129:                }
0130:            }
0131:
0132:            public void applyInserts(RowCollection rows) throws AxionException {
0133:                synchronized (this ) {
0134:                    // apply to the indices one at a time, as its more memory-friendly
0135:                    for (Iterator indexIter = getIndices(); indexIter.hasNext();) {
0136:                        Index index = (Index) (indexIter.next());
0137:                        for (RowIterator iter = rows.rowIterator(); iter
0138:                                .hasNext();) {
0139:                            Row row = iter.next();
0140:                            RowEvent event = new RowInsertedEvent(this , null,
0141:                                    row);
0142:                            index.rowInserted(event);
0143:                        }
0144:                        saveIndex(index);
0145:                    }
0146:                    applyInsertsToRows(rows.rowIterator());
0147:                }
0148:            }
0149:
0150:            public void applyUpdates(RowCollection rows) throws AxionException {
0151:                synchronized (this ) {
0152:                    applyUpdatesToIndices(rows);
0153:                    applyUpdatesToRows(rows.rowIterator());
0154:                }
0155:            }
0156:
0157:            public void checkpoint() throws AxionException {
0158:                super .checkpoint();
0159:                DataOutputStream out = null;
0160:                try {
0161:                    if (getSequence() != null) {
0162:                        File seqFile = getTableFile(SEQ_FILE_EXT);
0163:                        out = FS.createDataOutputSteam(seqFile);
0164:                        getSequence().write(out);
0165:                    }
0166:
0167:                } catch (IOException e) {
0168:                    String msg = "Unable to persist sequence file";
0169:                    throw new AxionException(msg);
0170:                } finally {
0171:                    FS.closeOutputStream(out);
0172:                }
0173:            }
0174:
0175:            public void drop() throws AxionException {
0176:                closeFiles();
0177:                if (!FileUtil.delete(getRootDir())) {
0178:                    throw new AxionException("Unable to delete \""
0179:                            + getRootDir() + "\" during drop table "
0180:                            + getName());
0181:                }
0182:            }
0183:
0184:            public void freeRowId(int id) {
0185:                if (_freeIdPos >= 0 && id == _freeIds.get(_freeIdPos)) {
0186:                    _freeIdPos--;
0187:                } else if (_nextFreeId > getPidxList().size() - 1) {
0188:                    _nextFreeId--;
0189:                }
0190:            }
0191:
0192:            public int getNextRowId() {
0193:                if (_freeIds.isEmpty() || _freeIdPos >= _freeIds.size() - 1) {
0194:                    return _nextFreeId = (_nextFreeId == -1 ? getPidxList()
0195:                            .size() : _nextFreeId + 1);
0196:                } else {
0197:                    return _freeIds.get(++_freeIdPos);
0198:                }
0199:            }
0200:
0201:            public Row getRow(int id) throws AxionException {
0202:                long ptr = getPidxList().get(id);
0203:                Row row = getRowByOffset(id, ptr);
0204:                return row;
0205:            }
0206:
0207:            /** Migrate from older version to newer version for this table */
0208:            public void migrate(Database db) throws AxionException {
0209:                File metaFile = getTableFile(META_FILE_EXT);
0210:                if (!metaFile.exists()) {
0211:                    return;
0212:                }
0213:
0214:                int version = CURRENT_META_VERSION;
0215:                ObjectInputStream in = null;
0216:                try {
0217:                    in = FS.openObjectInputSteam(metaFile);
0218:                    // read version number
0219:                    version = in.readInt();
0220:                    if (_log.isDebugEnabled()) {
0221:                        _log.debug("Version number for " + getName()
0222:                                + " in migrate() is " + version);
0223:                    }
0224:
0225:                    if (version < 0 || version > CURRENT_META_VERSION) {
0226:                        throw new AxionException("Unrecognized version "
0227:                                + version);
0228:                    }
0229:
0230:                    if (version == 0) {
0231:                        parseV0MetaFile(in);
0232:                    } else {
0233:                        parseV1MetaFile(in, db);
0234:                    }
0235:                    parseTableProperties(in);
0236:                } catch (ClassNotFoundException e) {
0237:                    throw new AxionException("Unable to parse meta file "
0238:                            + metaFile + " for table " + getName(), e);
0239:                } catch (IOException e) {
0240:                    throw new AxionException("Unable to parse meta file "
0241:                            + metaFile + " for table " + getName(), e);
0242:                } finally {
0243:                    FS.closeInputStream(in);
0244:                }
0245:
0246:                if (version < 2) {
0247:                    _pidx = FS.parseLongPidx(getTableFile(PIDX_FILE_EXT),
0248:                            _readOnly);
0249:                }
0250:
0251:                if (version < 3) {
0252:                    // change col name to upper if required
0253:                    for (int i = 0, I = getColumnCount(); i < I; i++) {
0254:                        Column col = getColumn(i);
0255:                        col.getConfiguration().put(Column.NAME_CONFIG_KEY,
0256:                                col.getName().toUpperCase());
0257:                    }
0258:                }
0259:
0260:                if (version != CURRENT_META_VERSION) {
0261:                    writeMetaFile(); // migrating from older meta type, so update meta file
0262:                }
0263:            }
0264:
0265:            public int getRowCount() {
0266:                return _rowCount;
0267:            }
0268:
0269:            public void populateIndex(Index index) throws AxionException {
0270:                for (int i = 0, I = getPidxList().size(); i < I; i++) {
0271:                    long ptr = getPidxList().get(i);
0272:                    if (ptr != INVALID_OFFSET) {
0273:                        index.rowInserted(new RowInsertedEvent(this , null,
0274:                                getRowByOffset(i, ptr)));
0275:                    }
0276:                }
0277:
0278:                File indexDir = new File(_indexRootDir, index.getName());
0279:                if (!indexDir.exists()) {
0280:                    indexDir.mkdirs();
0281:                }
0282:                File typefile = new File(indexDir, index.getName()
0283:                        + TYPE_FILE_EXT);
0284:                IndexLoader loader = index.getIndexLoader();
0285:                writeNameToFile(typefile, loader);
0286:                index.save(indexDir);
0287:            }
0288:
0289:            public void remount(File newdir, boolean datafilesonly)
0290:                    throws AxionException {
0291:                closeFiles();
0292:                initFiles(newdir, datafilesonly);
0293:                writeMetaFile();
0294:                resetLobColumns();
0295:                super .remount(newdir, datafilesonly);
0296:            }
0297:
0298:            public void removeIndex(Index index) throws AxionException {
0299:                super .removeIndex(index);
0300:                File indexdir = new File(_indexRootDir, index.getName());
0301:                if (!FileUtil.delete(indexdir)) {
0302:                    throw new AxionException("Unable to delete \"" + indexdir
0303:                            + "\" during remove index " + index.getName());
0304:                }
0305:            }
0306:
0307:            public void rename(String oldName, String newName)
0308:                    throws AxionException {
0309:                try {
0310:                    closeFiles();
0311:                    renameTableFiles(oldName, newName);
0312:                    super .rename(oldName, newName);
0313:
0314:                    clearDataFileReference();
0315:                    writeMetaFile(); // refresh meta file
0316:                    initFiles(getRootDir(), false);
0317:
0318:                    resetLobColumns();
0319:                } catch (Exception e) {
0320:                    throw new AxionException("Fail to alter table: " + newName);
0321:                }
0322:            }
0323:
0324:            public void setSequence(Sequence seq) throws AxionException {
0325:                super .setSequence(seq);
0326:                checkpoint();
0327:            }
0328:
0329:            public void shutdown() throws AxionException {
0330:                closeFiles();
0331:            }
0332:
0333:            public void truncate() throws AxionException {
0334:                // Return immediately if table is already empty.
0335:                if (getRowCount() == 0) {
0336:                    return;
0337:                }
0338:
0339:                // Rename old data file as backup and replace with zero-length file.
0340:                File df = getDataFile();
0341:                File pidxFile = getTableFile(PIDX_FILE_EXT);
0342:                File bkupFile = new File(df.getParentFile(), df.getName()
0343:                        + ".backup");
0344:                File bkupPidxFile = new File(pidxFile + ".backup");
0345:                FileUtil.assertFileNotLocked(bkupFile);
0346:
0347:                try {
0348:                    closeFiles();
0349:                    FileUtil.delete(bkupFile);
0350:                    df.renameTo(bkupFile);
0351:                    pidxFile.renameTo(bkupPidxFile);
0352:
0353:                    reloadFilesAfterTruncate();
0354:                    truncateIndices();
0355:                    saveIndicesAfterTruncate();
0356:
0357:                    FileUtil.delete(bkupFile);
0358:                    FileUtil.delete(bkupPidxFile);
0359:                } catch (Exception e) {
0360:                    // Restore old file and reload it.
0361:                    closeFiles();
0362:                    FileUtil.delete(df);
0363:                    FileUtil.delete(pidxFile);
0364:                    bkupFile.renameTo(df);
0365:                    bkupPidxFile.renameTo(pidxFile);
0366:                    reloadFilesAfterTruncate();
0367:                    recreateIndices();
0368:                    throw new AxionException(e);
0369:                }
0370:            }
0371:
0372:            //--------------------------------------------------------------- Protected
0373:
0374:            protected void clearDataFileReference() {
0375:                _dataFile = null;
0376:            }
0377:
0378:            protected void closeFiles() {
0379:                if (null != _readStream) {
0380:                    try {
0381:                        _readStream.close();
0382:                    } catch (IOException e) {
0383:                        // ignored
0384:                    }
0385:                    _readStream = null;
0386:                }
0387:
0388:                if (null != _writeStream) {
0389:                    try {
0390:                        _writeStream.close();
0391:                    } catch (IOException e) {
0392:                        // ignored
0393:                    }
0394:                    _writeStream = null;
0395:                }
0396:
0397:                if (null != _pidx) {
0398:                    try {
0399:                        _pidx.close();
0400:                    } catch (IOException e) {
0401:                        // ignored
0402:                    }
0403:                    _pidx = null;
0404:                }
0405:            }
0406:
0407:            protected void createOrLoadDataFile() throws AxionException {
0408:                if (!isReadOnly()) {
0409:                    FS.createNewFile(getDataFile());
0410:                }
0411:                getOutputStream();
0412:                getInputStream();
0413:            }
0414:
0415:            protected void createOrLoadFreeIdsFile() throws AxionException {
0416:                if (_freeIds == null) {
0417:                    File freeIdsFile = getTableFile(FRID_FILE_EXT);
0418:                    if (!isReadOnly()) {
0419:                        FS.createNewFile(freeIdsFile);
0420:                    }
0421:                    _freeIds = FS.parseIntFile(freeIdsFile);
0422:                }
0423:            }
0424:
0425:            protected void loadOrMigrateMetaFile(Database db)
0426:                    throws AxionException {
0427:                migrate(db);
0428:            }
0429:
0430:            abstract protected File getDataFile();
0431:
0432:            protected String getDefaultDataFileExtension() {
0433:                return "DATA";
0434:            }
0435:
0436:            protected synchronized BufferedDataInputStream getInputStream()
0437:                    throws AxionException {
0438:                if (null == _readStream) {
0439:                    _readStream = FS.openBufferedDIS(getDataFile());
0440:                }
0441:                return _readStream;
0442:            }
0443:
0444:            abstract protected File getLobDir();
0445:
0446:            protected synchronized BufferedDataOutputStream getOutputStream()
0447:                    throws AxionException {
0448:                if (!isReadOnly() && null == _writeStream) {
0449:                    _writeStream = FS
0450:                            .openBufferedDOSAppend(getDataFile(), 1024);
0451:                }
0452:                return _writeStream;
0453:            }
0454:
0455:            protected AxionFileSystem.PidxList getPidxList() {
0456:                if (_pidx == null) {
0457:                    File pidxFile = getTableFile(PIDX_FILE_EXT);
0458:                    try {
0459:                        if (!isReadOnly()) {
0460:                            FS.createNewFile(pidxFile);
0461:                        }
0462:                        _pidx = parsePidxFile(pidxFile);
0463:                    } catch (AxionException e) {
0464:                        throw ExceptionConverter.convertToRuntimeException(e);
0465:                    }
0466:                    _nextFreeId = -1;
0467:                }
0468:                return _pidx;
0469:            }
0470:
0471:            protected File getRootDir() {
0472:                return _dir;
0473:            }
0474:
0475:            protected RowIterator getRowIterator() throws AxionException {
0476:                return new BaseRowIterator() {
0477:                    Row _current = null;
0478:                    int _currentId = -1;
0479:                    int _currentIndex = -1;
0480:                    int _nextId = 0;
0481:                    int _nextIndex = 0;
0482:
0483:                    public Row current() {
0484:                        if (!hasCurrent()) {
0485:                            throw new NoSuchElementException("No current row.");
0486:                        }
0487:                        return _current;
0488:                    }
0489:
0490:                    public int currentIndex() {
0491:                        return _currentIndex;
0492:                    }
0493:
0494:                    public boolean hasCurrent() {
0495:                        return (null != _current);
0496:                    }
0497:
0498:                    public boolean hasNext() {
0499:                        return nextIndex() < getRowCount();
0500:                    }
0501:
0502:                    public boolean hasPrevious() {
0503:                        return nextIndex() > 0;
0504:                    }
0505:
0506:                    public Row last() throws AxionException {
0507:                        if (isEmpty()) {
0508:                            throw new IllegalStateException("No rows in table.");
0509:                        }
0510:                        _nextIndex = getRowCount();
0511:                        _nextId = getPidxList().size();
0512:                        previous();
0513:
0514:                        _nextId++;
0515:                        _nextIndex++;
0516:                        return current();
0517:                    }
0518:
0519:                    public Row next() throws AxionException {
0520:                        if (!hasNext()) {
0521:                            throw new NoSuchElementException("No next row");
0522:                        }
0523:                        next(1);
0524:                        setCurrentRow();
0525:                        return current();
0526:                    }
0527:
0528:                    public int next(int count) throws AxionException {
0529:                        for (int start = 0; start < count;) {
0530:                            _currentId = _nextId++;
0531:                            if (!hasNext() || _currentId > getPidxList().size()) {
0532:                                throw new NoSuchElementException("No next row");
0533:                            } else if (getPidxList().get(_currentId) != INVALID_OFFSET) {
0534:                                _currentIndex = _nextIndex++;
0535:                                start++;
0536:                            }
0537:                        }
0538:                        _current = null;
0539:                        return _currentId;
0540:                    }
0541:
0542:                    public int nextIndex() {
0543:                        return _nextIndex;
0544:                    }
0545:
0546:                    public Row previous() throws AxionException {
0547:                        if (!hasPrevious()) {
0548:                            throw new NoSuchElementException("No previous row");
0549:                        }
0550:                        previous(1);
0551:                        setCurrentRow();
0552:                        return current();
0553:                    }
0554:
0555:                    public int previous(int count) throws AxionException {
0556:                        for (int start = 0; start < count;) {
0557:                            _currentId = --_nextId;
0558:                            if (!hasPrevious() || _currentId < 0) {
0559:                                throw new NoSuchElementException(
0560:                                        "No Previous row");
0561:                            } else if (getPidxList().get(_currentId) != INVALID_OFFSET) {
0562:                                _currentIndex = --_nextIndex;
0563:                                start++;
0564:                            }
0565:                        }
0566:                        _current = null;
0567:                        return _currentId;
0568:                    }
0569:
0570:                    public int previousIndex() {
0571:                        return _nextIndex - 1;
0572:                    }
0573:
0574:                    public void remove() throws AxionException {
0575:                        if (-1 == _currentIndex) {
0576:                            throw new IllegalStateException("No current row.");
0577:                        }
0578:                        deleteRow(_current);
0579:                        _nextIndex--;
0580:                        _currentIndex = -1;
0581:                    }
0582:
0583:                    public void reset() {
0584:                        _current = null;
0585:                        _nextIndex = 0;
0586:                        _currentIndex = -1;
0587:                        _nextId = 0;
0588:                    }
0589:
0590:                    public void set(Row row) throws AxionException {
0591:                        if (-1 == _currentIndex) {
0592:                            throw new IllegalStateException("No current row.");
0593:                        }
0594:                        updateRow(_current, row);
0595:                    }
0596:
0597:                    public int size() throws AxionException {
0598:                        return getRowCount();
0599:                    }
0600:
0601:                    public String toString() {
0602:                        return "DiskTable(" + getName() + ")";
0603:                    }
0604:
0605:                    private Row setCurrentRow() throws AxionException {
0606:                        Row row = getRowByOffset(_currentId, getPidxList().get(
0607:                                _currentId));
0608:                        if (row != null) {
0609:                            return _current = row;
0610:                        }
0611:                        throw new IllegalStateException(
0612:                                "No valid row at position " + _currentIndex);
0613:                    }
0614:                };
0615:            }
0616:
0617:            abstract protected Row getRowByOffset(int idToAssign, long ptr)
0618:                    throws AxionException;
0619:
0620:            protected File getTableFile(String extension) {
0621:                return new File(getRootDir(), getName().toUpperCase()
0622:                        + extension);
0623:            }
0624:
0625:            protected boolean isReadOnly() {
0626:                return _readOnly;
0627:            }
0628:
0629:            protected void initFiles(File basedir, boolean datafilesonly)
0630:                    throws AxionException {
0631:                if (!datafilesonly) {
0632:                    _dir = basedir;
0633:                    _indexRootDir = new File(_dir, INDICES_DIR_NAME);
0634:                }
0635:                clearDataFileReference();
0636:                getDataFile();
0637:                _readStream = null;
0638:                _writeStream = null;
0639:            }
0640:
0641:            protected void initializeRowCount() throws AxionException {
0642:                _rowCount = 0;
0643:                for (int i = 0, I = getPidxList().size(); i < I; i++) {
0644:                    long ptr = getPidxList().get(i);
0645:                    if (ptr != INVALID_OFFSET) {
0646:                        _rowCount++;
0647:                    }
0648:                }
0649:            }
0650:
0651:            protected synchronized AxionFileSystem.PidxList parsePidxFile(
0652:                    File pidxFile) throws AxionException {
0653:                return FS.parseUnsignedIntPidx(pidxFile, _readOnly);
0654:            }
0655:
0656:            protected void parseTableProperties(ObjectInputStream in)
0657:                    throws AxionException {
0658:                // Allow sub class to read extra meta info
0659:            }
0660:
0661:            abstract protected void reloadFilesAfterTruncate()
0662:                    throws AxionException;
0663:
0664:            protected void renameTableFiles(String oldName, String name) {
0665:                // rename table dir
0666:                File olddir = new File(_dbdir, oldName);
0667:                _dir = new File(_dbdir, name);
0668:                olddir.renameTo(_dir);
0669:
0670:                // rename table files
0671:                FileUtil.renameFile(_dir, oldName, name, TYPE_FILE_EXT);
0672:                FileUtil.renameFile(_dir, oldName, name, PIDX_FILE_EXT);
0673:                FileUtil.renameFile(_dir, oldName, name, FRID_FILE_EXT);
0674:                FileUtil.renameFile(_dir, oldName, name, META_FILE_EXT);
0675:                FileUtil.renameFile(_dir, oldName, name, SEQ_FILE_EXT);
0676:            }
0677:
0678:            protected void saveIndicesAfterTruncate() throws AxionException {
0679:                for (Iterator iter = getIndices(); iter.hasNext();) {
0680:                    Index index = (Index) (iter.next());
0681:                    saveIndexAfterTruncate(index);
0682:                }
0683:            }
0684:
0685:            protected void tryToRemove(RowIterator iter) throws AxionException {
0686:                try {
0687:                    iter.remove();
0688:                } catch (UnsupportedOperationException e) {
0689:                    // ignore it, that's OK
0690:                }
0691:            }
0692:
0693:            protected final void writeFridFile() throws AxionException {
0694:                FS.writeIntFile(getTableFile(FRID_FILE_EXT), _freeIds);
0695:            }
0696:
0697:            protected void writeMetaFile() throws AxionException {
0698:                ObjectOutputStream out = null;
0699:                File metaFile = getTableFile(META_FILE_EXT);
0700:                try {
0701:                    out = FS.createObjectOutputSteam(metaFile);
0702:                    out.writeInt(CURRENT_META_VERSION);
0703:                    writeColumns(out);
0704:                    out.flush();
0705:                    writeConstraints(out);
0706:                    out.flush();
0707:                    writeTableProperties(out);
0708:                    out.flush();
0709:                } catch (IOException e) {
0710:                    throw new AxionException("Unable to write meta file "
0711:                            + metaFile + " for table " + getName(), e);
0712:                } finally {
0713:                    FS.closeOutputStream(out);
0714:                }
0715:            }
0716:
0717:            protected void writeNameToFile(File file, Object obj)
0718:                    throws AxionException {
0719:                ObjectOutputStream out = null;
0720:                try {
0721:                    out = FS.createObjectOutputSteam(file);
0722:                    out.writeUTF(obj.getClass().getName());
0723:                } catch (IOException e) {
0724:                    throw new AxionException(e);
0725:                } finally {
0726:                    FS.closeOutputStream(out);
0727:                }
0728:            }
0729:
0730:            protected abstract void writeRow(BufferedDataOutputStream buffer,
0731:                    Row row) throws AxionException;
0732:
0733:            protected void writeTableProperties(ObjectOutputStream out)
0734:                    throws AxionException {
0735:                // Allow the subclass to write table specific metadata
0736:            }
0737:
0738:            private void applyDeletesToRows(IntCollection rowids)
0739:                    throws AxionException {
0740:                try {
0741:                    IntIterator iter = rowids.iterator();
0742:                    if (iter.hasNext()) {
0743:                        for (int rowid; iter.hasNext();) {
0744:                            rowid = iter.next();
0745:                            if (rowid > getPidxList().size() - 1) {
0746:                                throw new AxionException(
0747:                                        "Can't delete non-existent row");
0748:                            }
0749:                            getPidxList().set(rowid, INVALID_OFFSET);
0750:                            //_freeIds.add(rowid);
0751:                            _rowCount--;
0752:                        }
0753:                        _pidx.flush();
0754:                        _freeIds.addAll(rowids);
0755:                        writeFridFile();
0756:                    }
0757:                } catch (IOException e) {
0758:                    throw new AxionException("Error writing data.", e);
0759:                }
0760:            }
0761:
0762:            private void applyInsertsToRows(RowIterator rows)
0763:                    throws AxionException {
0764:                try {
0765:                    // write all the rows to a buffer
0766:                    BufferedDataOutputStream out = getOutputStream();
0767:                    while (rows.hasNext()) {
0768:                        Row row = rows.next();
0769:                        _rowCount++;
0770:                        if (!_freeIds.isEmpty() && _freeIdPos > -1) {
0771:                            getPidxList().set(_freeIds.removeElementAt(0),
0772:                                    out.getPos());
0773:                            _freeIdPos--;
0774:                        } else {
0775:                            getPidxList().add(out.getPos());
0776:                        }
0777:                        writeRow(out, row);
0778:
0779:                        // drop the reference to the row form the iterator
0780:                        tryToRemove(rows);
0781:                    }
0782:
0783:                    _writeStream.flush();
0784:                    _pidx.flush();
0785:                    writeFridFile();
0786:                    _nextFreeId = -1;
0787:                } catch (IOException e) {
0788:                    throw new AxionException("Error writing data.", e);
0789:                }
0790:            }
0791:
0792:            private void applyUpdatesToRows(RowIterator rows)
0793:                    throws AxionException {
0794:                try {
0795:                    BufferedDataOutputStream out = getOutputStream();
0796:                    while (rows.hasNext()) {
0797:                        Row row = rows.next();
0798:                        if (row.getIdentifier() > getPidxList().size() - 1) {
0799:                            throw new AxionException(
0800:                                    "Can't update non-existent row");
0801:                        }
0802:                        // update the slot in the pidx file to point to the new data
0803:                        getPidxList().set(row.getIdentifier(), out.getPos());
0804:                        writeRow(out, row);
0805:
0806:                        // drop the reference to the row form the iterator
0807:                        tryToRemove(rows);
0808:                    }
0809:
0810:                    _writeStream.flush();
0811:                    _pidx.flush();
0812:                    getInputStream().reset();
0813:                } catch (IOException e) {
0814:                    throw new AxionException("Error writing data.", e);
0815:                }
0816:            }
0817:
0818:            // ----------------------------------------------------------------- Private
0819:
0820:            private void createOrLoadTableFiles(String name, Database db,
0821:                    TableFactory factory) throws AxionException {
0822:                synchronized (BaseDiskTable.class) {
0823:                    _dir = new File(db.getDBDirectory(), name.toUpperCase());
0824:
0825:                    if (!_dir.exists()) {
0826:                        if (!_dir.mkdirs()) {
0827:                            throw new AxionException(
0828:                                    "Unable to create directory \"" + _dir
0829:                                            + "\" for Table \"" + name + "\".");
0830:                        }
0831:                    }
0832:
0833:                    // create the type file if it doesn't already exist
0834:                    File typefile = getTableFile(TYPE_FILE_EXT);
0835:                    if (!typefile.exists()) {
0836:                        writeNameToFile(typefile, factory);
0837:                    }
0838:
0839:                    _freeIds = new ArrayIntList();
0840:
0841:                    loadOrMigrateMetaFile(db); // note order is signficant here!
0842:                    createOrLoadFreeIdsFile();
0843:
0844:                    initializeRowCount();
0845:
0846:                    // indices - directory containing index files
0847:                    _indexRootDir = new File(_dir, INDICES_DIR_NAME);
0848:                    if (_indexRootDir.exists()) {
0849:                        loadIndices(_indexRootDir, db);
0850:                    } else {
0851:                        _indexRootDir.mkdirs();
0852:                    }
0853:
0854:                    File seqfile = getTableFile(SEQ_FILE_EXT);
0855:                    if (seqfile.exists()) {
0856:                        loadSequences();
0857:                    }
0858:                }
0859:            }
0860:
0861:            private void loadIndices(File parentdir, Database db)
0862:                    throws AxionException {
0863:                String[] indices = parentdir.list(DOT_TYPE_FILE_FILTER);
0864:                for (int i = 0; i < indices.length; i++) {
0865:                    File indexdir = new File(parentdir, indices[i]);
0866:                    File typefile = new File(indexdir, indices[i]
0867:                            + TYPE_FILE_EXT);
0868:
0869:                    String loadername = null;
0870:                    ObjectInputStream in = null;
0871:                    try {
0872:                        in = FS.openObjectInputSteam(typefile);
0873:                        loadername = in.readUTF();
0874:                    } catch (IOException e) {
0875:                        throw new AxionException(e);
0876:                    } finally {
0877:                        FS.closeInputStream(in);
0878:                    }
0879:
0880:                    IndexLoader loader = null;
0881:                    try {
0882:                        Class clazz = Class.forName(loadername);
0883:                        loader = (IndexLoader) (clazz.newInstance());
0884:                    } catch (Exception e) {
0885:                        throw new AxionException(e);
0886:                    }
0887:                    Index index = loader.loadIndex(this , indexdir);
0888:                    db.addIndex(index, this );
0889:                }
0890:            }
0891:
0892:            private void loadSequences() throws AxionException {
0893:                File seqFile = getTableFile(SEQ_FILE_EXT);
0894:                DataInputStream in = null;
0895:                if (seqFile.exists()) {
0896:                    try {
0897:                        in = FS.openDataInputSteam(seqFile);
0898:                        Sequence seq = new Sequence();
0899:                        seq.read(in);
0900:                        super .setSequence(seq);
0901:                    } catch (Exception e) {
0902:                        throw new AxionException(
0903:                                "Unable to read sequence file", e);
0904:                    } finally {
0905:                        FS.closeInputStream(in);
0906:                    }
0907:                }
0908:            }
0909:
0910:            private void parseV0MetaFile(ObjectInputStream in)
0911:                    throws IOException, AxionException {
0912:                int I = in.readInt(); // read number of columns
0913:                for (int i = 0; i < I; i++) {
0914:                    String name = in.readUTF(); // read column name
0915:                    String dtypename = in.readUTF(); // read data type class name
0916:
0917:                    // create instance of datatype
0918:                    DataType type = null;
0919:                    try {
0920:                        Class clazz = Class.forName(dtypename);
0921:                        type = (DataType) (clazz.newInstance());
0922:                    } catch (Exception e) {
0923:                        throw new AxionException("Can't load table "
0924:                                + getName() + ", data type " + dtypename
0925:                                + " not found.", e);
0926:                    }
0927:                    addColumn(new Column(name, type), false);
0928:                }
0929:            }
0930:
0931:            private void parseV1MetaFile(ObjectInputStream in, Database db)
0932:                    throws AxionException, IOException, ClassNotFoundException {
0933:                readColumns(in);
0934:                readConstraints(in, db);
0935:            }
0936:
0937:            // FIXME: there ought to be a better way to do this
0938:            private void resetLobColumn(Column col) throws AxionException {
0939:                if (col.getDataType() instanceof  LOBType) {
0940:                    LOBType lob = (LOBType) (col.getDataType());
0941:                    lob.setLobDir(new File(getLobDir(), col.getName()
0942:                            .toUpperCase()));
0943:                }
0944:            }
0945:
0946:            protected void resetLobColumns() throws AxionException {
0947:                for (int i = 0, I = getColumnCount(); i < I; i++) {
0948:                    Column col = getColumn(i);
0949:                    resetLobColumn(col);
0950:                }
0951:            }
0952:
0953:            private void saveIndex(Index index) throws AxionException {
0954:                File dataDir = new File(_indexRootDir, index.getName());
0955:                index.save(dataDir);
0956:            }
0957:
0958:            private void saveIndexAfterTruncate(Index index)
0959:                    throws AxionException {
0960:                File dataDir = new File(_indexRootDir, index.getName());
0961:                index.saveAfterTruncate(dataDir);
0962:            }
0963:
0964:            private static final FilenameFilter DOT_TYPE_FILE_FILTER = new FilenameFilter() {
0965:                public boolean accept(File dir, String name) {
0966:                    File file = new File(dir, name);
0967:                    if (file.isDirectory()) {
0968:                        File idx = new File(file, name + TYPE_FILE_EXT);
0969:                        if (idx.exists()) {
0970:                            return true;
0971:                        }
0972:                    }
0973:                    return false;
0974:                }
0975:            };
0976:
0977:            //--------------------------------------------------------------- Attributes
0978:            protected static AxionFileSystem FS = new AxionFileSystem();
0979:            protected static final long INVALID_OFFSET = ArrayUnsignedIntList.MAX_VALUE;
0980:            protected static final int CURRENT_META_VERSION = 3;
0981:
0982:            protected static final String FRID_FILE_EXT = ".FRID";
0983:            protected static final String INDICES_DIR_NAME = "INDICES";
0984:            protected static final String META_FILE_EXT = ".META";
0985:            protected static final String PIDX_FILE_EXT = ".PIDX";
0986:            protected static final String SEQ_FILE_EXT = ".SEQ";
0987:            protected static final String TYPE_FILE_EXT = ".TYPE";
0988:
0989:            /** The name of my ".data" file. */
0990:            protected File _dataFile = null;
0991:            protected File _dbdir = null;
0992:
0993:            /** List of free ids. */
0994:            protected IntList _freeIds = null;
0995:
0996:            private int _nextFreeId = -1;
0997:            private int _freeIdPos = -1;
0998:
0999:            /** List of offsets into the .data file, by row id. */
1000:            private AxionFileSystem.PidxList _pidx = null;
1001:
1002:            protected boolean _readOnly = false;
1003:            protected int _rowCount = 0;
1004:
1005:            /** The directory in which my data are stored. */
1006:            private File _dir = null;
1007:
1008:            /** The directory in which my indices are stored. */
1009:            private File _indexRootDir = null;
1010:
1011:            private BufferedDataInputStream _readStream = null;
1012:            private BufferedDataOutputStream _writeStream = null;
1013:
1014:            private static final Log _log = LogFactory
1015:                    .getLog(BaseDiskTable.class);
1016:
1017:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.