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


001:        /*
002:         * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003:         *
004:         * This file is part of Resin(R) Open Source
005:         *
006:         * Each copy or derived work must preserve the copyright notice and this
007:         * notice unmodified.
008:         *
009:         * Resin Open Source is free software; you can redistribute it and/or modify
010:         * it under the terms of the GNU General Public License as published by
011:         * the Free Software Foundation; either version 2 of the License, or
012:         * (at your option) any later version.
013:         *
014:         * Resin Open Source is distributed in the hope that it will be useful,
015:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
016:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017:         * of NON-INFRINGEMENT.  See the GNU General Public License for more
018:         * details.
019:         *
020:         * You should have received a copy of the GNU General Public License
021:         * along with Resin Open Source; if not, write to the
022:         *
023:         *   Free Software Foundation, Inc.
024:         *   59 Temple Place, Suite 330
025:         *   Boston, MA 02111-1307  USA
026:         *
027:         * @author Scott Ferguson
028:         */
029:
030:        package com.caucho.db.table;
031:
032:        import com.caucho.db.Database;
033:        import com.caucho.db.index.BTree;
034:        import com.caucho.db.index.KeyCompare;
035:        import com.caucho.db.sql.CreateQuery;
036:        import com.caucho.db.sql.Expr;
037:        import com.caucho.db.sql.Parser;
038:        import com.caucho.db.sql.QueryContext;
039:        import com.caucho.db.store.Block;
040:        import com.caucho.db.store.Lock;
041:        import com.caucho.db.store.Store;
042:        import com.caucho.db.store.Transaction;
043:        import com.caucho.log.Log;
044:        import com.caucho.sql.SQLExceptionWrapper;
045:        import com.caucho.util.L10N;
046:        import com.caucho.vfs.Path;
047:        import com.caucho.vfs.ReadStream;
048:        import com.caucho.vfs.TempBuffer;
049:        import com.caucho.vfs.TempStream;
050:        import com.caucho.vfs.WriteStream;
051:
052:        import java.io.IOException;
053:        import java.sql.SQLException;
054:        import java.util.ArrayList;
055:        import java.util.logging.Level;
056:        import java.util.logging.Logger;
057:
058:        /**
059:         * Table format:
060:         *
061:         * <pre>
062:         * Block 0: allocation table
063:         * Block 1: fragment table
064:         * Block 2: table definition
065:         *   0    - store data
066:         *   1024 - table data
067:         *    1024 - index pointers
068:         *   2048 - CREATE text
069:         * Block 3: first data
070:         * </pre>
071:         */
072:        public class Table extends Store {
073:            private final static Logger log = Log.open(Table.class);
074:            private final static L10N L = new L10N(Table.class);
075:
076:            private final static int ROOT_DATA_OFFSET = STORE_CREATE_END;
077:            private final static int INDEX_ROOT_OFFSET = ROOT_DATA_OFFSET + 32;
078:
079:            private final static int ROOT_DATA_END = ROOT_DATA_OFFSET + 1024;
080:
081:            public final static int INLINE_BLOB_SIZE = 120;
082:
083:            public final static long ROW_CLOCK_MIN = 1024;
084:
085:            public final static byte ROW_VALID = 0x1;
086:            public final static byte ROW_ALLOC = 0x2;
087:            public final static byte ROW_MASK = 0x3;
088:
089:            private final static String DB_VERSION = "Resin-DB 3.1.1";
090:            private final static String MIN_VERSION = "Resin-DB 3.1.1";
091:
092:            private final Row _row;
093:
094:            private final int _rowLength;
095:            private final int _rowsPerBlock;
096:            private final int _rowEnd;
097:
098:            private final Constraint[] _constraints;
099:
100:            private final Column _autoIncrementColumn;
101:
102:            private long _entries;
103:
104:            private final Object _rowClockLock = new Object();
105:            private long _rowClockAddr;
106:            private long _rowClockTotal;
107:            private long _rowClockUsed;
108:            private int _rowClockCount;
109:            private int _rowAllocCount;
110:
111:            private long _autoIncrementValue = -1;
112:
113:            private Lock _allocLock;
114:            private Lock _insertLock;
115:
116:            Table(Database database, String name, Row row,
117:                    Constraint constraints[]) {
118:                super (database, name, null);
119:
120:                _row = row;
121:                _constraints = constraints;
122:
123:                _rowLength = _row.getLength();
124:                _rowsPerBlock = BLOCK_SIZE / _rowLength;
125:                _rowEnd = _rowLength * _rowsPerBlock;
126:
127:                _rowClockAddr = 0;
128:
129:                Column[] columns = _row.getColumns();
130:                Column autoIncrementColumn = null;
131:                for (int i = 0; i < columns.length; i++) {
132:                    columns[i].setTable(this );
133:
134:                    if (columns[i].getAutoIncrement() >= 0)
135:                        autoIncrementColumn = columns[i];
136:                }
137:                _autoIncrementColumn = autoIncrementColumn;
138:
139:                _insertLock = new Lock("table-insert:" + name);
140:                _allocLock = new Lock("table-alloc:" + name);
141:            }
142:
143:            Row getRow() {
144:                return _row;
145:            }
146:
147:            /**
148:             * Returns the length of a row.
149:             */
150:            int getRowLength() {
151:                return _rowLength;
152:            }
153:
154:            /**
155:             * Returns the end of the row
156:             */
157:            int getRowEnd() {
158:                return _rowEnd;
159:            }
160:
161:            public final Column[] getColumns() {
162:                return _row.getColumns();
163:            }
164:
165:            /**
166:             * Returns the table's constraints.
167:             */
168:            public final Constraint[] getConstraints() {
169:                return _constraints;
170:            }
171:
172:            /**
173:             * Returns the auto-increment column.
174:             */
175:            public Column getAutoIncrementColumn() {
176:                return _autoIncrementColumn;
177:            }
178:
179:            /**
180:             * Returns the column for the given column name.
181:             *
182:             * @param name the column name
183:             *
184:             * @return the column
185:             */
186:            public Column getColumn(String name) {
187:                Column[] columns = getColumns();
188:
189:                for (int i = 0; i < columns.length; i++) {
190:                    if (columns[i].getName().equals(name))
191:                        return columns[i];
192:                }
193:
194:                return null;
195:            }
196:
197:            /**
198:             * Returns the column index for the given column name.
199:             *
200:             * @param name the column name
201:             *
202:             * @return the column index.
203:             */
204:            public int getColumnIndex(String name) throws SQLException {
205:                Column[] columns = getColumns();
206:
207:                for (int i = 0; i < columns.length; i++) {
208:                    if (columns[i].getName().equals(name))
209:                        return i;
210:                }
211:
212:                return -1;
213:            }
214:
215:            /**
216:             * Loads the table from the file.
217:             */
218:            public static Table loadFromFile(Database db, String name)
219:                    throws IOException, SQLException {
220:                Path path = db.getPath().lookup(name + ".db");
221:
222:                if (!path.exists())
223:                    throw new IOException(L.l("table {0} does not exist", name));
224:
225:                String version = null;
226:
227:                ReadStream is = path.openRead();
228:                try {
229:                    // skip allocation table and fragment table
230:                    is.skip(DATA_START + ROOT_DATA_OFFSET);
231:
232:                    StringBuilder sb = new StringBuilder();
233:                    int ch;
234:
235:                    while ((ch = is.read()) > 0) {
236:                        sb.append((char) ch);
237:                    }
238:
239:                    version = sb.toString();
240:
241:                    if (!version.startsWith("Resin-DB")) {
242:                        throw new SQLException(L.l(
243:                                "table {0} is not a Resin DB.  Version '{1}'",
244:                                name, version));
245:                    } else if (version.compareTo(MIN_VERSION) < 0
246:                            || DB_VERSION.compareTo(version) < 0) {
247:                        throw new SQLException(L.l(
248:                                "table {0} is out of date.  Old version {1}.",
249:                                name, version));
250:                    }
251:                } finally {
252:                    is.close();
253:                }
254:
255:                is = path.openRead();
256:                try {
257:                    // skip allocation table and fragment table
258:                    is.skip(DATA_START + ROOT_DATA_END);
259:
260:                    StringBuilder cb = new StringBuilder();
261:
262:                    int ch;
263:                    while ((ch = is.read()) > 0) {
264:                        cb.append((char) ch);
265:                    }
266:
267:                    String sql = cb.toString();
268:
269:                    if (log.isLoggable(Level.FINER))
270:                        log.finer("Table[" + name + "] " + version
271:                                + " loading\n" + sql);
272:
273:                    try {
274:                        CreateQuery query = (CreateQuery) Parser.parse(db, sql);
275:
276:                        TableFactory factory = query.getFactory();
277:
278:                        if (!factory.getName().equalsIgnoreCase(name))
279:                            throw new IOException(L.l(
280:                                    "factory {0} does not match", name));
281:
282:                        Table table = new Table(db, factory.getName(), factory
283:                                .getRow(), factory.getConstraints());
284:
285:                        table.init();
286:
287:                        table.clearIndexes();
288:                        table.initIndexes();
289:                        table.rebuildIndexes();
290:
291:                        return table;
292:                    } catch (Exception e) {
293:                        log.log(Level.FINE, e.toString(), e);
294:
295:                        log.warning(e.toString());
296:
297:                        throw new SQLException(L.l(
298:                                "can't load table {0} in {1}.\n{2}", name, path
299:                                        .getNativePath(), e.toString()));
300:                    }
301:                } finally {
302:                    is.close();
303:                }
304:            }
305:
306:            /**
307:             * Creates the table.
308:             */
309:            public void create() throws IOException, SQLException {
310:                super .create();
311:
312:                initIndexes();
313:
314:                byte[] tempBuffer = new byte[BLOCK_SIZE];
315:
316:                readBlock(BLOCK_SIZE, tempBuffer, 0, BLOCK_SIZE);
317:
318:                TempStream ts = new TempStream();
319:
320:                WriteStream os = new WriteStream(ts);
321:
322:                try {
323:                    for (int i = 0; i < ROOT_DATA_OFFSET; i++)
324:                        os.write(tempBuffer[i]);
325:
326:                    writeTableHeader(os);
327:                } finally {
328:                    os.close();
329:                }
330:
331:                TempBuffer head = ts.getHead();
332:                int offset = 0;
333:                for (; head != null; head = head.getNext()) {
334:                    byte[] buffer = head.getBuffer();
335:
336:                    int length = head.getLength();
337:
338:                    System.arraycopy(buffer, 0, tempBuffer, offset, length);
339:
340:                    for (; length < buffer.length; length++) {
341:                        tempBuffer[offset + length] = 0;
342:                    }
343:
344:                    offset += buffer.length;
345:                }
346:
347:                for (; offset < BLOCK_SIZE; offset++)
348:                    tempBuffer[offset] = 0;
349:
350:                writeBlock(BLOCK_SIZE, tempBuffer, 0, BLOCK_SIZE);
351:
352:                _database.addTable(this );
353:            }
354:
355:            /**
356:             * Initialize the indexes
357:             */
358:            private void initIndexes() throws IOException, SQLException {
359:                Column[] columns = _row.getColumns();
360:                for (int i = 0; i < columns.length; i++) {
361:                    Column column = columns[i];
362:
363:                    if (!column.isUnique())
364:                        continue;
365:
366:                    KeyCompare keyCompare = column.getIndexKeyCompare();
367:
368:                    if (keyCompare == null)
369:                        continue;
370:
371:                    Block rootBlock = allocateIndexBlock();
372:                    long rootBlockId = rootBlock.getBlockId();
373:                    rootBlock.free();
374:
375:                    BTree btree = new BTree(this , rootBlockId, column
376:                            .getLength(), keyCompare);
377:
378:                    column.setIndex(btree);
379:                }
380:            }
381:
382:            /**
383:             * Clears the indexes
384:             */
385:            private void clearIndexes() throws IOException {
386:                Column[] columns = _row.getColumns();
387:
388:                for (int i = 0; i < columns.length; i++) {
389:                    BTree index = columns[i].getIndex();
390:
391:                    if (index == null)
392:                        continue;
393:
394:                    long rootAddr = index.getIndexRoot();
395:
396:                    Block block = readBlock(addressToBlockId(rootAddr));
397:
398:                    try {
399:                        byte[] blockBuffer = block.getBuffer();
400:
401:                        synchronized (blockBuffer) {
402:                            for (int j = 0; j < blockBuffer.length; j++) {
403:                                blockBuffer[j] = 0;
404:                            }
405:
406:                            block.setDirty(0, BLOCK_SIZE);
407:                        }
408:                    } finally {
409:                        block.free();
410:                    }
411:                }
412:
413:                long blockAddr = 0;
414:
415:                while ((blockAddr = firstBlock(blockAddr + BLOCK_SIZE,
416:                        ALLOC_INDEX)) > 0) {
417:                    freeBlock(blockAddr);
418:                }
419:            }
420:
421:            /**
422:             * Rebuilds the indexes
423:             */
424:            private void rebuildIndexes() throws IOException, SQLException {
425:                Transaction xa = Transaction.create();
426:                xa.setAutoCommit(true);
427:
428:                try {
429:                    TableIterator iter = createTableIterator();
430:
431:                    iter.init(xa);
432:
433:                    Column[] columns = _row.getColumns();
434:
435:                    while (iter.nextBlock()) {
436:                        iter.initRow();
437:
438:                        byte[] blockBuffer = iter.getBuffer();
439:
440:                        while (iter.nextRow()) {
441:                            long rowAddress = iter.getRowAddress();
442:                            int rowOffset = iter.getRowOffset();
443:
444:                            for (int i = 0; i < columns.length; i++) {
445:                                Column column = columns[i];
446:
447:                                column.setIndex(xa, blockBuffer, rowOffset,
448:                                        rowAddress, null);
449:                            }
450:                        }
451:                    }
452:                } finally {
453:                    xa.commit();
454:                }
455:            }
456:
457:            private void writeTableHeader(WriteStream os) throws IOException {
458:                os.print(DB_VERSION);
459:                os.write(0);
460:
461:                while (os.getBufferOffset() < INDEX_ROOT_OFFSET)
462:                    os.write(0);
463:
464:                Column[] columns = _row.getColumns();
465:                for (int i = 0; i < columns.length; i++) {
466:                    if (!columns[i].isUnique())
467:                        continue;
468:
469:                    BTree index = columns[i].getIndex();
470:
471:                    if (index != null) {
472:                        writeLong(os, index.getIndexRoot());
473:                    } else {
474:                        writeLong(os, 0);
475:                    }
476:                }
477:
478:                while (os.getBufferOffset() < ROOT_DATA_END)
479:                    os.write(0);
480:
481:                os.print("CREATE TABLE " + getName() + "(");
482:                for (int i = 0; i < _row.getColumns().length; i++) {
483:                    Column column = _row.getColumns()[i];
484:
485:                    if (i != 0)
486:                        os.print(",");
487:
488:                    os.print(column.getName());
489:                    os.print(" ");
490:
491:                    switch (column.getTypeCode()) {
492:                    case Column.VARCHAR:
493:                        os
494:                                .print("VARCHAR(" + column.getDeclarationSize()
495:                                        + ")");
496:                        break;
497:                    case Column.VARBINARY:
498:                        os.print("VARBINARY(" + column.getDeclarationSize()
499:                                + ")");
500:                        break;
501:                    case Column.INT:
502:                        os.print("INTEGER");
503:                        break;
504:                    case Column.LONG:
505:                        os.print("BIGINT");
506:                        break;
507:                    case Column.DOUBLE:
508:                        os.print("DOUBLE");
509:                        break;
510:                    case Column.DATE:
511:                        os.print("TIMESTAMP");
512:                        break;
513:                    case Column.BLOB:
514:                        os.print("BLOB");
515:                        break;
516:                    case Column.NUMERIC: {
517:                        NumericColumn numeric = (NumericColumn) column;
518:
519:                        os.print("NUMERIC(" + numeric.getPrecision() + ","
520:                                + numeric.getScale() + ")");
521:                        break;
522:                    }
523:                    default:
524:                        throw new UnsupportedOperationException();
525:                    }
526:
527:                    if (column.isPrimaryKey())
528:                        os.print(" PRIMARY KEY");
529:                    else if (column.isUnique())
530:                        os.print(" UNIQUE");
531:
532:                    if (column.isNotNull())
533:                        os.print(" NOT NULL");
534:
535:                    Expr defaultExpr = column.getDefault();
536:
537:                    if (defaultExpr != null) {
538:                        os.print(" DEFAULT (");
539:                        os.print(defaultExpr);
540:                        os.print(")");
541:                    }
542:
543:                    if (column.getAutoIncrement() >= 0)
544:                        os.print(" auto_increment");
545:                }
546:                os.print(")");
547:
548:                /*
549:                writeLong(os, _blockMax);
550:                writeLong(os, _entries);
551:                writeLong(os, _clockAddr);
552:                 */
553:            }
554:
555:            public TableIterator createTableIterator() {
556:                assertStoreActive();
557:
558:                return new TableIterator(this );
559:            }
560:
561:            /**
562:             * Returns the next auto-increment value.
563:             */
564:            public long nextAutoIncrement(QueryContext context)
565:                    throws SQLException {
566:                synchronized (this ) {
567:                    if (_autoIncrementValue >= 0)
568:                        return ++_autoIncrementValue;
569:                }
570:
571:                long max = 0;
572:
573:                try {
574:                    TableIterator iter = createTableIterator();
575:                    iter.init(context);
576:                    while (iter.next()) {
577:                        byte[] buffer = iter.getBuffer();
578:
579:                        long value = _autoIncrementColumn.getLong(buffer, iter
580:                                .getRowOffset());
581:
582:                        if (max < value)
583:                            max = value;
584:                    }
585:                } catch (IOException e) {
586:                    throw new SQLExceptionWrapper(e);
587:                }
588:
589:                synchronized (this ) {
590:                    if (_autoIncrementValue < max)
591:                        _autoIncrementValue = max;
592:
593:                    return ++_autoIncrementValue;
594:                }
595:            }
596:
597:            /**
598:             * Inserts a new row, returning the row address.
599:             */
600:            public long insert(QueryContext queryContext, Transaction xa,
601:                    ArrayList<Column> columns, ArrayList<Expr> values)
602:                    throws IOException, SQLException {
603:                if (log.isLoggable(Level.FINEST))
604:                    log
605:                            .finest("db table " + getName() + " insert row xa:"
606:                                    + xa);
607:
608:                Block block = null;
609:
610:                try {
611:                    long addr;
612:                    int rowOffset = 0;
613:
614:                    boolean isLoop = false;
615:                    boolean hasRow = false;
616:
617:                    int rowClockCount = 0;
618:                    long rowClockAddr = 0;
619:                    long rowClockUsed = 0;
620:                    long rowClockTotal = 0;
621:
622:                    do {
623:                        long blockId = 0;
624:
625:                        if (block != null) {
626:                            block.free();
627:                            block = null;
628:                        }
629:
630:                        synchronized (_rowClockLock) {
631:                            blockId = firstRow(_rowClockAddr);
632:
633:                            if (blockId >= 0) {
634:                            } else if (!isLoop
635:                                    && (ROW_CLOCK_MIN < _rowClockTotal
636:                                            && 4 * _rowClockUsed < 3 * _rowClockTotal || _rowAllocCount > 8)) {
637:                                // System.out.println("LOOP: used:" + _rowClockUsed + " total:" + _rowClockTotal + " frac:" + (double) _rowClockUsed / (double) (_rowClockTotal + 0.01));
638:                                // go around loop if there are sufficient entries, i.e. over
639:                                // ROW_CLOCK_MIN and at least 1/4 free entries.
640:                                isLoop = true;
641:                                _rowClockCount = 0;
642:                                _rowClockAddr = 0;
643:                                _rowClockUsed = 0;
644:                                _rowClockTotal = 0;
645:                                _rowAllocCount = 0;
646:                                continue;
647:                            } else {
648:                                //System.out.println("ROW: used:" + _rowClockUsed + " total:" + _rowClockTotal + " frac:" + (double) _rowClockUsed / (double) (_rowClockTotal + 0.01));
649:
650:                                _rowAllocCount++;
651:
652:                                // if no free row is available, allocate a new one
653:                                block = xa.allocateRow(this );
654:                                //System.out.println("ALLOC: " + block);
655:
656:                                blockId = block.getBlockId();
657:                            }
658:
659:                            rowClockCount = _rowClockCount;
660:                            rowClockAddr = blockIdToAddress(blockId);
661:                            rowClockUsed = _rowClockUsed;
662:                            rowClockTotal = _rowClockTotal;
663:
664:                            // the next insert will try the following block
665:                            _rowClockCount++;
666:                            _rowClockAddr = rowClockAddr + BLOCK_SIZE;
667:                            _rowClockUsed = rowClockUsed + _rowsPerBlock;
668:                            _rowClockTotal = rowClockTotal + _rowsPerBlock;
669:                        }
670:
671:                        if (block == null)
672:                            block = xa.readBlock(this , blockId);
673:
674:                        Lock blockLock = block.getLock();
675:
676:                        if (xa.lockReadAndWriteNoWait(blockLock)) {
677:                            try {
678:                                rowOffset = 0;
679:
680:                                byte[] buffer = block.getBuffer();
681:
682:                                for (; rowOffset < _rowEnd; rowOffset += _rowLength) {
683:                                    if (buffer[rowOffset] == 0) {
684:                                        block
685:                                                .setDirty(rowOffset,
686:                                                        rowOffset + 1);
687:
688:                                        hasRow = true;
689:                                        buffer[rowOffset] = ROW_ALLOC;
690:                                        break;
691:                                    }
692:                                }
693:                            } finally {
694:                                xa.unlockReadAndWrite(blockLock);
695:                            }
696:                        }
697:                    } while (!hasRow);
698:
699:                    insertRow(queryContext, xa, columns, values, block,
700:                            rowOffset);
701:
702:                    synchronized (_rowClockLock) {
703:                        if (rowClockCount < _rowClockCount) {
704:                            // the next insert will retry this block
705:                            int blocks = _rowClockCount - rowClockCount;
706:
707:                            _rowClockCount = rowClockCount;
708:                            _rowClockAddr = rowClockAddr;
709:                            _rowClockUsed -= blocks * _rowsPerBlock;
710:                            _rowClockTotal -= blocks * _rowsPerBlock;
711:                        }
712:                    }
713:
714:                    return blockIdToAddress(block.getBlockId(), rowOffset);
715:                } finally {
716:                    if (block != null)
717:                        block.free();
718:                }
719:            }
720:
721:            public void insertRow(QueryContext queryContext, Transaction xa,
722:                    ArrayList<Column> columns, ArrayList<Expr> values,
723:                    Block block, int rowOffset) throws SQLException {
724:                byte[] buffer = block.getBuffer();
725:
726:                long rowAddr = blockIdToAddress(block.getBlockId(), rowOffset);
727:                //System.out.println("ADDR:" + rowAddr + " " + rowOffset + " " + block);
728:
729:                TableIterator iter = createTableIterator();
730:                TableIterator[] iterSet = new TableIterator[] { iter };
731:                // QueryContext context = QueryContext.allocate();
732:                queryContext.init(xa, iterSet, true);
733:                iter.init(queryContext);
734:
735:                boolean isOkay = false;
736:                queryContext.lock();
737:                try {
738:                    iter.setRow(block, rowOffset);
739:
740:                    block.setDirty(rowOffset, rowOffset + _rowLength);
741:
742:                    for (int i = rowOffset + _rowLength - 1; rowOffset < i; i--)
743:                        buffer[i] = 0;
744:
745:                    for (int i = 0; i < columns.size(); i++) {
746:                        Column column = columns.get(i);
747:                        Expr value = values.get(i);
748:
749:                        column.setExpr(xa, buffer, rowOffset, value,
750:                                queryContext);
751:                    }
752:
753:                    // lock for insert, i.e. entries, indices, and validation
754:                    // XXX: the set index needs to handle the validation
755:                    //xa.lockWrite(_insertLock);
756:                    try {
757:                        validate(block, rowOffset, queryContext, xa);
758:
759:                        buffer[rowOffset] = (byte) ((buffer[rowOffset] & ~ROW_MASK) | ROW_VALID);
760:
761:                        for (int i = 0; i < columns.size(); i++) {
762:                            Column column = columns.get(i);
763:                            Expr value = values.get(i);
764:
765:                            column.setIndex(xa, buffer, rowOffset, rowAddr,
766:                                    queryContext);
767:                        }
768:
769:                        xa.addUpdateBlock(block);
770:
771:                        if (_autoIncrementColumn != null) {
772:                            long value = _autoIncrementColumn.getLong(buffer,
773:                                    rowOffset);
774:
775:                            synchronized (this ) {
776:                                if (_autoIncrementValue < value)
777:                                    _autoIncrementValue = value;
778:                            }
779:                        }
780:
781:                        _entries++;
782:
783:                        isOkay = true;
784:                    } finally {
785:                        // xa.unlockWrite(_insertLock);
786:
787:                        if (!isOkay)
788:                            delete(xa, block, buffer, rowOffset);
789:                    }
790:                } finally {
791:                    queryContext.unlock();
792:                }
793:            }
794:
795:            /**
796:             * Validates the given row.
797:             */
798:            private void validate(Block block, int rowOffset,
799:                    QueryContext queryContext, Transaction xa)
800:                    throws SQLException {
801:                TableIterator row = createTableIterator();
802:                TableIterator[] rows = new TableIterator[] { row };
803:
804:                row.setRow(block, rowOffset);
805:
806:                for (int i = 0; i < _constraints.length; i++) {
807:                    _constraints[i].validate(rows, queryContext, xa);
808:                }
809:            }
810:
811:            void delete(Transaction xa, Block block, byte[] buffer,
812:                    int rowOffset) throws SQLException {
813:                byte rowState = buffer[rowOffset];
814:
815:                if ((rowState & ROW_MASK) != ROW_VALID)
816:                    return;
817:
818:                buffer[rowOffset] = (byte) ((rowState & ~ROW_MASK) | ROW_ALLOC);
819:
820:                Column[] columns = _row.getColumns();
821:
822:                for (int i = 0; i < columns.length; i++) {
823:                    columns[i].delete(xa, buffer, rowOffset);
824:                }
825:
826:                buffer[rowOffset] = 0;
827:
828:                synchronized (_rowClockLock) {
829:                    long addr = blockIdToAddress(block.getBlockId());
830:
831:                    if (addr <= _rowClockAddr) {
832:                        _rowClockUsed--;
833:                    }
834:                }
835:            }
836:
837:            private void writeLong(WriteStream os, long value)
838:                    throws IOException {
839:                os.write((int) (value >> 56));
840:                os.write((int) (value >> 48));
841:                os.write((int) (value >> 40));
842:                os.write((int) (value >> 32));
843:                os.write((int) (value >> 24));
844:                os.write((int) (value >> 16));
845:                os.write((int) (value >> 8));
846:                os.write((int) value);
847:            }
848:
849:            private void setLong(byte[] buffer, int offset, long value)
850:                    throws IOException {
851:                buffer[offset + 0] = (byte) (value >> 56);
852:                buffer[offset + 1] = (byte) (value >> 48);
853:                buffer[offset + 2] = (byte) (value >> 40);
854:                buffer[offset + 3] = (byte) (value >> 32);
855:                buffer[offset + 4] = (byte) (value >> 24);
856:                buffer[offset + 5] = (byte) (value >> 16);
857:                buffer[offset + 6] = (byte) (value >> 8);
858:                buffer[offset + 7] = (byte) (value);
859:            }
860:
861:            private long getLong(byte[] buffer, int offset) throws IOException {
862:                long value = (((buffer[offset + 0] & 0xffL) << 56)
863:                        + ((buffer[offset + 1] & 0xffL) << 48)
864:                        + ((buffer[offset + 2] & 0xffL) << 40)
865:                        + ((buffer[offset + 3] & 0xffL) << 32) +
866:
867:                        ((buffer[offset + 4] & 0xffL) << 24)
868:                        + ((buffer[offset + 5] & 0xffL) << 16)
869:                        + ((buffer[offset + 6] & 0xffL) << 8) + ((buffer[offset + 7] & 0xffL)));
870:
871:                return value;
872:            }
873:
874:            public String toString() {
875:                return "Table[" + getName() + ":" + getId() + "]";
876:            }
877:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.