Source Code Cross Referenced for Store.java in  » EJB-Server-resin-3.1.5 » resin » com » caucho » db » store » 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 » EJB Server resin 3.1.5 » resin » com.caucho.db.store 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003:         *
0004:         * This file is part of Resin(R) Open Source
0005:         *
0006:         * Each copy or derived work must preserve the copyright notice and this
0007:         * notice unmodified.
0008:         *
0009:         * Resin Open Source is free software; you can redistribute it and/or modify
0010:         * it under the terms of the GNU General Public License as published by
0011:         * the Free Software Foundation; either version 2 of the License, or
0012:         * (at your option) any later version.
0013:         *
0014:         * Resin Open Source is distributed in the hope that it will be useful,
0015:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017:         * of NON-INFRINGEMENT.  See the GNU General Public License for more
0018:         * details.
0019:         *
0020:         * You should have received a copy of the GNU General Public License
0021:         * along with Resin Open Source; if not, write to the
0022:         *
0023:         *   Free Software Foundation, Inc.
0024:         *   59 Temple Place, Suite 330
0025:         *   Boston, MA 02111-1307  USA
0026:         *
0027:         * @author Scott Ferguson
0028:         */
0029:
0030:        package com.caucho.db.store;
0031:
0032:        import com.caucho.db.Database;
0033:        import com.caucho.lifecycle.Lifecycle;
0034:        import com.caucho.log.Log;
0035:        import com.caucho.sql.SQLExceptionWrapper;
0036:        import com.caucho.util.L10N;
0037:        import com.caucho.vfs.Path;
0038:        import com.caucho.vfs.RandomAccessStream;
0039:
0040:        import java.io.IOException;
0041:        import java.lang.ref.SoftReference;
0042:        import java.sql.SQLException;
0043:        import java.util.logging.Level;
0044:        import java.util.logging.Logger;
0045:
0046:        /**
0047:         * The store manages the block-based persistent store file.  Each table
0048:         * will have its own store file, table.db.
0049:         *
0050:         * The store is block-based, where each block is 64k.  Block allocation
0051:         * is tracked by a free block, block 0.  Each block is represented as a
0052:         * two-byte value.  The first byte is the allocation code: free, row,
0053:         * or used.  The second byte is a fragment allocation mask.
0054:         *
0055:         * Since 64k stores 32k entries, the allocation block can handle
0056:         * a 2G database size.  If the database is larger, another free block
0057:         * occurs at block 32k handling another 2G.
0058:         *
0059:         * The blocks are marked as free (00), row (01), used (10) or fragment(11).
0060:         * Row-blocks are table rows, so a table iterator will only look at
0061:         * the row blocks.   Used blocks are for special blocks like the
0062:         * free list.  Fragments are for blobs.
0063:         *
0064:         * Each store has a unique id in the database.  The store id is merged with
0065:         * the block number in the store to create a unique block id.  There are
0066:         * 64k allowed stores (and therefore 64k tables), leaving 64 - 16 = 48 bits
0067:         * for the blocks in a table, i.e. 2 ^ 48 blocks = 256T blocks.
0068:         *
0069:         * block index: the block number in the file.
0070:         *
0071:         * address: the address of a byte within the store, treating the file as a
0072:         * flat file.
0073:         *
0074:         * block id: the unique id of the block in the database.
0075:         *
0076:         * <h3>Blobs and fragments</h3>
0077:         *
0078:         * Fragments are stored in 8k chunks with a single byte prefix indicating
0079:         * its use.
0080:         *
0081:         * <h3>Transactions</h3>
0082:         *
0083:         * Fragments are not associated with transactions.  The rollback is
0084:         * associated with a transaction.
0085:         */
0086:        public class Store {
0087:            private final static Logger log = Log.open(Store.class);
0088:            private final static L10N L = new L10N(Store.class);
0089:
0090:            public final static int BLOCK_BITS = 16;
0091:            public final static int BLOCK_SIZE = 1 << BLOCK_BITS;
0092:            public final static long BLOCK_INDEX_MASK = BLOCK_SIZE - 1;
0093:            public final static long BLOCK_MASK = ~BLOCK_INDEX_MASK;
0094:            public final static long BLOCK_OFFSET_MASK = BLOCK_SIZE - 1;
0095:
0096:            private final static int ALLOC_BYTES_PER_BLOCK = 2;
0097:
0098:            private final static int ALLOC_CHUNK_SIZE = 1024 * ALLOC_BYTES_PER_BLOCK;
0099:
0100:            public final static int ALLOC_FREE = 0x00;
0101:            public final static int ALLOC_ROW = 0x01;
0102:            public final static int ALLOC_USED = 0x02;
0103:            public final static int ALLOC_FRAGMENT = 0x03;
0104:            public final static int ALLOC_INDEX = 0x04;
0105:            public final static int ALLOC_MINI_FRAG = 0x05;
0106:            public final static int ALLOC_MASK = 0x0f;
0107:
0108:            public final static int FRAGMENT_SIZE = 8 * 1024;
0109:            public final static int FRAGMENT_PER_BLOCK = (int) (BLOCK_SIZE / FRAGMENT_SIZE);
0110:
0111:            public final static int MINI_FRAG_SIZE = 256;
0112:            public final static int MINI_FRAG_PER_BLOCK = (int) ((BLOCK_SIZE - 64) / MINI_FRAG_SIZE);
0113:            public final static int MINI_FRAG_ALLOC_OFFSET = MINI_FRAG_PER_BLOCK
0114:                    * MINI_FRAG_SIZE;
0115:
0116:            public final static long DATA_START = BLOCK_SIZE;
0117:
0118:            public final static int STORE_CREATE_END = 1024;
0119:
0120:            protected final Database _database;
0121:            protected final BlockManager _blockManager;
0122:
0123:            private final String _name;
0124:
0125:            private int _id;
0126:
0127:            private Path _path;
0128:
0129:            // If true, dirty blocks are written at the end of the transaction.
0130:            // Otherwise, they are buffered
0131:            private boolean _isFlushDirtyBlocksOnCommit = true;
0132:
0133:            private long _fileSize;
0134:            private long _blockCount;
0135:
0136:            private final Object _allocationLock = new Object();
0137:            private byte[] _allocationTable;
0138:
0139:            private final Object _allocationWriteLock = new Object();
0140:            private int _allocDirtyMin = Integer.MAX_VALUE;
0141:            private int _allocDirtyMax;
0142:
0143:            private final Object _fragmentLock = new Object();
0144:            private final Object _miniFragLock = new Object();
0145:
0146:            private final Object _statLock = new Object();
0147:            // number of fragments currently used
0148:            private long _fragmentUseCount;
0149:
0150:            // number of minifragments currently used
0151:            private long _miniFragmentUseCount;
0152:
0153:            private Object _fileLock = new Object();
0154:            private SoftReference<RandomAccessWrapper> _cachedRowFile;
0155:
0156:            private Lock _rowLock;
0157:
0158:            private final Lifecycle _lifecycle = new Lifecycle();
0159:
0160:            public Store(Database database, String name, Lock tableLock) {
0161:                this (database, name, tableLock, database.getPath().lookup(
0162:                        name + ".db"));
0163:            }
0164:
0165:            /**
0166:             * Creates a new store.
0167:             *
0168:             * @param database the owning database.
0169:             * @param name the store name
0170:             * @param lock the table lock
0171:             * @param path the path to the files
0172:             */
0173:            public Store(Database database, String name, Lock rowLock, Path path) {
0174:                _database = database;
0175:                _blockManager = _database.getBlockManager();
0176:
0177:                _name = name;
0178:                _path = path;
0179:
0180:                if (path == null)
0181:                    throw new NullPointerException();
0182:
0183:                _id = _blockManager.allocateStoreId();
0184:
0185:                if (rowLock == null)
0186:                    rowLock = new Lock("row-lock:" + _name + ":" + _id);
0187:
0188:                _rowLock = rowLock;
0189:            }
0190:
0191:            /**
0192:             * Creates an independent store.
0193:             */
0194:            public static Store create(Path path) throws IOException,
0195:                    SQLException {
0196:                Database db = new Database();
0197:                db.init();
0198:
0199:                Store store = new Store(db, "temp", null, path);
0200:
0201:                if (path.canRead())
0202:                    store.init();
0203:                else
0204:                    store.create();
0205:
0206:                return store;
0207:            }
0208:
0209:            /**
0210:             * If true, dirty blocks are written at commit time.
0211:             */
0212:            public void setFlushDirtyBlocksOnCommit(boolean flushOnCommit) {
0213:                _isFlushDirtyBlocksOnCommit = flushOnCommit;
0214:            }
0215:
0216:            /**
0217:             * If true, dirty blocks are written at commit time.
0218:             */
0219:            public boolean isFlushDirtyBlocksOnCommit() {
0220:                return _isFlushDirtyBlocksOnCommit;
0221:            }
0222:
0223:            /**
0224:             * Returns the store's name.
0225:             */
0226:            public String getName() {
0227:                return _name;
0228:            }
0229:
0230:            /**
0231:             * Returns the store's id.
0232:             */
0233:            public int getId() {
0234:                return _id;
0235:            }
0236:
0237:            /**
0238:             * Returns the table's lock.
0239:             */
0240:            public Lock getLock() {
0241:                return _rowLock;
0242:            }
0243:
0244:            /**
0245:             * Returns the block manager.
0246:             */
0247:            public BlockManager getBlockManager() {
0248:                return _blockManager;
0249:            }
0250:
0251:            /**
0252:             * Returns the file size.
0253:             */
0254:            public long getFileSize() {
0255:                return _fileSize;
0256:            }
0257:
0258:            /**
0259:             * Returns the block count.
0260:             */
0261:            public long getBlockCount() {
0262:                return _blockCount;
0263:            }
0264:
0265:            /**
0266:             * Converts from the block index to the address for database
0267:             * storage.
0268:             */
0269:            private static long blockIndexToAddr(long blockIndex) {
0270:                return blockIndex << BLOCK_BITS;
0271:            }
0272:
0273:            /**
0274:             * Converts from the block index to the unique block id.
0275:             */
0276:            private final long blockIndexToBlockId(long blockIndex) {
0277:                return (blockIndex << BLOCK_BITS) + _id;
0278:            }
0279:
0280:            /**
0281:             * Converts from the block index to the address for database
0282:             * storage.
0283:             */
0284:            private static long blockIdToIndex(long blockId) {
0285:                return blockId >> BLOCK_BITS;
0286:            }
0287:
0288:            /**
0289:             * Converts from the block index to the unique block id.
0290:             */
0291:            public final long addressToBlockId(long address) {
0292:                return (address & BLOCK_MASK) + _id;
0293:            }
0294:
0295:            /**
0296:             * Converts from the block index to the unique block id.
0297:             */
0298:            public static long blockIdToAddress(long blockId) {
0299:                return (blockId & BLOCK_MASK);
0300:            }
0301:
0302:            /**
0303:             * Converts from the block index to the unique block id.
0304:             */
0305:            public static long blockIdToAddress(long blockId, int offset) {
0306:                return (blockId & BLOCK_MASK) + offset;
0307:            }
0308:
0309:            /**
0310:             * Returns the current number of fragments used.
0311:             */
0312:            public long getTotalFragmentSize() {
0313:                return _fragmentUseCount * FRAGMENT_SIZE;
0314:            }
0315:
0316:            /**
0317:             * Creates the store.
0318:             */
0319:            public void create() throws IOException, SQLException {
0320:                if (!_lifecycle.toActive())
0321:                    return;
0322:
0323:                log.finer(this  + " create");
0324:
0325:                _path.getParent().mkdirs();
0326:
0327:                if (_path.exists())
0328:                    throw new SQLException(
0329:                            L
0330:                                    .l(
0331:                                            "Table '{0}' already exists.  CREATE can not override an existing table.",
0332:                                            _name));
0333:
0334:                _allocationTable = new byte[ALLOC_CHUNK_SIZE];
0335:
0336:                // allocates the allocation table itself
0337:                setAllocation(0, ALLOC_USED);
0338:                // allocates the header information
0339:                setAllocation(1, ALLOC_USED);
0340:
0341:                byte[] buffer = new byte[BLOCK_SIZE];
0342:                writeBlock(0, buffer, 0, BLOCK_SIZE);
0343:                writeBlock(BLOCK_SIZE, buffer, 0, BLOCK_SIZE);
0344:
0345:                writeBlock(0, _allocationTable, 0, _allocationTable.length);
0346:
0347:                _blockCount = 2;
0348:            }
0349:
0350:            public void init() throws IOException {
0351:                if (!_lifecycle.toActive())
0352:                    return;
0353:
0354:                log.finer(this  + " init");
0355:
0356:                RandomAccessWrapper wrapper = openRowFile();
0357:
0358:                try {
0359:                    RandomAccessStream file = wrapper.getFile();
0360:
0361:                    _fileSize = file.getLength();
0362:                    _blockCount = ((_fileSize + BLOCK_SIZE - 1) / BLOCK_SIZE);
0363:
0364:                    int allocCount = (int) (_blockCount * ALLOC_BYTES_PER_BLOCK);
0365:
0366:                    allocCount += ALLOC_CHUNK_SIZE - allocCount
0367:                            % ALLOC_CHUNK_SIZE;
0368:
0369:                    _allocationTable = new byte[allocCount];
0370:
0371:                    for (int i = 0; i < allocCount; i += BLOCK_SIZE) {
0372:                        int len = allocCount - i;
0373:
0374:                        if (BLOCK_SIZE < len)
0375:                            len = BLOCK_SIZE;
0376:
0377:                        readBlock(
0378:                                (long) i / ALLOC_BYTES_PER_BLOCK * BLOCK_SIZE,
0379:                                _allocationTable, i, len);
0380:                    }
0381:                } finally {
0382:                    wrapper.close();
0383:                }
0384:            }
0385:
0386:            public void remove() throws SQLException {
0387:                try {
0388:                    _path.remove();
0389:                } catch (IOException e) {
0390:                    throw new SQLExceptionWrapper(e);
0391:                }
0392:            }
0393:
0394:            /**
0395:             * Returns the first block id which contains a row.
0396:             *
0397:             * @return the block id of the first row block
0398:             */
0399:            public long firstRow(long blockId) throws IOException {
0400:                return firstBlock(blockId, ALLOC_ROW);
0401:            }
0402:
0403:            /**
0404:             * Returns the first block id which contains a fragment.
0405:             *
0406:             * @return the block id of the first row block
0407:             */
0408:            public long firstFragment(long blockId) throws IOException {
0409:                return firstBlock(blockId, ALLOC_FRAGMENT);
0410:            }
0411:
0412:            /**
0413:             * Returns the first block id which contains a row.
0414:             *
0415:             * @return the block id of the first row block
0416:             */
0417:            public long firstBlock(long blockId, int type) throws IOException {
0418:                if (blockId <= BLOCK_SIZE)
0419:                    blockId = BLOCK_SIZE;
0420:
0421:                long blockIndex = blockId >> BLOCK_BITS;
0422:
0423:                synchronized (_allocationLock) {
0424:                    for (; blockIndex < _blockCount; blockIndex++) {
0425:                        if (getAllocation(blockIndex) == type)
0426:                            return blockIndexToBlockId(blockIndex);
0427:                    }
0428:                }
0429:
0430:                return -1;
0431:            }
0432:
0433:            /**
0434:             * Returns the matching block.
0435:             */
0436:            public final Block readBlock(long blockAddress) throws IOException {
0437:                long blockId = addressToBlockId(blockAddress);
0438:
0439:                Block block = _blockManager.getBlock(this , blockId);
0440:
0441:                try {
0442:                    block.read();
0443:
0444:                    return block;
0445:                } catch (IOException e) {
0446:                    block.free();
0447:
0448:                    throw e;
0449:                } catch (RuntimeException e) {
0450:                    block.free();
0451:
0452:                    throw e;
0453:                }
0454:            }
0455:
0456:            /**
0457:             * Allocates a new block for a row.
0458:             *
0459:             * @return the block id of the allocated block.
0460:             */
0461:            public Block allocateRow() throws IOException {
0462:                return allocateBlock(ALLOC_ROW);
0463:            }
0464:
0465:            /**
0466:             * Return true if the block is a row block.
0467:             */
0468:            public boolean isRowBlock(long blockAddress) {
0469:                return getAllocation(blockAddress / BLOCK_SIZE) == ALLOC_ROW;
0470:            }
0471:
0472:            /**
0473:             * Allocates a new block for a non-row.
0474:             *
0475:             * @return the block id of the allocated block.
0476:             */
0477:            public Block allocateBlock() throws IOException {
0478:                return allocateBlock(ALLOC_USED);
0479:            }
0480:
0481:            /**
0482:             * Allocates a new block for a fragment
0483:             *
0484:             * @return the block id of the allocated block.
0485:             */
0486:            private Block allocateFragmentBlock() throws IOException {
0487:                return allocateBlock(ALLOC_FRAGMENT);
0488:            }
0489:
0490:            /**
0491:             * Allocates a new block for a mini-fragment
0492:             *
0493:             * @return the block id of the allocated block.
0494:             */
0495:            private Block allocateMiniFragmentBlock() throws IOException {
0496:                return allocateBlock(ALLOC_MINI_FRAG);
0497:            }
0498:
0499:            /**
0500:             * Allocates a new block for an index
0501:             *
0502:             * @return the block id of the allocated block.
0503:             */
0504:            public Block allocateIndexBlock() throws IOException {
0505:                return allocateBlock(ALLOC_INDEX);
0506:            }
0507:
0508:            /**
0509:             * Return true if the block is an index block.
0510:             */
0511:            public boolean isIndexBlock(long blockAddress) {
0512:                return getAllocation(blockAddress / BLOCK_SIZE) == ALLOC_INDEX;
0513:            }
0514:
0515:            /**
0516:             * Allocates a new block.
0517:             *
0518:             * @return the block id of the allocated block.
0519:             */
0520:            private Block allocateBlock(int code) throws IOException {
0521:                long blockIndex;
0522:                boolean isFileExtended = false;
0523:
0524:                synchronized (_allocationLock) {
0525:                    long end = _blockCount;
0526:
0527:                    if (_allocationTable.length < ALLOC_BYTES_PER_BLOCK * end)
0528:                        end = _allocationTable.length / ALLOC_BYTES_PER_BLOCK;
0529:
0530:                    for (blockIndex = 0; blockIndex < end; blockIndex++) {
0531:                        if (getAllocation(blockIndex) == ALLOC_FREE)
0532:                            break;
0533:                    }
0534:
0535:                    if (_allocationTable.length <= ALLOC_BYTES_PER_BLOCK
0536:                            * blockIndex) {
0537:                        // expand the allocation table
0538:                        byte[] newTable = new byte[_allocationTable.length
0539:                                + ALLOC_CHUNK_SIZE];
0540:                        System.arraycopy(_allocationTable, 0, newTable, 0,
0541:                                _allocationTable.length);
0542:                        _allocationTable = newTable;
0543:
0544:                        // if the allocation table is over 32k, allocate the block for the
0545:                        // extension (each allocation block of 32k allocates 2G)
0546:                        if (blockIndex % (BLOCK_SIZE / ALLOC_BYTES_PER_BLOCK) == 0) {
0547:                            setAllocation(blockIndex, ALLOC_USED);
0548:                            blockIndex++;
0549:                        }
0550:                    }
0551:
0552:                    // mark USED before actual code so it's properly initialized
0553:                    setAllocation(blockIndex, ALLOC_USED);
0554:
0555:                    if (log.isLoggable(Level.FINE))
0556:                        log.fine(this  + " allocating block " + blockIndex + " "
0557:                                + codeToName(code));
0558:
0559:                    if (_blockCount <= blockIndex) {
0560:                        isFileExtended = true;
0561:                        _blockCount = blockIndex + 1;
0562:                    }
0563:                }
0564:
0565:                long blockId = blockIndexToBlockId(blockIndex);
0566:
0567:                Block block = _blockManager.getBlock(this , blockId);
0568:
0569:                byte[] buffer = block.getBuffer();
0570:
0571:                for (int i = BLOCK_SIZE - 1; i >= 0; i--)
0572:                    buffer[i] = 0;
0573:
0574:                block.setDirty(0, BLOCK_SIZE);
0575:
0576:                // if extending file, write the contents now
0577:                if (isFileExtended) {
0578:                    try {
0579:                        block.write();
0580:                    } catch (IOException e) {
0581:                        log.log(Level.WARNING, e.toString(), e);
0582:                    }
0583:                }
0584:
0585:                synchronized (_allocationLock) {
0586:                    setAllocation(blockIndex, code);
0587:                }
0588:
0589:                saveAllocation();
0590:
0591:                return block;
0592:            }
0593:
0594:            /**
0595:             * Check that an allocated block is valid.
0596:             */
0597:            protected void validateBlockId(long blockId)
0598:                    throws IllegalArgumentException, IllegalStateException {
0599:                RuntimeException e = null;
0600:
0601:                if (isClosed())
0602:                    e = new IllegalStateException(L.l("store {0} is closing.",
0603:                            this ));
0604:                else if (getId() <= 0)
0605:                    e = new IllegalStateException(L.l("invalid store {0}.",
0606:                            this ));
0607:                else if (getId() != (blockId & BLOCK_INDEX_MASK)) {
0608:                    e = new IllegalArgumentException(L.l(
0609:                            "block {0} must match store {1}.", blockId
0610:                                    & BLOCK_INDEX_MASK, this ));
0611:                }
0612:
0613:                if (e != null)
0614:                    throw e;
0615:            }
0616:
0617:            /**
0618:             * Check that an allocated block is valid.
0619:             */
0620:            protected void assertStoreActive() throws IllegalStateException {
0621:                RuntimeException e = null;
0622:
0623:                if (isClosed())
0624:                    e = new IllegalStateException(L.l("store {0} is closing.",
0625:                            this ));
0626:                else if (getId() <= 0)
0627:                    e = new IllegalStateException(L.l("invalid store {0}.",
0628:                            this ));
0629:
0630:                if (e != null)
0631:                    throw e;
0632:            }
0633:
0634:            /**
0635:             * Frees a block.
0636:             *
0637:             * @return the block id of the allocated block.
0638:             */
0639:            protected void freeBlock(long blockId) throws IOException {
0640:                if (blockId == 0)
0641:                    return;
0642:
0643:                synchronized (_allocationLock) {
0644:                    setAllocation(blockIdToIndex(blockId), ALLOC_FREE);
0645:                }
0646:
0647:                saveAllocation();
0648:            }
0649:
0650:            /**
0651:             * Sets the allocation for a block.
0652:             */
0653:            private final int getAllocation(long blockIndex) {
0654:                int allocOffset = (int) (ALLOC_BYTES_PER_BLOCK * blockIndex);
0655:
0656:                return _allocationTable[allocOffset] & ALLOC_MASK;
0657:            }
0658:
0659:            /**
0660:             * Sets the allocation for a block.
0661:             */
0662:            private void setAllocation(long blockIndex, int code) {
0663:                int allocOffset = (int) (ALLOC_BYTES_PER_BLOCK * blockIndex);
0664:
0665:                for (int i = 1; i < ALLOC_BYTES_PER_BLOCK; i++)
0666:                    _allocationTable[allocOffset + i] = 0;
0667:
0668:                _allocationTable[allocOffset] = (byte) code;
0669:
0670:                setAllocDirty(allocOffset, allocOffset + ALLOC_BYTES_PER_BLOCK);
0671:            }
0672:
0673:            /**
0674:             * Sets the dirty range for the allocation table.
0675:             */
0676:            private void setAllocDirty(int min, int max) {
0677:                if (min < _allocDirtyMin)
0678:                    _allocDirtyMin = min;
0679:
0680:                if (_allocDirtyMax < max)
0681:                    _allocDirtyMax = max;
0682:            }
0683:
0684:            /**
0685:             * Sets the allocation for a block.
0686:             */
0687:            void saveAllocation() throws IOException {
0688:                // cache doesn't actually need to write this data
0689:                if (!_isFlushDirtyBlocksOnCommit)
0690:                    return;
0691:
0692:                synchronized (_allocationWriteLock) {
0693:                    int dirtyMin;
0694:                    int dirtyMax;
0695:
0696:                    synchronized (_allocationLock) {
0697:                        dirtyMin = _allocDirtyMin;
0698:                        _allocDirtyMin = Integer.MAX_VALUE;
0699:
0700:                        dirtyMax = _allocDirtyMax;
0701:                        _allocDirtyMax = 0;
0702:                    }
0703:
0704:                    // Write each dirty block to disk.  The physical blocks are
0705:                    // broken up each BLOCK_SIZE / ALLOC_BYTES_PER_BLOCK.
0706:                    for (; dirtyMin < dirtyMax; dirtyMin = (dirtyMin + BLOCK_SIZE)
0707:                            - dirtyMin % BLOCK_SIZE) {
0708:                        int block = dirtyMin
0709:                                / (BLOCK_SIZE / ALLOC_BYTES_PER_BLOCK);
0710:
0711:                        int offset = dirtyMin % BLOCK_SIZE;
0712:                        int length;
0713:
0714:                        if (dirtyMin / BLOCK_SIZE != dirtyMax / BLOCK_SIZE)
0715:                            length = BLOCK_SIZE - offset;
0716:                        else
0717:                            length = dirtyMax - dirtyMin;
0718:
0719:                        writeBlock((long) block * BLOCK_SIZE + offset,
0720:                                _allocationTable, offset, length);
0721:                    }
0722:                }
0723:            }
0724:
0725:            /**
0726:             * Reads a fragment.
0727:             *
0728:             * @param fragmentAddress the address of the fragment
0729:             * @param fragmentOffset the offset inside the fragment to start reading
0730:             * @param buffer the result buffer
0731:             * @param offset offset into the result buffer
0732:             * @param length the number of bytes to read
0733:             *
0734:             * @return the number of bytes read
0735:             */
0736:            public int readFragment(long fragmentAddress, int fragmentOffset,
0737:                    byte[] buffer, int offset, int length) throws IOException {
0738:                if (FRAGMENT_SIZE - fragmentOffset < length) {
0739:                    // server/13df
0740:                    throw new IllegalArgumentException(L.l(
0741:                            "read offset {0} length {1} too long",
0742:                            fragmentOffset, length));
0743:                }
0744:
0745:                Block block = readBlock(addressToBlockId(fragmentAddress));
0746:
0747:                try {
0748:                    int blockOffset = getFragmentOffset(fragmentAddress);
0749:
0750:                    byte[] blockBuffer = block.getBuffer();
0751:
0752:                    synchronized (blockBuffer) {
0753:                        System.arraycopy(blockBuffer, blockOffset
0754:                                + fragmentOffset, buffer, offset, length);
0755:                    }
0756:
0757:                    return length;
0758:                } finally {
0759:                    block.free();
0760:                }
0761:            }
0762:
0763:            /**
0764:             * Reads a fragment for a clob.
0765:             *
0766:             * @param fragmentAddress the address of the fragment
0767:             * @param fragmentOffset the offset inside the fragment to start reading
0768:             * @param buffer the result buffer
0769:             * @param offset offset into the result buffer
0770:             * @param length the length of the fragment in characters
0771:             *
0772:             * @return the number of characters read
0773:             */
0774:            public int readFragment(long fragmentAddress, int fragmentOffset,
0775:                    char[] buffer, int offset, int length) throws IOException {
0776:                if (FRAGMENT_SIZE - fragmentOffset < 2 * length) {
0777:                    // server/13df
0778:                    throw new IllegalArgumentException(L.l(
0779:                            "read offset {0} length {1} too long",
0780:                            fragmentOffset, length));
0781:                }
0782:
0783:                Block block = readBlock(addressToBlockId(fragmentAddress));
0784:
0785:                try {
0786:                    int blockOffset = getFragmentOffset(fragmentAddress);
0787:                    blockOffset += fragmentOffset;
0788:
0789:                    byte[] blockBuffer = block.getBuffer();
0790:
0791:                    synchronized (blockBuffer) {
0792:                        for (int i = 0; i < length; i++) {
0793:                            int ch1 = blockBuffer[blockOffset] & 0xff;
0794:                            int ch2 = blockBuffer[blockOffset + 1] & 0xff;
0795:
0796:                            buffer[offset + i] = (char) ((ch1 << 8) + ch2);
0797:
0798:                            blockOffset += 2;
0799:                        }
0800:                    }
0801:
0802:                    return length;
0803:                } finally {
0804:                    block.free();
0805:                }
0806:            }
0807:
0808:            /**
0809:             * Reads a long value from a fragment.
0810:             *
0811:             * @return the long value
0812:             */
0813:            public long readFragmentLong(long fragmentAddress,
0814:                    int fragmentOffset) throws IOException {
0815:                Block block = readBlock(addressToBlockId(fragmentAddress));
0816:
0817:                try {
0818:                    int blockOffset = getFragmentOffset(fragmentAddress);
0819:
0820:                    byte[] blockBuffer = block.getBuffer();
0821:
0822:                    synchronized (blockBuffer) {
0823:                        return readLong(blockBuffer, blockOffset
0824:                                + fragmentOffset);
0825:                    }
0826:                } finally {
0827:                    block.free();
0828:                }
0829:            }
0830:
0831:            /**
0832:             * Reads a block.
0833:             *
0834:             * @param blockAddress the address of the block
0835:             * @param blockOffset the offset inside the block to start reading
0836:             * @param buffer the result buffer
0837:             * @param offset offset into the result buffer
0838:             * @param length the number of bytes to read
0839:             *
0840:             * @return the number of bytes read
0841:             */
0842:            public int readBlock(long blockAddress, int blockOffset,
0843:                    byte[] buffer, int offset, int length) throws IOException {
0844:                if (BLOCK_SIZE - blockOffset < length) {
0845:                    // server/13df
0846:                    throw new IllegalArgumentException(L.l(
0847:                            "read offset {0} length {1} too long", blockOffset,
0848:                            length));
0849:                }
0850:
0851:                Block block = readBlock(addressToBlockId(blockAddress));
0852:
0853:                try {
0854:                    byte[] blockBuffer = block.getBuffer();
0855:
0856:                    synchronized (blockBuffer) {
0857:                        System.arraycopy(blockBuffer, blockOffset, buffer,
0858:                                offset, length);
0859:                    }
0860:
0861:                    return length;
0862:                } finally {
0863:                    block.free();
0864:                }
0865:            }
0866:
0867:            /**
0868:             * Reads a block for a clob.
0869:             *
0870:             * @param blockAddress the address of the block
0871:             * @param blockOffset the offset inside the block to start reading
0872:             * @param buffer the result buffer
0873:             * @param offset offset into the result buffer
0874:             * @param length the length of the block in characters
0875:             *
0876:             * @return the number of characters read
0877:             */
0878:            public int readBlock(long blockAddress, int blockOffset,
0879:                    char[] buffer, int offset, int length) throws IOException {
0880:                if (BLOCK_SIZE - blockOffset < 2 * length) {
0881:                    // server/13df
0882:                    throw new IllegalArgumentException(L.l(
0883:                            "read offset {0} length {1} too long", blockOffset,
0884:                            length));
0885:                }
0886:
0887:                Block block = readBlock(addressToBlockId(blockAddress));
0888:
0889:                try {
0890:                    byte[] blockBuffer = block.getBuffer();
0891:
0892:                    synchronized (blockBuffer) {
0893:                        for (int i = 0; i < length; i++) {
0894:                            int ch1 = blockBuffer[blockOffset] & 0xff;
0895:                            int ch2 = blockBuffer[blockOffset + 1] & 0xff;
0896:
0897:                            buffer[offset + i] = (char) ((ch1 << 8) + ch2);
0898:
0899:                            blockOffset += 2;
0900:                        }
0901:                    }
0902:
0903:                    return length;
0904:                } finally {
0905:                    block.free();
0906:                }
0907:            }
0908:
0909:            /**
0910:             * Reads a long value from a block.
0911:             *
0912:             * @return the long value
0913:             */
0914:            public long readBlockLong(long blockAddress, int offset)
0915:                    throws IOException {
0916:                Block block = readBlock(addressToBlockId(blockAddress));
0917:
0918:                try {
0919:                    byte[] blockBuffer = block.getBuffer();
0920:
0921:                    synchronized (blockBuffer) {
0922:                        return readLong(blockBuffer, offset);
0923:                    }
0924:                } finally {
0925:                    block.free();
0926:                }
0927:            }
0928:
0929:            /**
0930:             * Allocates a new fragment.
0931:             *
0932:             * @return the fragment address
0933:             */
0934:            public long allocateFragment(StoreTransaction xa)
0935:                    throws IOException {
0936:                while (true) {
0937:                    synchronized (_allocationLock) {
0938:                        byte[] allocationTable = _allocationTable;
0939:
0940:                        for (int i = 0; i < allocationTable.length; i += ALLOC_BYTES_PER_BLOCK) {
0941:                            int fragMask = allocationTable[i + 1] & 0xff;
0942:
0943:                            if (allocationTable[i] == ALLOC_FRAGMENT
0944:                                    && fragMask != 0xff) {
0945:                                for (int j = 0; j < FRAGMENT_PER_BLOCK; j++) {
0946:                                    if ((fragMask & (1 << j)) == 0) {
0947:                                        allocationTable[i + 1] = (byte) (fragMask | (1 << j));
0948:
0949:                                        setAllocDirty(i + 1, i + 2);
0950:
0951:                                        _fragmentUseCount++;
0952:
0953:                                        long fragmentAddress = BLOCK_SIZE
0954:                                                * ((long) i / ALLOC_BYTES_PER_BLOCK)
0955:                                                + j;
0956:
0957:                                        //System.out.println((fragmentAddress / BLOCK_SIZE) + ":" + j + " ALLOCATE");
0958:                                        return fragmentAddress;
0959:                                    }
0960:                                }
0961:                            }
0962:                        }
0963:                    }
0964:
0965:                    // if no fragment, allocate a new one.
0966:
0967:                    Block block = allocateFragmentBlock();
0968:                    block.free();
0969:                }
0970:            }
0971:
0972:            /**
0973:             * Deletes a fragment.
0974:             */
0975:            public void deleteFragment(StoreTransaction xa, long fragmentAddress)
0976:                    throws IOException {
0977:                synchronized (_allocationLock) {
0978:                    int i = (int) (ALLOC_BYTES_PER_BLOCK * (fragmentAddress / BLOCK_SIZE));
0979:                    int j = (int) (fragmentAddress & 0xff);
0980:
0981:                    int fragMask = _allocationTable[i + 1] & 0xff;
0982:                    //System.out.println((fragmentAddress / BLOCK_SIZE) + ":" + j + " DELETE");
0983:
0984:                    if (_allocationTable[i] != ALLOC_FRAGMENT)
0985:                        System.out.println("BAD ENTRY: " + fragMask);
0986:
0987:                    if (j >= 8)
0988:                        System.out.println("BAD J: " + fragMask);
0989:
0990:                    if ((fragMask & (1 << j)) == 0) {
0991:                        log.fine("BAD J-MASK: " + fragMask + " " + j);
0992:                    }
0993:
0994:                    _allocationTable[i + 1] = (byte) (fragMask & ~(1 << j));
0995:
0996:                    _fragmentUseCount--;
0997:
0998:                    setAllocDirty(i + 1, i + 2);
0999:                }
1000:            }
1001:
1002:            /**
1003:             * Writes a fragment.
1004:             *
1005:             * @param xa the owning transaction
1006:             * @param fragmentAddress the fragment to write
1007:             * @param fragmentOffset the offset into the fragment
1008:             * @param buffer the write buffer
1009:             * @param offset offset into the write buffer
1010:             * @param length the number of bytes to write
1011:             *
1012:             * @return the fragment id
1013:             */
1014:            public void writeFragment(StoreTransaction xa,
1015:                    long fragmentAddress, int fragmentOffset, byte[] buffer,
1016:                    int offset, int length) throws IOException {
1017:                if (FRAGMENT_SIZE - fragmentOffset < length)
1018:                    throw new IllegalArgumentException(L.l(
1019:                            "write offset {0} length {1} too long",
1020:                            fragmentOffset, length));
1021:
1022:                Block block = xa.readBlock(this ,
1023:                        addressToBlockId(fragmentAddress));
1024:
1025:                try {
1026:                    xa.addUpdateFragmentBlock(block);
1027:
1028:                    int blockOffset = getFragmentOffset(fragmentAddress);
1029:
1030:                    byte[] blockBuffer = block.getBuffer();
1031:
1032:                    blockOffset += fragmentOffset;
1033:
1034:                    synchronized (blockBuffer) {
1035:                        System.arraycopy(buffer, offset, blockBuffer,
1036:                                blockOffset, length);
1037:
1038:                        block.setDirty(blockOffset, blockOffset + length);
1039:                    }
1040:                } finally {
1041:                    block.free();
1042:                }
1043:            }
1044:
1045:            /**
1046:             * Writes a character based
1047:             *
1048:             * @param fragmentAddress the fragment to write
1049:             * @param fragmentOffset the offset into the fragment
1050:             * @param buffer the write buffer
1051:             * @param offset offset into the write buffer
1052:             * @param length the number of bytes to write
1053:             */
1054:            public void writeFragment(StoreTransaction xa,
1055:                    long fragmentAddress, int fragmentOffset, char[] buffer,
1056:                    int offset, int length) throws IOException {
1057:                if (FRAGMENT_SIZE - fragmentOffset < length)
1058:                    throw new IllegalArgumentException(L.l(
1059:                            "write offset {0} length {1} too long",
1060:                            fragmentOffset, length));
1061:
1062:                Block block = xa.readBlock(this ,
1063:                        addressToBlockId(fragmentAddress));
1064:
1065:                try {
1066:                    block = xa.createAutoCommitWriteBlock(block);
1067:
1068:                    int blockOffset = getFragmentOffset(fragmentAddress);
1069:
1070:                    byte[] blockBuffer = block.getBuffer();
1071:
1072:                    blockOffset += fragmentOffset;
1073:
1074:                    synchronized (blockBuffer) {
1075:                        int blockTail = blockOffset;
1076:
1077:                        for (int i = 0; i < length; i++) {
1078:                            char ch = buffer[offset + i];
1079:
1080:                            blockBuffer[blockTail] = (byte) (ch >> 8);
1081:                            blockBuffer[blockTail + 1] = (byte) (ch);
1082:
1083:                            blockTail += 2;
1084:                        }
1085:
1086:                        block.setDirty(blockOffset, blockTail);
1087:                    }
1088:                } finally {
1089:                    block.free();
1090:                }
1091:            }
1092:
1093:            /**
1094:             * Writes a long value to a fragment.
1095:             *
1096:             * @return the long value
1097:             */
1098:            public void writeFragmentLong(StoreTransaction xa,
1099:                    long fragmentAddress, int fragmentOffset, long value)
1100:                    throws IOException {
1101:                Block block = xa.readBlock(this ,
1102:                        addressToBlockId(fragmentAddress));
1103:
1104:                try {
1105:                    xa.addUpdateBlock(block);
1106:
1107:                    int blockOffset = getFragmentOffset(fragmentAddress);
1108:
1109:                    byte[] blockBuffer = block.getBuffer();
1110:                    int offset = blockOffset + fragmentOffset;
1111:
1112:                    synchronized (blockBuffer) {
1113:                        writeLong(blockBuffer, offset, value);
1114:
1115:                        block.setDirty(offset, offset + 8);
1116:                    }
1117:                } finally {
1118:                    block.free();
1119:                }
1120:            }
1121:
1122:            /**
1123:             * Writes a blockfragment.
1124:             *
1125:             * @param xa the owning transaction
1126:             * @param blockAddress the block to write
1127:             * @param blockOffset the offset into the block
1128:             * @param buffer the write buffer
1129:             * @param offset offset into the write buffer
1130:             * @param length the number of bytes to write
1131:             *
1132:             * @return the fragment id
1133:             */
1134:            public void writeBlock(StoreTransaction xa, long blockAddress,
1135:                    int blockOffset, byte[] buffer, int offset, int length)
1136:                    throws IOException {
1137:                if (BLOCK_SIZE - blockOffset < length)
1138:                    throw new IllegalArgumentException(L.l(
1139:                            "write offset {0} length {1} too long",
1140:                            blockOffset, length));
1141:
1142:                Block block = xa
1143:                        .readBlock(this , addressToBlockId(blockAddress));
1144:
1145:                try {
1146:                    xa.addUpdateBlock(block);
1147:
1148:                    byte[] blockBuffer = block.getBuffer();
1149:
1150:                    synchronized (blockBuffer) {
1151:                        System.arraycopy(buffer, offset, blockBuffer,
1152:                                blockOffset, length);
1153:
1154:                        block.setDirty(blockOffset, blockOffset + length);
1155:                    }
1156:                } finally {
1157:                    block.free();
1158:                }
1159:            }
1160:
1161:            /**
1162:             * Writes a character based block
1163:             *
1164:             * @param blockAddress the fragment to write
1165:             * @param blockOffset the offset into the fragment
1166:             * @param buffer the write buffer
1167:             * @param offset offset into the write buffer
1168:             * @param length the number of bytes to write
1169:             */
1170:            public void writeBlock(StoreTransaction xa, long blockAddress,
1171:                    int blockOffset, char[] buffer, int offset, int length)
1172:                    throws IOException {
1173:                if (BLOCK_SIZE - blockOffset < length)
1174:                    throw new IllegalArgumentException(L.l(
1175:                            "write offset {0} length {1} too long",
1176:                            blockOffset, length));
1177:
1178:                Block block = xa
1179:                        .readBlock(this , addressToBlockId(blockAddress));
1180:
1181:                try {
1182:                    block = xa.createAutoCommitWriteBlock(block);
1183:
1184:                    byte[] blockBuffer = block.getBuffer();
1185:
1186:                    synchronized (blockBuffer) {
1187:                        int blockTail = blockOffset;
1188:
1189:                        for (int i = 0; i < length; i++) {
1190:                            char ch = buffer[offset + i];
1191:
1192:                            blockBuffer[blockTail] = (byte) (ch >> 8);
1193:                            blockBuffer[blockTail + 1] = (byte) (ch);
1194:
1195:                            blockTail += 2;
1196:                        }
1197:
1198:                        block.setDirty(blockOffset, blockTail);
1199:                    }
1200:                } finally {
1201:                    block.free();
1202:                }
1203:            }
1204:
1205:            /**
1206:             * Writes a long value to a block
1207:             *
1208:             * @return the long value
1209:             */
1210:            public void writeBlockLong(StoreTransaction xa, long blockAddress,
1211:                    int offset, long value) throws IOException {
1212:                Block block = xa
1213:                        .readBlock(this , addressToBlockId(blockAddress));
1214:
1215:                try {
1216:                    xa.addUpdateBlock(block);
1217:
1218:                    byte[] blockBuffer = block.getBuffer();
1219:
1220:                    synchronized (blockBuffer) {
1221:                        writeLong(blockBuffer, offset, value);
1222:
1223:                        block.setDirty(offset, offset + 8);
1224:                    }
1225:                } finally {
1226:                    block.free();
1227:                }
1228:            }
1229:
1230:            /**
1231:             * Returns the fragment offset for an id.
1232:             */
1233:            private int getFragmentOffset(long fragmentAddress) {
1234:                int id = (int) (fragmentAddress & BLOCK_OFFSET_MASK);
1235:
1236:                return (int) (FRAGMENT_SIZE * id);
1237:            }
1238:
1239:            /**
1240:             * Reads a fragment.
1241:             *
1242:             * @param fragmentAddress the address of the fragment
1243:             * @param fragmentOffset the offset inside the fragment to start reading
1244:             * @param buffer the result buffer
1245:             * @param offset offset into the result buffer
1246:             * @param length the number of bytes to read
1247:             *
1248:             * @return the number of bytes read
1249:             */
1250:            public int readMiniFragment(long fragmentAddress,
1251:                    int fragmentOffset, byte[] buffer, int offset, int length)
1252:                    throws IOException {
1253:                if (MINI_FRAG_SIZE - fragmentOffset < length) {
1254:                    throw new IllegalArgumentException(L.l(
1255:                            "read offset {0} length {1} too long",
1256:                            fragmentOffset, length));
1257:                }
1258:
1259:                Block block = readBlock(addressToBlockId(fragmentAddress));
1260:
1261:                try {
1262:                    int blockOffset = getMiniFragmentOffset(fragmentAddress);
1263:
1264:                    byte[] blockBuffer = block.getBuffer();
1265:
1266:                    synchronized (blockBuffer) {
1267:                        System.arraycopy(blockBuffer, blockOffset
1268:                                + fragmentOffset, buffer, offset, length);
1269:                    }
1270:
1271:                    return length;
1272:                } finally {
1273:                    block.free();
1274:                }
1275:            }
1276:
1277:            /**
1278:             * Reads a miniFragment for a clob.
1279:             *
1280:             * @param fragmentAddress the address of the fragment
1281:             * @param fragmentOffset the offset inside the fragment to start reading
1282:             * @param buffer the result buffer
1283:             * @param offset offset into the result buffer
1284:             * @param length the length of the fragment in characters
1285:             *
1286:             * @return the number of characters read
1287:             */
1288:            public int readMiniFragment(long fragmentAddress,
1289:                    int fragmentOffset, char[] buffer, int offset, int length)
1290:                    throws IOException {
1291:                if (MINI_FRAG_SIZE - fragmentOffset < 2 * length) {
1292:                    throw new IllegalArgumentException(L.l(
1293:                            "read offset {0} length {1} too long",
1294:                            fragmentOffset, length));
1295:                }
1296:
1297:                Block block = readBlock(addressToBlockId(fragmentAddress));
1298:
1299:                try {
1300:                    int blockOffset = getMiniFragmentOffset(fragmentAddress);
1301:                    blockOffset += fragmentOffset;
1302:
1303:                    byte[] blockBuffer = block.getBuffer();
1304:
1305:                    synchronized (blockBuffer) {
1306:                        for (int i = 0; i < length; i++) {
1307:                            int ch1 = blockBuffer[blockOffset] & 0xff;
1308:                            int ch2 = blockBuffer[blockOffset + 1] & 0xff;
1309:
1310:                            buffer[offset + i] = (char) ((ch1 << 8) + ch2);
1311:
1312:                            blockOffset += 2;
1313:                        }
1314:                    }
1315:
1316:                    return length;
1317:                } finally {
1318:                    block.free();
1319:                }
1320:            }
1321:
1322:            /**
1323:             * Reads a long value from a miniFragment.
1324:             *
1325:             * @return the long value
1326:             */
1327:            public long readMiniFragmentLong(long fragmentAddress,
1328:                    int fragmentOffset) throws IOException {
1329:                Block block = readBlock(addressToBlockId(fragmentAddress));
1330:
1331:                try {
1332:                    int blockOffset = getMiniFragmentOffset(fragmentAddress);
1333:
1334:                    byte[] blockBuffer = block.getBuffer();
1335:
1336:                    synchronized (blockBuffer) {
1337:                        return readLong(blockBuffer, blockOffset
1338:                                + fragmentOffset);
1339:                    }
1340:                } finally {
1341:                    block.free();
1342:                }
1343:            }
1344:
1345:            /**
1346:             * Allocates a new miniFragment.
1347:             *
1348:             * @return the fragment address
1349:             */
1350:            public long allocateMiniFragment(StoreTransaction xa)
1351:                    throws IOException {
1352:                while (true) {
1353:                    long blockAddr = allocateMiniFragmentBlock(xa);
1354:
1355:                    Block block = readBlock(blockAddr);
1356:                    int fragOffset = -1;
1357:
1358:                    try {
1359:                        byte[] blockBuffer = block.getBuffer();
1360:
1361:                        synchronized (blockBuffer) {
1362:                            for (int i = 0; i < MINI_FRAG_PER_BLOCK; i++) {
1363:                                int offset = i / 8 + MINI_FRAG_ALLOC_OFFSET;
1364:                                int mask = 1 << (i % 8);
1365:
1366:                                if ((blockBuffer[offset] & mask) == 0) {
1367:                                    fragOffset = i;
1368:                                    blockBuffer[offset] |= mask;
1369:                                    block.setDirty(offset, offset + 1);
1370:                                    break;
1371:                                }
1372:                            }
1373:
1374:                            // fragment allocated underneath us
1375:                            if (fragOffset < 0)
1376:                                continue;
1377:
1378:                            boolean hasFree = false;
1379:                            for (int i = 0; i < MINI_FRAG_PER_BLOCK; i++) {
1380:                                int offset = i / 8 + MINI_FRAG_ALLOC_OFFSET;
1381:                                int mask = 1 << (i % 8);
1382:
1383:                                if ((blockBuffer[offset] & mask) == 0) {
1384:                                    hasFree = true;
1385:                                    break;
1386:                                }
1387:                            }
1388:
1389:                            if (hasFree) {
1390:                                int i = (int) (ALLOC_BYTES_PER_BLOCK * (blockAddr / BLOCK_SIZE));
1391:
1392:                                synchronized (_allocationLock) {
1393:                                    _allocationTable[i + 1] = 0;
1394:                                    setAllocDirty(i + 1, i + 2);
1395:                                }
1396:                            }
1397:
1398:                            return blockAddr + fragOffset;
1399:                        }
1400:                    } finally {
1401:                        block.free();
1402:                    }
1403:                }
1404:            }
1405:
1406:            /**
1407:             * Allocates a new miniFragment.
1408:             *
1409:             * @return the fragment address
1410:             */
1411:            private long allocateMiniFragmentBlock(StoreTransaction xa)
1412:                    throws IOException {
1413:                while (true) {
1414:                    synchronized (_allocationLock) {
1415:                        byte[] allocationTable = _allocationTable;
1416:
1417:                        for (int i = 0; i < allocationTable.length; i += ALLOC_BYTES_PER_BLOCK) {
1418:                            int fragMask = allocationTable[i + 1] & 0xff;
1419:
1420:                            if (allocationTable[i] == ALLOC_MINI_FRAG
1421:                                    && fragMask != 0xff) {
1422:                                allocationTable[i + 1] = (byte) 0xff;
1423:
1424:                                setAllocDirty(i + 1, i + 2);
1425:
1426:                                _miniFragmentUseCount++;
1427:
1428:                                long fragmentAddress = BLOCK_SIZE
1429:                                        * ((long) i / ALLOC_BYTES_PER_BLOCK);
1430:
1431:                                return fragmentAddress;
1432:                            }
1433:                        }
1434:                    }
1435:
1436:                    // if no fragment, allocate a new one.
1437:
1438:                    Block block = allocateMiniFragmentBlock();
1439:                    block.free();
1440:                }
1441:            }
1442:
1443:            /**
1444:             * Deletes a miniFragment.
1445:             */
1446:            public void deleteMiniFragment(StoreTransaction xa,
1447:                    long fragmentAddress) throws IOException {
1448:                Block block = readBlock(fragmentAddress);
1449:
1450:                try {
1451:                    int fragIndex = (int) (fragmentAddress & BLOCK_OFFSET_MASK);
1452:                    int offset = fragIndex / 8 + MINI_FRAG_ALLOC_OFFSET;
1453:                    int mask = 1 << (fragIndex % 8);
1454:                    byte[] blockBuffer = block.getBuffer();
1455:
1456:                    synchronized (blockBuffer) {
1457:                        blockBuffer[offset] &= ~mask;
1458:                        block.setDirty(offset, offset + 1);
1459:
1460:                        int i = (int) (ALLOC_BYTES_PER_BLOCK * (fragmentAddress / BLOCK_SIZE));
1461:                        int j = (int) (fragmentAddress & 0xff);
1462:
1463:                        synchronized (_allocationLock) {
1464:                            int fragMask = _allocationTable[i + 1] & 0xff;
1465:                            //System.out.println((fragmentAddress / BLOCK_SIZE) + ":" + j + " DELETE");
1466:
1467:                            if (_allocationTable[i] != ALLOC_MINI_FRAG)
1468:                                System.out.println("BAD ENTRY: " + fragMask);
1469:
1470:                            _allocationTable[i + 1] = 0;
1471:
1472:                            _miniFragmentUseCount--;
1473:
1474:                            setAllocDirty(i + 1, i + 2);
1475:                        }
1476:                    }
1477:                } finally {
1478:                    block.free();
1479:                }
1480:            }
1481:
1482:            /**
1483:             * Writes a miniFragment.
1484:             *
1485:             * @param xa the owning transaction
1486:             * @param fragmentAddress the fragment to write
1487:             * @param fragmentOffset the offset into the fragment
1488:             * @param buffer the write buffer
1489:             * @param offset offset into the write buffer
1490:             * @param length the number of bytes to write
1491:             *
1492:             * @return the fragment id
1493:             */
1494:            public void writeMiniFragment(StoreTransaction xa,
1495:                    long fragmentAddress, int fragmentOffset, byte[] buffer,
1496:                    int offset, int length) throws IOException {
1497:                if (MINI_FRAG_SIZE - fragmentOffset < length)
1498:                    throw new IllegalArgumentException(L.l(
1499:                            "write offset {0} length {1} too long",
1500:                            fragmentOffset, length));
1501:
1502:                Block block = xa.readBlock(this ,
1503:                        addressToBlockId(fragmentAddress));
1504:
1505:                try {
1506:                    xa.addUpdateBlock(block);
1507:
1508:                    int blockOffset = getMiniFragmentOffset(fragmentAddress);
1509:
1510:                    byte[] blockBuffer = block.getBuffer();
1511:
1512:                    blockOffset += fragmentOffset;
1513:
1514:                    synchronized (blockBuffer) {
1515:                        System.arraycopy(buffer, offset, blockBuffer,
1516:                                blockOffset, length);
1517:
1518:                        block.setDirty(blockOffset, blockOffset + length);
1519:                    }
1520:                } finally {
1521:                    block.free();
1522:                }
1523:            }
1524:
1525:            /**
1526:             * Writes a character based
1527:             *
1528:             * @param miniFragmentAddress the fragment to write
1529:             * @param fragmentOffset the offset into the fragment
1530:             * @param buffer the write buffer
1531:             * @param offset offset into the write buffer
1532:             * @param length the number of bytes to write
1533:             */
1534:            public void writeMiniFragment(StoreTransaction xa,
1535:                    long fragmentAddress, int fragmentOffset, char[] buffer,
1536:                    int offset, int length) throws IOException {
1537:                if (MINI_FRAG_SIZE - fragmentOffset < length)
1538:                    throw new IllegalArgumentException(L.l(
1539:                            "write offset {0} length {1} too long",
1540:                            fragmentOffset, length));
1541:
1542:                Block block = xa.readBlock(this ,
1543:                        addressToBlockId(fragmentAddress));
1544:
1545:                try {
1546:                    block = xa.createAutoCommitWriteBlock(block);
1547:
1548:                    int blockOffset = getMiniFragmentOffset(fragmentAddress);
1549:
1550:                    byte[] blockBuffer = block.getBuffer();
1551:
1552:                    blockOffset += fragmentOffset;
1553:
1554:                    synchronized (blockBuffer) {
1555:                        int blockTail = blockOffset;
1556:
1557:                        for (int i = 0; i < length; i++) {
1558:                            char ch = buffer[offset + i];
1559:
1560:                            blockBuffer[blockTail] = (byte) (ch >> 8);
1561:                            blockBuffer[blockTail + 1] = (byte) (ch);
1562:
1563:                            blockTail += 2;
1564:                        }
1565:
1566:                        block.setDirty(blockOffset, blockTail);
1567:                    }
1568:                } finally {
1569:                    block.free();
1570:                }
1571:            }
1572:
1573:            /**
1574:             * Writes a long value to a miniFragment.
1575:             *
1576:             * @return the long value
1577:             */
1578:            public void writeMiniFragmentLong(StoreTransaction xa,
1579:                    long fragmentAddress, int fragmentOffset, long value)
1580:                    throws IOException {
1581:                Block block = xa.readBlock(this ,
1582:                        addressToBlockId(fragmentAddress));
1583:
1584:                try {
1585:                    xa.addUpdateBlock(block);
1586:
1587:                    int blockOffset = getMiniFragmentOffset(fragmentAddress);
1588:
1589:                    byte[] blockBuffer = block.getBuffer();
1590:                    int offset = blockOffset + fragmentOffset;
1591:
1592:                    synchronized (blockBuffer) {
1593:                        writeLong(blockBuffer, offset, value);
1594:
1595:                        block.setDirty(offset, offset + 8);
1596:                    }
1597:                } finally {
1598:                    block.free();
1599:                }
1600:            }
1601:
1602:            /**
1603:             * Returns the miniFragment offset for an id.
1604:             */
1605:            private int getMiniFragmentOffset(long fragmentAddress) {
1606:                int id = (int) (fragmentAddress & BLOCK_OFFSET_MASK);
1607:
1608:                return (int) (MINI_FRAG_SIZE * id);
1609:            }
1610:
1611:            /**
1612:             * Reads a block into the buffer.
1613:             */
1614:            public void readBlock(long blockId, byte[] buffer, int offset,
1615:                    int length) throws IOException {
1616:                synchronized (_fileLock) {
1617:                    RandomAccessWrapper wrapper = openRowFile();
1618:                    RandomAccessStream is = wrapper.getFile();
1619:
1620:                    long blockAddress = blockId & BLOCK_MASK;
1621:
1622:                    try {
1623:                        if (blockAddress < 0
1624:                                || _fileSize < blockAddress + length) {
1625:                            throw new IllegalStateException(
1626:                                    L
1627:                                            .l(
1628:                                                    "block at {0} is invalid for file {1} (length {2})",
1629:                                                    Long
1630:                                                            .toHexString(blockAddress),
1631:                                                    _path,
1632:                                                    Long.toHexString(_fileSize)));
1633:                        }
1634:
1635:                        //System.out.println("READ: " + (blockAddress >> 16) + ":" + (blockAddress & 0xffff));
1636:                        int readLen = is.read(blockAddress, buffer, offset,
1637:                                length);
1638:
1639:                        if (readLen < 0) {
1640:                            for (int i = 0; i < BLOCK_SIZE; i++)
1641:                                buffer[i] = 0;
1642:                        }
1643:
1644:                        freeRowFile(wrapper);
1645:                        wrapper = null;
1646:                    } finally {
1647:                        if (wrapper != null)
1648:                            wrapper.close();
1649:                    }
1650:                }
1651:            }
1652:
1653:            /**
1654:             * Saves the buffer to the database.
1655:             */
1656:            public void writeBlock(long blockAddress, byte[] buffer,
1657:                    int offset, int length) throws IOException {
1658:                synchronized (_fileLock) {
1659:                    RandomAccessWrapper wrapper = openRowFile();
1660:                    RandomAccessStream os = wrapper.getFile();
1661:
1662:                    try {
1663:                        os.write(blockAddress, buffer, offset, length);
1664:
1665:                        freeRowFile(wrapper);
1666:                        wrapper = null;
1667:
1668:                        if (_fileSize < blockAddress + length) {
1669:                            _fileSize = blockAddress + length;
1670:                        }
1671:
1672:                    } finally {
1673:                        if (wrapper != null)
1674:                            wrapper.close();
1675:                    }
1676:                }
1677:            }
1678:
1679:            /**
1680:             * Opens the underlying file to the database.
1681:             */
1682:            private RandomAccessWrapper openRowFile() throws IOException {
1683:                RandomAccessStream file = null;
1684:                RandomAccessWrapper wrapper = null;
1685:
1686:                synchronized (this ) {
1687:                    SoftReference<RandomAccessWrapper> ref = _cachedRowFile;
1688:                    _cachedRowFile = null;
1689:
1690:                    if (ref != null) {
1691:                        wrapper = ref.get();
1692:                    }
1693:                }
1694:
1695:                if (wrapper != null)
1696:                    file = wrapper.getFile();
1697:
1698:                if (file == null) {
1699:                    file = _path.openRandomAccess();
1700:
1701:                    wrapper = new RandomAccessWrapper(file);
1702:                }
1703:
1704:                return wrapper;
1705:            }
1706:
1707:            private void freeRowFile(RandomAccessWrapper wrapper)
1708:                    throws IOException {
1709:                synchronized (this ) {
1710:                    if (_cachedRowFile == null) {
1711:                        _cachedRowFile = new SoftReference<RandomAccessWrapper>(
1712:                                wrapper);
1713:                        return;
1714:                    }
1715:                }
1716:
1717:                wrapper.close();
1718:            }
1719:
1720:            /**
1721:             * Writes the short.
1722:             */
1723:            private static void writeShort(byte[] buffer, int offset, int v) {
1724:                buffer[offset + 0] = (byte) (v >> 8);
1725:                buffer[offset + 1] = (byte) (v);
1726:            }
1727:
1728:            /**
1729:             * Reads a short.
1730:             */
1731:            private static int readShort(byte[] buffer, int offset) {
1732:                return (((buffer[offset + 0] & 0xff) << 8) | ((buffer[offset + 1] & 0xff)));
1733:            }
1734:
1735:            /**
1736:             * Flush the store.
1737:             */
1738:            public void flush() {
1739:                if (_lifecycle.isActive()) {
1740:                    if (_blockManager != null) {
1741:                        _blockManager.flush(this );
1742:                    }
1743:                }
1744:            }
1745:
1746:            /**
1747:             * True if destroyed.
1748:             */
1749:            public boolean isClosed() {
1750:                return _lifecycle.isDestroyed();
1751:            }
1752:
1753:            /**
1754:             * Closes the store.
1755:             */
1756:            public void close() {
1757:                if (!_lifecycle.toDestroy())
1758:                    return;
1759:
1760:                log.finer(this  + " closing");
1761:
1762:                if (_blockManager != null) {
1763:                    _blockManager.freeStore(this );
1764:                    _blockManager.freeStoreId(_id);
1765:                }
1766:
1767:                long id = _id;
1768:                _id = 0;
1769:
1770:                _path = null;
1771:
1772:                RandomAccessWrapper wrapper = null;
1773:
1774:                SoftReference<RandomAccessWrapper> ref = _cachedRowFile;
1775:                _cachedRowFile = null;
1776:
1777:                if (ref != null)
1778:                    wrapper = ref.get();
1779:
1780:                if (wrapper != null) {
1781:                    try {
1782:                        wrapper.close();
1783:                    } catch (Throwable e) {
1784:                    }
1785:                }
1786:            }
1787:
1788:            // debugging stuff.
1789:            /**
1790:             * Returns a copy of the allocation table.
1791:             */
1792:            public byte[] getAllocationTable() {
1793:                byte[] table = new byte[_allocationTable.length];
1794:
1795:                System.arraycopy(_allocationTable, 0, table, 0, table.length);
1796:
1797:                return table;
1798:            }
1799:
1800:            private static IllegalStateException stateError(String msg) {
1801:                IllegalStateException e = new IllegalStateException(msg);
1802:                e.fillInStackTrace();
1803:                log.log(Level.WARNING, e.toString(), e);
1804:                return e;
1805:            }
1806:
1807:            /**
1808:             * Reads the long.
1809:             */
1810:            public static long readLong(byte[] buffer, int offset) {
1811:                return (((buffer[offset + 0] & 0xffL) << 56)
1812:                        + ((buffer[offset + 1] & 0xffL) << 48)
1813:                        + ((buffer[offset + 2] & 0xffL) << 40)
1814:                        + ((buffer[offset + 3] & 0xffL) << 32)
1815:                        + ((buffer[offset + 4] & 0xffL) << 24)
1816:                        + ((buffer[offset + 5] & 0xffL) << 16)
1817:                        + ((buffer[offset + 6] & 0xffL) << 8) + ((buffer[offset + 7] & 0xffL)));
1818:            }
1819:
1820:            /**
1821:             * Writes the long.
1822:             */
1823:            public static void writeLong(byte[] buffer, int offset, long v) {
1824:                buffer[offset + 0] = (byte) (v >> 56);
1825:                buffer[offset + 1] = (byte) (v >> 48);
1826:                buffer[offset + 2] = (byte) (v >> 40);
1827:                buffer[offset + 3] = (byte) (v >> 32);
1828:
1829:                buffer[offset + 4] = (byte) (v >> 24);
1830:                buffer[offset + 5] = (byte) (v >> 16);
1831:                buffer[offset + 6] = (byte) (v >> 8);
1832:                buffer[offset + 7] = (byte) (v);
1833:            }
1834:
1835:            /**
1836:             * Debug names for the allocation.
1837:             */
1838:            public static String codeToName(int code) {
1839:                switch (code) {
1840:                case ALLOC_FREE:
1841:                    return "free";
1842:                case ALLOC_ROW:
1843:                    return "row";
1844:                case ALLOC_USED:
1845:                    return "used";
1846:                case ALLOC_FRAGMENT:
1847:                    return "fragment";
1848:                case ALLOC_MINI_FRAG:
1849:                    return "mini-fragment";
1850:                case ALLOC_INDEX:
1851:                    return "index";
1852:                default:
1853:                    return String.valueOf(code);
1854:                }
1855:            }
1856:
1857:            public String toString() {
1858:                return "Store[" + _id + "]";
1859:            }
1860:
1861:            static class RandomAccessWrapper {
1862:                private RandomAccessStream _file;
1863:
1864:                RandomAccessWrapper(RandomAccessStream file) {
1865:                    _file = file;
1866:                }
1867:
1868:                RandomAccessStream getFile() {
1869:                    return _file;
1870:                }
1871:
1872:                void close() throws IOException {
1873:                    RandomAccessStream file = _file;
1874:                    _file = null;
1875:
1876:                    if (file != null)
1877:                        file.close();
1878:                }
1879:
1880:                protected void finalize() throws Throwable {
1881:                    super.finalize();
1882:
1883:                    close();
1884:                }
1885:            }
1886:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.