Source Code Cross Referenced for BasePage.java in  » Database-DBMS » db-derby-10.2 » org » apache » derby » impl » store » raw » data » Java Source Code / Java DocumentationJava Source Code and Java Documentation

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


0001:        /*
0002:
0003:           Derby - Class org.apache.derby.impl.store.raw.data.BasePage
0004:
0005:           Licensed to the Apache Software Foundation (ASF) under one or more
0006:           contributor license agreements.  See the NOTICE file distributed with
0007:           this work for additional information regarding copyright ownership.
0008:           The ASF licenses this file to you under the Apache License, Version 2.0
0009:           (the "License"); you may not use this file except in compliance with
0010:           the License.  You may obtain a copy of the License at
0011:
0012:              http://www.apache.org/licenses/LICENSE-2.0
0013:
0014:           Unless required by applicable law or agreed to in writing, software
0015:           distributed under the License is distributed on an "AS IS" BASIS,
0016:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017:           See the License for the specific language governing permissions and
0018:           limitations under the License.
0019:
0020:         */
0021:
0022:        package org.apache.derby.impl.store.raw.data;
0023:
0024:        import org.apache.derby.iapi.reference.SQLState;
0025:
0026:        import org.apache.derby.iapi.services.io.FormatableBitSet;
0027:        import org.apache.derby.iapi.services.io.DynamicByteArrayOutputStream;
0028:        import org.apache.derby.iapi.services.io.DynamicByteArrayOutputStream;
0029:
0030:        import org.apache.derby.iapi.services.locks.C_LockFactory;
0031:        import org.apache.derby.iapi.services.locks.Lockable;
0032:        import org.apache.derby.iapi.services.locks.Latch;
0033:        import org.apache.derby.iapi.services.locks.VirtualLockTable;
0034:
0035:        import org.apache.derby.iapi.services.sanity.SanityManager;
0036:
0037:        import org.apache.derby.iapi.services.io.LimitObjectInput;
0038:        import org.apache.derby.iapi.services.io.TypedFormat;
0039:
0040:        import org.apache.derby.iapi.error.StandardException;
0041:
0042:        import org.apache.derby.iapi.store.raw.AuxObject;
0043:        import org.apache.derby.iapi.store.raw.ContainerHandle;
0044:        import org.apache.derby.iapi.store.raw.ContainerKey;
0045:        import org.apache.derby.iapi.store.raw.FetchDescriptor;
0046:        import org.apache.derby.iapi.store.raw.Page;
0047:        import org.apache.derby.iapi.store.raw.PageKey;
0048:        import org.apache.derby.iapi.store.raw.RecordHandle;
0049:        import org.apache.derby.iapi.store.raw.RawStoreFactory;
0050:        import org.apache.derby.iapi.store.raw.xact.RawTransaction;
0051:        import org.apache.derby.iapi.store.raw.log.LogInstant;
0052:
0053:        import org.apache.derby.iapi.store.access.Qualifier;
0054:        import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo;
0055:
0056:        import org.apache.derby.iapi.types.DataValueDescriptor;
0057:
0058:        import java.io.IOException;
0059:        import java.io.OutputStream;
0060:        import java.io.ObjectInput;
0061:
0062:        import java.util.Hashtable;
0063:        import java.util.Observer;
0064:        import java.util.Observable;
0065:
0066:        /**
0067:
0068:         This class implements all the the generic locking behaviour for a Page.
0069:         It leaves method used to log and store the records up to sub-classes.
0070:         It is intended that the object can represent multiple pages from different
0071:         containers during its lifetime.
0072:         <P>
0073:         A page contains a set of records, which can be accessed by "slot",
0074:         which defines the order of the records on the page, or by "id" which
0075:         defines the identity of the records on the page.  Clients access
0076:         records by both slot and id, depending on their needs.
0077:         <P>
0078:         BasePage implements Observer to watch the ContainerHandle which notifies
0079:         its Observers when it is closing.
0080:
0081:         <BR>
0082:         MT - mutable
0083:
0084:         **/
0085:
0086:        public abstract class BasePage implements  Page, Lockable, Observer,
0087:                TypedFormat {
0088:
0089:            /**
0090:            	auxiliary object
0091:
0092:            	MT - mutable - content dynamic : single thread required. This reference is
0093:            	set while the page is latched and returned to callers of page while the page is latched.
0094:            	For correct MT behaviour it is assumed that the caller discards any reference to an
0095:            	auxiliary object once the page is unlatched. The reference mya be cleared while
0096:            	the page is latched, or while the page is being cleaned from the cache. In the latter
0097:            	case the cache manager ensures that only a single thread can access this object.		
0098:             */
0099:            private AuxObject auxObj;
0100:
0101:            /**
0102:            	this page's identity
0103:            	<BR>
0104:            	MT - immutable - content dynamic : single thread required
0105:             */
0106:            protected PageKey identity;
0107:
0108:            /**
0109:            	In-memory slot table, array of StoredRecordHeaders.
0110:            	<BR>
0111:            	MT - Immutable - Content Dynamic : Single thread required.
0112:             */
0113:            private StoredRecordHeader[] headers; // in memory slot table
0114:
0115:            private int recordCount;
0116:
0117:            /**
0118:            	Page owner during exclusive access.
0119:
0120:            	MT - mutable : single thread required, provided by Lockable single thread required. 
0121:             */
0122:            protected BaseContainerHandle owner;
0123:
0124:            /**
0125:            	Count of times a latch is held nested during an abort
0126:             */
0127:            private int nestedLatch;
0128:
0129:            /**
0130:            	LockManager held latch during exclusive access.
0131:            	When this is not null, latch.getQualifier() == owner
0132:             */
0133:            private Latch myLatch;
0134:
0135:            protected boolean inClean; // is the page being cleaned
0136:
0137:            /**
0138:             * Used to determine latch state of a page.
0139:             *
0140:             * MT - mutable
0141:             *
0142:             * There are 3 latch states for a page:
0143:             *
0144:             * UNLATCHED - (owner == null) 
0145:             * PRELATCH  - (owner != null) && preLatch
0146:             * LATCHED   - (owner != null) && !preLatch
0147:             *
0148:             * A page may be "cleaned" while it is either UNLATCHED, or PRELATCH, but
0149:             * it must wait for it to be not LATCHED.
0150:             *
0151:             * A page may move from UNLATCHED to PRELATCH, while being cleaned.
0152:             * A page must wait for !inClean before it can move from PRELATCH to 
0153:             * LATCHED.
0154:             **/
0155:            protected boolean preLatch;
0156:
0157:            /**
0158:            	Instant of last log record that updated this page.
0159:
0160:            	<BR> MT - mutable : latched
0161:             */
0162:            private LogInstant lastLog;
0163:
0164:            /**
0165:            	Version of the page.
0166:
0167:            	<BR> MT - mutable : single thread required - The page must be latched to access
0168:            	this variable or the page muts be in the noidentiy state.
0169:             */
0170:            private long pageVersion = 0; // version of the page
0171:
0172:            /**
0173:            	Status of the page
0174:             */
0175:            private byte pageStatus;
0176:
0177:            /**
0178:            	Values for pageStatus flag 
0179:
0180:            	page goes thru the following transition:
0181:            	VALID_PAGE <-> deallocated page -> free page <-> VALID_PAGE
0182:
0183:            	deallocated and free page are both INVALID_PAGE as far as BasePage is concerned.
0184:            	When a page is deallocated, it transitioned from VALID to INVALID.
0185:            	When a page is allocated, it trnasitioned from INVALID to VALID.
0186:
0187:             */
0188:            public static final byte VALID_PAGE = 1;
0189:            public static final byte INVALID_PAGE = 2;
0190:
0191:            /**
0192:            	Init page flag.
0193:
0194:            	INIT_PAGE_REUSE - set if page is being initialized for reuse
0195:            	INIT_PAGE_OVERFLOW - set if page will be an overflow page
0196:            	INIT_PAGE_REUSE_RECORDID - set if page is being reused and its record
0197:            					id can be reset to RecordHandle.FIRST_RECORD_ID, rather
0198:            					to 1+ next recordId on the page
0199:             */
0200:            public static final int INIT_PAGE_REUSE = 0x1;
0201:            public static final int INIT_PAGE_OVERFLOW = 0x2;
0202:            public static final int INIT_PAGE_REUSE_RECORDID = 0x4;
0203:
0204:            /**
0205:            	Log Record flag.  Why the before image of this record is being logged
0206:
0207:            	LOG_RECORD_FOR_UPDATE - set if the record is being logged for update.
0208:            	LOG_RECORD_DEFAULT - for non update.
0209:            	LOG_RECORD_FOR_PURGE - set if the record is being logged for purges 
0210:            	                       and no data required to ve logged.
0211:            	The other cases (copy, purge, delete), we don't need to distinguish,
0212:            	leave no bit set. 
0213:             */
0214:            public static final int LOG_RECORD_DEFAULT = 0x0;
0215:            public static final int LOG_RECORD_FOR_UPDATE = 0x1;
0216:            public static final int LOG_RECORD_FOR_PURGE = 0x2;
0217:
0218:            /**
0219:             ** Create a new, empty page.
0220:             **/
0221:
0222:            protected BasePage() {
0223:
0224:            }
0225:
0226:            /**
0227:                Initialized the BasePage.
0228:                <p>
0229:            	Initialize the object, ie. perform work normally perfomed in 
0230:                constructor.  Called by setIdentity() and createIdentity().
0231:             */
0232:            protected void initialize() {
0233:                setAuxObject(null);
0234:                identity = null;
0235:                recordCount = 0;
0236:                clearLastLogInstant();
0237:
0238:                if (SanityManager.DEBUG) {
0239:                    if (nestedLatch != 0)
0240:                        SanityManager
0241:                                .THROWASSERT("nestedLatch is non-zero in initialize - value =  "
0242:                                        + nestedLatch);
0243:                    if (inClean)
0244:                        SanityManager
0245:                                .THROWASSERT("inClean is true in initialize");
0246:                    if (preLatch)
0247:                        SanityManager
0248:                                .THROWASSERT("preLatch is true in initialize");
0249:                }
0250:
0251:            }
0252:
0253:            /**
0254:            	Must be called by a sub-class before calling setHeaderAtSlot.
0255:
0256:             */
0257:            protected void initializeHeaders(int numRecords) {
0258:
0259:                if (SanityManager.DEBUG) {
0260:                    if (recordCount != 0)
0261:                        SanityManager.THROWASSERT("record count = "
0262:                                + recordCount
0263:                                + " before initSlotTable is called");
0264:                }
0265:
0266:                headers = new StoredRecordHeader[numRecords];
0267:            }
0268:
0269:            /*
0270:             ** Cacheable methods
0271:             */
0272:
0273:            protected void fillInIdentity(PageKey key) {
0274:                if (SanityManager.DEBUG) {
0275:                    SanityManager.ASSERT(identity == null);
0276:                }
0277:
0278:                identity = key;
0279:            }
0280:
0281:            public void clearIdentity() {
0282:
0283:                if (SanityManager.DEBUG) {
0284:                    SanityManager.ASSERT(!isLatched());
0285:                }
0286:
0287:                identity = null;
0288:
0289:                cleanPageForReuse();
0290:            }
0291:
0292:            /**
0293:            	Initialized this page for reuse or first use
0294:             */
0295:            protected void cleanPageForReuse() {
0296:                setAuxObject(null);
0297:                recordCount = 0;
0298:            }
0299:
0300:            /**	
0301:            	OK to hand object outside to cache.. 
0302:             */
0303:            public Object getIdentity() {
0304:                return identity;
0305:            }
0306:
0307:            /*
0308:             ** Methods of Page
0309:             */
0310:
0311:            private static final RecordHandle InvalidRecordHandle = new RecordId(
0312:                    new PageKey(new ContainerKey(0, 0),
0313:                            ContainerHandle.INVALID_PAGE_NUMBER),
0314:                    RecordHandle.INVALID_RECORD_HANDLE);
0315:
0316:            public final RecordHandle getInvalidRecordHandle() {
0317:                // a static invalid record handle
0318:                return InvalidRecordHandle;
0319:            }
0320:
0321:            public static final RecordHandle MakeRecordHandle(PageKey pkey,
0322:                    int recordHandleConstant) throws StandardException {
0323:                if (recordHandleConstant >= RecordHandle.FIRST_RECORD_ID) {
0324:                    throw StandardException.newException(
0325:                            SQLState.DATA_CANNOT_MAKE_RECORD_HANDLE, new Long(
0326:                                    recordHandleConstant));
0327:                }
0328:
0329:                return new RecordId(pkey, recordHandleConstant);
0330:            }
0331:
0332:            public final RecordHandle makeRecordHandle(int recordHandleConstant)
0333:                    throws StandardException {
0334:                return MakeRecordHandle(getPageId(), recordHandleConstant);
0335:            }
0336:
0337:            /** @see Page#getPageNumber */
0338:            public final long getPageNumber() {
0339:                if (SanityManager.DEBUG) {
0340:                    SanityManager.ASSERT(isLatched(), "page is not latched.");
0341:                    SanityManager.ASSERT(identity != null, "identity is null.");
0342:                }
0343:
0344:                return identity.getPageNumber();
0345:            }
0346:
0347:            public final RecordHandle getRecordHandle(int recordId) {
0348:                if (SanityManager.DEBUG) {
0349:                    SanityManager.ASSERT(isLatched());
0350:                }
0351:
0352:                int slot = findRecordById(recordId, FIRST_SLOT_NUMBER);
0353:                if (slot < 0)
0354:                    return null;
0355:
0356:                return getRecordHandleAtSlot(slot);
0357:            }
0358:
0359:            public final RecordHandle getRecordHandleAtSlot(int slot) {
0360:                return getHeaderAtSlot(slot).getHandle(getPageId(), slot);
0361:            }
0362:
0363:            /**
0364:              @see Page#recordExists
0365:              @exception StandardException recordHandle is not a valid record handle
0366:             */
0367:            public final boolean recordExists(RecordHandle handle,
0368:                    boolean ignoreDelete) throws StandardException {
0369:                if (SanityManager.DEBUG) {
0370:                    SanityManager.ASSERT(isLatched());
0371:                }
0372:
0373:                if (handle.getId() < RecordHandle.FIRST_RECORD_ID) {
0374:                    throw StandardException.newException(
0375:                            SQLState.DATA_INVALID_RECORD_HANDLE, handle);
0376:                }
0377:
0378:                if (handle.getPageNumber() != getPageNumber())
0379:                    return false;
0380:
0381:                int slot = findRecordById(handle.getId(), handle
0382:                        .getSlotNumberHint());
0383:                return (slot >= FIRST_SLOT_NUMBER && (ignoreDelete || !isDeletedAtSlot(slot)));
0384:            }
0385:
0386:            /**
0387:            	<OL>
0388:            	<LI>Lock the record (according to the locking policy)
0389:            	<LI>If the record is deleted then return null. We must check after we hold the lock to
0390:            	ensure that we don't look at the delete status of an uncommitted record.
0391:            	<LI>Fetch the record
0392:            	<LI>Unlock the record (according to the locking policy)
0393:            	</OL>
0394:
0395:            	@see Page#fetch
0396:
0397:            	@exception StandardException messageId equals StandardException.newException(SQLState.RECORD_VANISHED
0398:            	If the record identfied by handle does not exist on this page.
0399:
0400:            	@exception StandardException	Standard Cloudscape error policy
0401:            	@exception StandardException   record is not on page with message id equal to
0402:            		StandardException.newException(SQLState.RECORD_VANISHED.
0403:             */
0404:
0405:            public RecordHandle fetch(RecordHandle handle, Object[] row,
0406:                    FormatableBitSet validColumns, boolean forUpdate)
0407:                    throws StandardException {
0408:
0409:                if (SanityManager.DEBUG) {
0410:                    SanityManager.ASSERT(isLatched());
0411:                }
0412:
0413:                owner.getLockingPolicy().lockRecordForRead(myLatch, handle,
0414:                        forUpdate);
0415:
0416:                // See if the record is deleted or not.
0417:                int slot = getSlotNumber(handle);
0418:
0419:                StoredRecordHeader recordHeader = getHeaderAtSlot(slot);
0420:
0421:                if (recordHeader.isDeleted())
0422:                    return null;
0423:
0424:                FetchDescriptor hack_fetch = new FetchDescriptor(row.length,
0425:                        validColumns, (Qualifier[][]) null);
0426:
0427:                // magic to copy rows across ...
0428:                restoreRecordFromSlot(slot, row, hack_fetch, handle,
0429:                        recordHeader, true);
0430:
0431:                owner.getLockingPolicy().unlockRecordAfterRead(
0432:                        owner.getTransaction(), owner, handle, forUpdate, true);
0433:
0434:                return handle;
0435:            }
0436:
0437:            public RecordHandle fetchFromSlot(RecordHandle rh, int slot,
0438:                    Object[] row, FetchDescriptor fetchDesc,
0439:                    boolean ignoreDelete) throws StandardException {
0440:                if (SanityManager.DEBUG) {
0441:                    SanityManager.ASSERT(isLatched());
0442:
0443:                    if (rh != null)
0444:                        SanityManager.ASSERT(getSlotNumber(rh) == slot);
0445:                }
0446:
0447:                checkSlotOnPage(slot);
0448:
0449:                StoredRecordHeader recordHeader = getHeaderAtSlot(slot);
0450:
0451:                if (rh == null)
0452:                    rh = recordHeader.getHandle(getPageId(), slot);
0453:
0454:                if (!ignoreDelete && recordHeader.isDeleted())
0455:                    return null;
0456:
0457:                /*
0458:                SanityManager.DEBUG_PRINT("fetchFromSlot", "before.");
0459:                SanityManager.showTrace(new Throwable());
0460:                SanityManager.DEBUG_PRINT("fetchFromSlot", "fetchDesc = " + fetchDesc);
0461:
0462:                if (fetchDesc != null)
0463:                {
0464:                    SanityManager.DEBUG_PRINT("fetchFromSlot", 
0465:                        ";fetchDesc.getMaxFetchColumnId() = " + 
0466:                            fetchDesc.getMaxFetchColumnId() +
0467:                        ";fetchDesc.getValidColumns() = " + 
0468:                            fetchDesc.getValidColumns() +
0469:                        ";fetchDesc.getQualifierList() = " + 
0470:                            fetchDesc.getQualifierList()
0471:                    );
0472:                }
0473:                 */
0474:
0475:                return (restoreRecordFromSlot(slot, row, fetchDesc, rh,
0476:                        recordHeader, true) ? rh : null);
0477:            }
0478:
0479:            /**
0480:            	@exception StandardException	Standard Cloudscape error policy
0481:            	@see Page#fetchFieldFromSlot
0482:             */
0483:            public final RecordHandle fetchFieldFromSlot(int slot, int fieldId,
0484:                    Object column) throws StandardException {
0485:                // need to allocate row with fieldId cols because of sparse row change
0486:                // needs to be RESOLVED
0487:                Object[] row = new Object[fieldId + 1];
0488:                row[fieldId] = column;
0489:                FormatableBitSet singleColumn = new FormatableBitSet(
0490:                        fieldId + 1);
0491:
0492:                singleColumn.set(fieldId);
0493:
0494:                FetchDescriptor fetchDesc = new FetchDescriptor(fieldId + 1,
0495:                        singleColumn, (Qualifier[][]) null);
0496:
0497:                return (fetchFromSlot(null, slot, row, fetchDesc, true));
0498:            }
0499:
0500:            /** 
0501:            	@exception StandardException Record does not exist on this page.
0502:
0503:                @see Page#getSlotNumber
0504:             */
0505:            public final int getSlotNumber(RecordHandle handle)
0506:                    throws StandardException {
0507:                if (SanityManager.DEBUG) {
0508:                    SanityManager.ASSERT(isLatched());
0509:                }
0510:
0511:                int slot = findRecordById(handle.getId(), handle
0512:                        .getSlotNumberHint());
0513:
0514:                if (slot < 0) {
0515:                    throw StandardException.newException(
0516:                            SQLState.RAWSTORE_RECORD_VANISHED, handle);
0517:                }
0518:
0519:                return slot;
0520:            }
0521:
0522:            /** 
0523:            	@exception StandardException Record does not exist on this page.
0524:
0525:                @see Page#getNextSlotNumber
0526:             */
0527:            public final int getNextSlotNumber(RecordHandle handle)
0528:                    throws StandardException {
0529:                if (SanityManager.DEBUG) {
0530:                    SanityManager.ASSERT(isLatched());
0531:                }
0532:
0533:                int slot = findNextRecordById(handle.getId());
0534:
0535:                return slot;
0536:            }
0537:
0538:            /** @see Page#insertAtSlot
0539:            	@exception StandardException	Standard Cloudscape error policy
0540:             */
0541:            public RecordHandle insertAtSlot(int slot, Object[] row,
0542:                    FormatableBitSet validColumns, LogicalUndo undo,
0543:                    byte insertFlag, int overflowThreshold)
0544:                    throws StandardException {
0545:                if (SanityManager.DEBUG) {
0546:                    if (overflowThreshold == 0)
0547:                        SanityManager
0548:                                .THROWASSERT("overflowThreshold cannot be 0");
0549:                }
0550:
0551:                if ((insertFlag & Page.INSERT_DEFAULT) == Page.INSERT_DEFAULT) {
0552:                    return (insertNoOverflow(slot, row, validColumns, undo,
0553:                            insertFlag, overflowThreshold));
0554:                } else {
0555:                    if (SanityManager.DEBUG) {
0556:                        if (undo != null)
0557:                            SanityManager
0558:                                    .THROWASSERT("logical undo with overflow allowed on insert "
0559:                                            + undo.toString());
0560:                    }
0561:                    return (insertAllowOverflow(slot, row, validColumns, 0,
0562:                            insertFlag, overflowThreshold, (RecordHandle) null));
0563:                }
0564:            }
0565:
0566:            protected RecordHandle insertNoOverflow(int slot, Object[] row,
0567:                    FormatableBitSet validColumns, LogicalUndo undo,
0568:                    byte insertFlag, int overflowThreshold)
0569:                    throws StandardException {
0570:
0571:                if (SanityManager.DEBUG) {
0572:                    SanityManager.ASSERT(isLatched());
0573:                }
0574:
0575:                if (!owner.updateOK()) {
0576:                    throw StandardException
0577:                            .newException(SQLState.DATA_CONTAINER_READ_ONLY);
0578:                }
0579:
0580:                if (slot < FIRST_SLOT_NUMBER || slot > recordCount) {
0581:                    throw StandardException
0582:                            .newException(SQLState.DATA_SLOT_NOT_ON_PAGE);
0583:                }
0584:
0585:                if (!allowInsert())
0586:                    return null;
0587:
0588:                RawTransaction t = owner.getTransaction();
0589:
0590:                // logical operations not allowed in internal transactions.
0591:                if (undo != null) {
0592:                    t.checkLogicalOperationOk();
0593:                }
0594:
0595:                int recordId;
0596:                RecordHandle handle;
0597:
0598:                do {
0599:
0600:                    // loop until we get a new record id we can get a lock on.
0601:
0602:                    // If we can't get the lock without waiting then assume the record
0603:                    // id is owned by another xact.  The current heap overflow 
0604:                    // algorithm makes this likely, as it first try's to insert a row
0605:                    // telling raw store to fail if it doesn't fit on the page getting
0606:                    // a lock on an id that never makes it to disk.   The inserting
0607:                    // transaction will hold a lock on this "unused" record id until
0608:                    // it commits.  The page can leave the cache at this point, and
0609:                    // the inserting transaction has not dirtied the page (it failed
0610:                    // after getting the lock but before logging anything), another
0611:                    // inserting transaction will then get the same id as the 
0612:                    // previous inserter - thus the loop on lock waits.
0613:                    //
0614:                    // The lock we request indicates that this is a lock for insert,
0615:                    // which the locking policy may use to perform locking concurrency
0616:                    // optimizations.
0617:
0618:                    recordId = newRecordIdAndBump();
0619:                    handle = new RecordId(getPageId(), recordId, slot);
0620:
0621:                } while (!owner
0622:                        .getLockingPolicy()
0623:                        .lockRecordForWrite(t, handle,
0624:                                true /* lock is for insert */, false /* don't wait for grant */));
0625:
0626:                owner.getActionSet().actionInsert(t, this , slot, recordId, row,
0627:                        validColumns, undo, insertFlag, 0, false, -1,
0628:                        (DynamicByteArrayOutputStream) null, -1,
0629:                        overflowThreshold);
0630:
0631:                // at this point the insert has been logged and made on the physical 
0632:                // page the in-memory manipulation of the slot table is also performed
0633:                // by the PageActions object that implements actionInsert.
0634:
0635:                return handle;
0636:            }
0637:
0638:            /** @see Page#insert
0639:            	@exception StandardException	Standard Cloudscape error policy
0640:             */
0641:            public final RecordHandle insert(Object[] row,
0642:                    FormatableBitSet validColumns, byte insertFlag,
0643:                    int overflowThreshold) throws StandardException {
0644:
0645:                if (SanityManager.DEBUG) {
0646:                    if (overflowThreshold == 0)
0647:                        SanityManager
0648:                                .THROWASSERT("overflowThreshold much be greater than 0");
0649:                }
0650:
0651:                if (((insertFlag & Page.INSERT_DEFAULT) == Page.INSERT_DEFAULT)) {
0652:                    return (insertAtSlot(recordCount, row, validColumns,
0653:                            (LogicalUndo) null, insertFlag, overflowThreshold));
0654:                } else {
0655:                    return (insertAllowOverflow(recordCount, row, validColumns,
0656:                            0, insertFlag, overflowThreshold,
0657:                            (RecordHandle) null));
0658:                }
0659:            }
0660:
0661:            /**
0662:            	Insert a row allowing overflow.
0663:
0664:            	If handle is supplied then the record at that hanlde will be updated
0665:            	to indicate it is a partial row and it has an overflow portion.
0666:
0667:            	@exception StandardException	Standard Cloudscape error policy
0668:             */
0669:            public RecordHandle insertAllowOverflow(int slot, Object[] row,
0670:                    FormatableBitSet validColumns, int startColumn,
0671:                    byte insertFlag, int overflowThreshold,
0672:                    RecordHandle nextPortionHandle) throws StandardException {
0673:
0674:                BasePage curPage = this ;
0675:
0676:                if (!curPage.owner.updateOK()) {
0677:                    throw StandardException
0678:                            .newException(SQLState.DATA_CONTAINER_READ_ONLY);
0679:                }
0680:
0681:                // Handle of the first portion of the chain
0682:                RecordHandle headHandle = null;
0683:                RecordHandle handleToUpdate = null;
0684:
0685:                RawTransaction t = curPage.owner.getTransaction();
0686:
0687:                for (;;) {
0688:
0689:                    if (SanityManager.DEBUG) {
0690:                        SanityManager.ASSERT(curPage.isLatched());
0691:                    }
0692:
0693:                    if (!curPage.allowInsert())
0694:                        return null;
0695:
0696:                    // 'this' is the head page
0697:                    if (curPage != this )
0698:                        slot = curPage.recordCount;
0699:
0700:                    boolean isLongColumns = false;
0701:                    int realStartColumn = -1;
0702:                    int realSpaceOnPage = -1;
0703:
0704:                    DynamicByteArrayOutputStream logBuffer = null;
0705:
0706:                    // allocate new record id and handle
0707:                    int recordId = curPage.newRecordIdAndBump();
0708:                    RecordHandle handle = new RecordId(curPage.getPageId(),
0709:                            recordId, slot);
0710:
0711:                    if (curPage == this ) {
0712:
0713:                        // Lock the row, if it is the very first portion of the record.
0714:                        if (handleToUpdate == null) {
0715:
0716:                            while (!owner.getLockingPolicy()
0717:                                    .lockRecordForWrite(t, handle,
0718:                                            true /* lock is for insert */,
0719:                                            false /* don't wait for grant */)) {
0720:
0721:                                // loop until we get a new record id we can get a lock 
0722:                                // on.  If we can't get the lock without waiting then 
0723:                                // assume the record id is owned by another xact.  The 
0724:                                // current heap overflow algorithm makes this likely, 
0725:                                // as it first try's to insert a row telling raw store
0726:                                // to fail if it doesn't fit on the page getting a lock
0727:                                // on an id that never makes it to disk.   The 
0728:                                // inserting transaction will hold a lock on this
0729:                                // "unused" record id until it commits.  The page can 
0730:                                // leave the cache at this point, and the inserting 
0731:                                // transaction has not dirtied the page (it failed
0732:                                // after getting the lock but before logging anything),
0733:                                // another inserting transaction will then get the 
0734:                                // same id as the previous inserter - thus the loop on
0735:                                // lock waits.
0736:                                //
0737:                                // The lock we request indicates that this is a lock 
0738:                                // for insert, which the locking policy may use to 
0739:                                // perform locking concurrency optimizations.
0740:
0741:                                // allocate new record id and handle
0742:                                recordId = curPage.newRecordIdAndBump();
0743:                                handle = new RecordId(curPage.getPageId(),
0744:                                        recordId, slot);
0745:                            }
0746:                        }
0747:
0748:                        headHandle = handle;
0749:                    }
0750:
0751:                    do {
0752:
0753:                        // do this loop at least once.  If we caught a long Column,
0754:                        // then, we redo the insert with saved logBuffer.
0755:                        try {
0756:
0757:                            startColumn = owner.getActionSet().actionInsert(t,
0758:                                    curPage, slot, recordId, row, validColumns,
0759:                                    (LogicalUndo) null, insertFlag,
0760:                                    startColumn, false, realStartColumn,
0761:                                    logBuffer, realSpaceOnPage,
0762:                                    overflowThreshold);
0763:                            isLongColumns = false;
0764:
0765:                        } catch (LongColumnException lce) {
0766:
0767:                            // we caught a long column exception
0768:                            // three things should happen here:
0769:                            // 1. insert the long column into overflow pages.
0770:                            // 2. append the overflow field header in the main chain.
0771:                            // 3. continue the insert in the main data chain.
0772:                            logBuffer = new DynamicByteArrayOutputStream(lce
0773:                                    .getLogBuffer());
0774:
0775:                            // step 1: insert the long column ... use the same
0776:                            // insertFlag as the rest of the row.
0777:                            RecordHandle longColumnHandle = insertLongColumn(
0778:                                    curPage, lce, insertFlag);
0779:
0780:                            // step 2: append the overflow field header to the log buffer
0781:                            int overflowFieldLen = 0;
0782:                            try {
0783:                                overflowFieldLen += appendOverflowFieldHeader(
0784:                                        (DynamicByteArrayOutputStream) logBuffer,
0785:                                        longColumnHandle);
0786:                            } catch (IOException ioe) {
0787:                                // YYZ: revisit...  ioexception, insert failed...
0788:                                return null;
0789:                            }
0790:
0791:                            // step 3: continue the insert in the main data chain
0792:                            // need to pass the log buffer, and start column to the next insert.
0793:                            realStartColumn = lce.getNextColumn() + 1;
0794:                            realSpaceOnPage = lce.getRealSpaceOnPage()
0795:                                    - overflowFieldLen;
0796:
0797:                            isLongColumns = true;
0798:                        }
0799:                    } while (isLongColumns);
0800:
0801:                    if (handleToUpdate != null) {
0802:                        // update the recordheader on the previous page
0803:                        updateOverflowDetails(handleToUpdate, handle);
0804:                    }
0805:
0806:                    // all done
0807:                    if (startColumn == -1) {
0808:
0809:                        if (curPage != this )
0810:                            curPage.unlatch();
0811:
0812:                        if (nextPortionHandle != null) {
0813:                            // need to update the overflow details of the last portion
0814:                            // to point to the existing portion
0815:                            updateOverflowDetails(handle, nextPortionHandle);
0816:                        }
0817:
0818:                        return headHandle;
0819:                    }
0820:
0821:                    handleToUpdate = handle;
0822:
0823:                    BasePage nextPage = curPage.getOverflowPageForInsert(slot,
0824:                            row, validColumns, startColumn);
0825:
0826:                    if (curPage != this )
0827:                        curPage.unlatch();
0828:                    curPage = nextPage;
0829:                }
0830:
0831:            }
0832:
0833:            /**
0834:              
0835:            	When we update a column, it turned into a long column.  Need to change
0836:            	the update to effectively insert a new long column chain.
0837:
0838:            	@exception StandardException Unexpected exception from the implementation
0839:             */
0840:            protected RecordHandle insertLongColumn(BasePage mainChainPage,
0841:                    LongColumnException lce, byte insertFlag)
0842:                    throws StandardException {
0843:
0844:                // Object[] row = new Object[1];
0845:                // row[0] = (Object) lce.getColumn();
0846:                Object[] row = new Object[1];
0847:                row[0] = lce.getColumn();
0848:
0849:                RecordHandle firstHandle = null;
0850:                RecordHandle handle = null;
0851:                RecordHandle prevHandle = null;
0852:                BasePage curPage = mainChainPage;
0853:                BasePage prevPage = null;
0854:                boolean isFirstPage = true;
0855:
0856:                // when inserting a long column startCOlumn is just used
0857:                // as a flag. -1 means the insert is complete, != -1 indicates
0858:                // more inserts are required.
0859:                int startColumn = 0;
0860:                RawTransaction t = curPage.owner.getTransaction();
0861:
0862:                do {
0863:                    // in this loop, we do 3 things:
0864:                    // 1. get a new overflow page
0865:                    // 2. insert portion of a long column
0866:                    // 3. update previous handle, release latch on previous page
0867:
0868:                    if (!isFirstPage) {
0869:                        prevPage = curPage;
0870:                        prevHandle = handle;
0871:                    }
0872:
0873:                    // step 1. get a new overflow page
0874:                    curPage = (BasePage) getNewOverflowPage();
0875:
0876:                    if (SanityManager.DEBUG) {
0877:                        SanityManager.ASSERT(curPage.isLatched());
0878:                        SanityManager.ASSERT(curPage.allowInsert());
0879:                    }
0880:
0881:                    int slot = curPage.recordCount;
0882:
0883:                    int recordId = curPage.newRecordId();
0884:                    handle = new RecordId(curPage.getPageId(), recordId, slot);
0885:
0886:                    if (isFirstPage)
0887:                        firstHandle = handle;
0888:
0889:                    // step 2: insert column portion
0890:                    startColumn = owner.getActionSet().actionInsert(t, curPage,
0891:                            slot, recordId, row, (FormatableBitSet) null,
0892:                            (LogicalUndo) null, insertFlag, startColumn, true,
0893:                            -1, (DynamicByteArrayOutputStream) null, -1, 100);
0894:
0895:                    // step 3: if it is not the first page, update previous page,
0896:                    // then release latch on prevPage
0897:                    if (!isFirstPage) {
0898:                        // for the previous page, add an overflow field header,
0899:                        // and update the record header to show 2 fields
0900:                        prevPage.updateFieldOverflowDetails(prevHandle, handle);
0901:                        prevPage.unlatch();
0902:                        prevPage = null;
0903:                    } else
0904:                        isFirstPage = false;
0905:
0906:                } while (startColumn != (-1));
0907:
0908:                if (curPage != null) {
0909:                    curPage.unlatch();
0910:                    curPage = null;
0911:                }
0912:
0913:                return (firstHandle);
0914:            }
0915:
0916:            /**
0917:            	The page or its header is about to be modified.
0918:            	Loggable actions use this to make sure the page gets cleaned if a
0919:            	checkpoint is taken after any log record is sent to the log stream but
0920:            	before the page is actually dirtied.
0921:             */
0922:            public abstract void preDirty();
0923:
0924:            /**
0925:            	Update the overflow pointer for a long row
0926:
0927:            	<BR> MT - latched - page latch must be held
0928:
0929:            	@param handle			handle of the record for long row
0930:            	@param overflowHandle	the overflow (continuation) pointer for the long row
0931:
0932:            	@exception StandardException	Standard Cloudscape error policy
0933:             */
0934:            public abstract void updateOverflowDetails(RecordHandle handle,
0935:                    RecordHandle overflowHandle) throws StandardException;
0936:
0937:            /**
0938:            	Update the overflow pointer for a long column
0939:
0940:            	<BR> MT - latched - page latch must be held
0941:
0942:            	@param handle			handle of the record for long row
0943:            	@param overflowHandle	the overflow (continuation) pointer for the long row
0944:
0945:            	@exception StandardException	Standard Cloudscape error policy
0946:             */
0947:            public abstract void updateFieldOverflowDetails(
0948:                    RecordHandle handle, RecordHandle overflowHandle)
0949:                    throws StandardException;
0950:
0951:            /**
0952:            	Append an overflow pointer to a partly logged row,
0953:            	to point to a long column that just been logged.
0954:
0955:            	<BR> MT - latched - page latch must be held
0956:
0957:            	@param logBuffer		The buffer that contains the partially logged row.
0958:            	@param overflowHandle	the overflow (continuation) pointer
0959:            							to the beginning of the long column
0960:
0961:            	@exception StandardException	Standard Cloudscape error policy
0962:             */
0963:            public abstract int appendOverflowFieldHeader(
0964:                    DynamicByteArrayOutputStream logBuffer,
0965:                    RecordHandle overflowHandle) throws StandardException,
0966:                    IOException;
0967:
0968:            public abstract BasePage getOverflowPageForInsert(int slot,
0969:                    Object[] row, FormatableBitSet validColumns, int startColumn)
0970:                    throws StandardException;
0971:
0972:            protected abstract BasePage getNewOverflowPage()
0973:                    throws StandardException;
0974:
0975:            public final boolean update(RecordHandle handle, Object[] row,
0976:                    FormatableBitSet validColumns) throws StandardException {
0977:                if (SanityManager.DEBUG) {
0978:                    SanityManager.ASSERT(isLatched());
0979:                }
0980:
0981:                if (!owner.updateOK()) {
0982:                    throw StandardException
0983:                            .newException(SQLState.DATA_CONTAINER_READ_ONLY);
0984:                }
0985:
0986:                RawTransaction t = owner.getTransaction();
0987:
0988:                owner.getLockingPolicy().lockRecordForWrite(myLatch, handle);
0989:
0990:                int slot = getSlotNumber(handle);
0991:
0992:                if (isDeletedAtSlot(slot))
0993:                    return false;
0994:
0995:                doUpdateAtSlot(t, slot, handle.getId(), row, validColumns);
0996:
0997:                return true;
0998:            }
0999:
1000:            /** @see Page#delete
1001:                @see BasePage#deleteAtSlot
1002:            	@exception StandardException Standard exception policy. 
1003:             */
1004:            public boolean delete(RecordHandle handle, LogicalUndo undo)
1005:                    throws StandardException {
1006:                if (SanityManager.DEBUG) {
1007:                    SanityManager.ASSERT(isLatched());
1008:                }
1009:
1010:                owner.getLockingPolicy().lockRecordForWrite(myLatch, handle);
1011:
1012:                int slot = getSlotNumber(handle);
1013:
1014:                if (isDeletedAtSlot(slot))
1015:                    return false;
1016:
1017:                deleteAtSlot(slot, true, undo);
1018:                return true;
1019:            }
1020:
1021:            /** @see Page#updateAtSlot
1022:            	@exception StandardException	Standard Cloudscape error policy
1023:            	@exception StandardException	StandardException.newException(SQLState.UPDATE_DELETED_RECORD
1024:            	if the record is already deleted
1025:            	@exception StandardException	StandardException.newException(SQLState.CONTAINER_READ_ONLY
1026:            	if the container is read only
1027:             */
1028:            public final RecordHandle updateAtSlot(int slot, Object[] row,
1029:                    FormatableBitSet validColumns) throws StandardException {
1030:                if (SanityManager.DEBUG) {
1031:                    SanityManager.ASSERT(isLatched());
1032:                }
1033:
1034:                if (!owner.updateOK()) {
1035:                    throw StandardException
1036:                            .newException(SQLState.DATA_CONTAINER_READ_ONLY);
1037:                }
1038:
1039:                if (isDeletedAtSlot(slot)) {
1040:                    throw StandardException
1041:                            .newException(SQLState.DATA_UPDATE_DELETED_RECORD);
1042:                }
1043:
1044:                RecordHandle handle = getRecordHandleAtSlot(slot);
1045:
1046:                RawTransaction t = owner.getTransaction();
1047:
1048:                doUpdateAtSlot(t, slot, handle.getId(), row, validColumns);
1049:
1050:                return handle;
1051:            }
1052:
1053:            public abstract void doUpdateAtSlot(RawTransaction t, int slot,
1054:                    int id, Object[] row, FormatableBitSet validColumns)
1055:                    throws StandardException;
1056:
1057:            /** @see Page#updateFieldAtSlot
1058:            	@exception StandardException	Standard Cloudscape error policy
1059:            	@exception StandardException	StandardException.newException(SQLState.UPDATE_DELETED_RECORD
1060:            	if the record is already deleted
1061:            	@exception StandardException	StandardException.newException(SQLState.CONTAINER_READ_ONLY
1062:            	if the container is read only
1063:             */
1064:            public RecordHandle updateFieldAtSlot(int slot, int fieldId,
1065:                    Object newValue, LogicalUndo undo) throws StandardException {
1066:                if (SanityManager.DEBUG) {
1067:                    SanityManager.ASSERT(isLatched());
1068:                    SanityManager.ASSERT(newValue != null);
1069:                }
1070:
1071:                if (!owner.updateOK()) {
1072:                    throw StandardException
1073:                            .newException(SQLState.DATA_CONTAINER_READ_ONLY);
1074:                }
1075:
1076:                if (isDeletedAtSlot(slot)) {
1077:                    throw StandardException
1078:                            .newException(SQLState.DATA_UPDATE_DELETED_RECORD);
1079:                }
1080:
1081:                RawTransaction t = owner.getTransaction();
1082:                RecordHandle handle = getRecordHandleAtSlot(slot);
1083:
1084:                owner.getActionSet().actionUpdateField(t, this , slot,
1085:                        handle.getId(), fieldId, newValue, undo);
1086:
1087:                return handle;
1088:            }
1089:
1090:            /** @see Page#fetchNumFields
1091:            	@exception StandardException Standard exception policy. 
1092:             */
1093:            public final int fetchNumFields(RecordHandle handle)
1094:                    throws StandardException {
1095:                if (SanityManager.DEBUG) {
1096:                    SanityManager.ASSERT(isLatched());
1097:                }
1098:
1099:                return fetchNumFieldsAtSlot(getSlotNumber(handle));
1100:            }
1101:
1102:            /** @see Page#fetchNumFieldsAtSlot
1103:            	@exception StandardException Standard exception policy. 
1104:             */
1105:            public int fetchNumFieldsAtSlot(int slot) throws StandardException {
1106:                if (SanityManager.DEBUG) {
1107:                    SanityManager.ASSERT(isLatched());
1108:                }
1109:
1110:                return getHeaderAtSlot(slot).getNumberFields();
1111:            }
1112:
1113:            /** 
1114:            	@see Page#deleteAtSlot
1115:
1116:            	@param slot		the slot number
1117:            	@param delete	true if this record is to be deleted, false if this
1118:            					deleted record is to be marked undeleted
1119:            	@param undo		logical undo logic if necessary
1120:
1121:            	@exception StandardException Standard exception policy. 
1122:            	@exception StandardException	StandardException.newException(SQLState.UPDATE_DELETED_RECORD
1123:            	if an attempt to delete a record that is already deleted
1124:            	@exception StandardException	StandardException.newException(SQLState.UNDELETE_RECORD
1125:            	if an attempt to undelete a record that is not deleted
1126:             */
1127:            public RecordHandle deleteAtSlot(int slot, boolean delete,
1128:                    LogicalUndo undo) throws StandardException {
1129:                if (SanityManager.DEBUG) {
1130:                    SanityManager.ASSERT(isLatched());
1131:                }
1132:
1133:                if (!owner.updateOK()) {
1134:                    throw StandardException
1135:                            .newException(SQLState.DATA_CONTAINER_READ_ONLY);
1136:                }
1137:
1138:                if (delete) {
1139:                    if (isDeletedAtSlot(slot)) {
1140:                        throw StandardException
1141:                                .newException(SQLState.DATA_UPDATE_DELETED_RECORD);
1142:                    }
1143:
1144:                } else // undelete a deleted record
1145:                {
1146:                    if (!isDeletedAtSlot(slot)) {
1147:                        throw StandardException
1148:                                .newException(SQLState.DATA_UNDELETE_RECORD);
1149:                    }
1150:                }
1151:
1152:                RawTransaction t = owner.getTransaction();
1153:
1154:                // logical operations not allowed in internal transactions.
1155:                if (undo != null) {
1156:                    t.checkLogicalOperationOk();
1157:                }
1158:
1159:                RecordHandle handle = getRecordHandleAtSlot(slot);
1160:
1161:                owner.getActionSet().actionDelete(t, this , slot,
1162:                        handle.getId(), delete, undo);
1163:
1164:                // delete/undelete the record in the stored version
1165:                // and in the in memory version performed by the PageActions item 
1166:
1167:                return handle;
1168:            }
1169:
1170:            /** 
1171:            	Purge one or more rows on a non-overflow page.
1172:
1173:            	@see Page#purgeAtSlot
1174:            	@exception StandardException Standard exception policy. 
1175:             */
1176:            public void purgeAtSlot(int slot, int numpurges,
1177:                    boolean needDataLogged) throws StandardException {
1178:                if (SanityManager.DEBUG) {
1179:                    SanityManager.ASSERT(isLatched());
1180:
1181:                    if (isOverflowPage())
1182:                        SanityManager
1183:                                .THROWASSERT("purge committed deletes on an overflow page.  Page = "
1184:                                        + this );
1185:                }
1186:
1187:                if (numpurges <= 0)
1188:                    return;
1189:
1190:                if (!owner.updateOK()) {
1191:                    throw StandardException
1192:                            .newException(SQLState.DATA_CONTAINER_READ_ONLY);
1193:                }
1194:
1195:                if ((slot < 0) || ((slot + numpurges) > recordCount)) {
1196:
1197:                    throw StandardException
1198:                            .newException(SQLState.DATA_SLOT_NOT_ON_PAGE);
1199:                }
1200:
1201:                RawTransaction t = owner.getTransaction();
1202:
1203:                // lock the records to be purged
1204:                int[] recordIds = new int[numpurges];
1205:
1206:                PageKey pageId = getPageId(); // RESOLVE: MT problem ?
1207:
1208:                for (int i = 0; i < numpurges; i++) {
1209:                    recordIds[i] = getHeaderAtSlot(slot + i).getId();
1210:
1211:                    // get row lock on head row piece
1212:                    RecordHandle handle = getRecordHandleAtSlot(slot);
1213:                    owner.getLockingPolicy().lockRecordForWrite(t, handle,
1214:                            false, true);
1215:
1216:                    // Before we purge these rows, we need to make sure they don't have
1217:                    // overflow rows and columns.  Only clean up long rows and long
1218:                    // columns if this is not a temporary container, otherwise, just
1219:                    // loose the space.
1220:
1221:                    if (owner.isTemporaryContainer()
1222:                            || entireRecordOnPage(slot + i))
1223:                        continue;
1224:
1225:                    // row[slot+i] has overflow rows and/or long columns, reclaim
1226:                    // them in a loop.
1227:                    RecordHandle headRowHandle = getHeaderAtSlot(slot + i)
1228:                            .getHandle(pageId, slot + i);
1229:                    purgeRowPieces(t, slot + i, headRowHandle, needDataLogged);
1230:                }
1231:
1232:                owner.getActionSet().actionPurge(t, this , slot, numpurges,
1233:                        recordIds, needDataLogged);
1234:
1235:            }
1236:
1237:            /**
1238:            	Purge all the overflow columns and overflow rows of the record at slot.
1239:            	@exception StandardException Standard exception policy. 
1240:             */
1241:            protected abstract void purgeRowPieces(RawTransaction t, int slot,
1242:                    RecordHandle headRowHandle, boolean needDataLogged)
1243:                    throws StandardException;
1244:
1245:            /** @see Page#copyAndPurge
1246:            	@exception StandardException Standard exception policy. 
1247:             */
1248:            public void copyAndPurge(Page destPage, int src_slot, int num_rows,
1249:                    int dest_slot) throws StandardException {
1250:                if (SanityManager.DEBUG) {
1251:                    SanityManager.ASSERT(isLatched());
1252:                }
1253:
1254:                if (num_rows <= 0) {
1255:                    throw StandardException
1256:                            .newException(SQLState.DATA_NO_ROW_COPIED);
1257:                }
1258:
1259:                if (!owner.updateOK()) {
1260:                    throw StandardException
1261:                            .newException(SQLState.DATA_CONTAINER_READ_ONLY);
1262:                }
1263:
1264:                if ((src_slot < 0) || ((src_slot + num_rows) > recordCount)) {
1265:                    throw StandardException
1266:                            .newException(SQLState.DATA_SLOT_NOT_ON_PAGE);
1267:                }
1268:
1269:                if (SanityManager.DEBUG) {
1270:                    // first copy into the destination page, let it do the work
1271:                    // if no problem, then purge from this page
1272:                    SanityManager.ASSERT((destPage instanceof  BasePage),
1273:                            "must copy from BasePage to BasePage");
1274:                }
1275:
1276:                BasePage dpage = (BasePage) destPage;
1277:
1278:                // make sure they are from the same container - this means they are of
1279:                // the same size and have the same page and record format.
1280:
1281:                PageKey pageId = getPageId(); // RESOLVE: MT problem ?
1282:
1283:                if (!pageId.getContainerId().equals(
1284:                        dpage.getPageId().getContainerId())) {
1285:                    throw StandardException.newException(
1286:                            SQLState.DATA_DIFFERENT_CONTAINER, pageId
1287:                                    .getContainerId(), dpage.getPageId()
1288:                                    .getContainerId());
1289:                }
1290:
1291:                int[] recordIds = new int[num_rows];
1292:
1293:                RawTransaction t = owner.getTransaction();
1294:
1295:                // lock the records to be purged and calculate total space needed
1296:                for (int i = 0; i < num_rows; i++) {
1297:                    RecordHandle handle = getRecordHandleAtSlot(src_slot + i);
1298:                    owner.getLockingPolicy().lockRecordForWrite(t, handle,
1299:                            false, true);
1300:
1301:                    recordIds[i] = getHeaderAtSlot(src_slot + i).getId();
1302:                }
1303:
1304:                // first copy num_rows into destination page
1305:                dpage.copyInto(this , src_slot, num_rows, dest_slot);
1306:
1307:                // Now purge num_rows from this page
1308:                // Do NOT purge overflow rows, if it has such a thing.  This operation
1309:                // is called by split and if the key has overflow, spliting the head
1310:                // page does not copy over the remaining pieces, i.e.,the new head page
1311:                // still points to those pieces.
1312:
1313:                owner.getActionSet().actionPurge(t, this , src_slot, num_rows,
1314:                        recordIds, true);
1315:            }
1316:
1317:            /**
1318:            	Unlatch the page.
1319:            	@see Page#unlatch
1320:             */
1321:            public void unlatch() {
1322:                if (SanityManager.DEBUG) {
1323:                    SanityManager.ASSERT(isLatched());
1324:                }
1325:
1326:                releaseExclusive();
1327:            }
1328:
1329:            /** @see Page#isLatched */
1330:            public boolean isLatched() {
1331:                if (SanityManager.DEBUG) {
1332:
1333:                    synchronized (this ) {
1334:                        SanityManager.ASSERT(identity != null);
1335:                        if (owner != null) {
1336:                            if (owner != myLatch.getQualifier())
1337:                                SanityManager
1338:                                        .THROWASSERT("Page incorrectly latched - "
1339:                                                + owner
1340:                                                + " "
1341:                                                + myLatch.getQualifier());
1342:                        }
1343:                    }
1344:                }
1345:
1346:                return owner != null;
1347:            }
1348:
1349:            /** @see Page#recordCount */
1350:            public final int recordCount() {
1351:                if (SanityManager.DEBUG) {
1352:                    SanityManager.ASSERT(isLatched());
1353:                }
1354:
1355:                return recordCount;
1356:            }
1357:
1358:            /**
1359:            	get record count without checking for latch
1360:             */
1361:            protected abstract int internalDeletedRecordCount();
1362:
1363:            /**
1364:            	get record count without checking for latch
1365:             */
1366:            protected int internalNonDeletedRecordCount() {
1367:                // deallocated or freed page, don't count
1368:                if (pageStatus != VALID_PAGE)
1369:                    return 0;
1370:
1371:                int deletedCount = internalDeletedRecordCount();
1372:
1373:                if (deletedCount == -1) {
1374:                    int count = 0;
1375:                    int maxSlot = recordCount;
1376:                    for (int slot = FIRST_SLOT_NUMBER; slot < maxSlot; slot++) {
1377:                        if (!isDeletedOnPage(slot))
1378:                            count++;
1379:                    }
1380:                    return count;
1381:
1382:                } else {
1383:
1384:                    if (SanityManager.DEBUG) {
1385:                        int delCount = 0;
1386:                        int maxSlot = recordCount;
1387:                        for (int slot = FIRST_SLOT_NUMBER; slot < maxSlot; slot++) {
1388:                            if (recordHeaderOnDemand(slot).isDeleted())
1389:                                delCount++;
1390:                        }
1391:                        if (delCount != deletedCount)
1392:                            SanityManager
1393:                                    .THROWASSERT("incorrect deleted row count.  Should be: "
1394:                                            + delCount
1395:                                            + ", instead got: "
1396:                                            + deletedCount
1397:                                            + ", maxSlot = "
1398:                                            + maxSlot
1399:                                            + ", recordCount = "
1400:                                            + recordCount);
1401:                    }
1402:
1403:                    return (recordCount - deletedCount);
1404:                }
1405:            }
1406:
1407:            /** @see Page#nonDeletedRecordCount */
1408:            public int nonDeletedRecordCount() {
1409:                if (SanityManager.DEBUG) {
1410:                    SanityManager.ASSERT(isLatched());
1411:                }
1412:
1413:                return internalNonDeletedRecordCount();
1414:
1415:            }
1416:
1417:            /**
1418:             * Is this page/deleted row a candidate for immediate reclaim space.
1419:             * <p>
1420:             * Used by access methods after executing a delete on "slot_just_deleted"
1421:             * to ask whether a post commit should be queued to try to reclaim space
1422:             * after the delete commits.  
1423:             * <p>
1424:             * Will return true if the number of non-deleted rows on the page is
1425:             * <= "num_non_deleted_rows".  For instance 0 means schedule reclaim
1426:             * only if all rows are deleted, 1 if all rows but one are deleted.  
1427:             * <p>
1428:             * Will return true if the row just deleted is either a long row or long
1429:             * column.  In this case doing a reclaim space on the single row may
1430:             * reclaim multiple pages of free space, so better to do it now rather
1431:             * than wait for all rows on page to be deleted.  This case is to address
1432:             * the worst case scenario of all rows with long columns, but very short
1433:             * rows otherwise.  In this case there could be 1000's of rows on the 
1434:             * main page with many gigabytes of data on overflow pages in deleted space
1435:             * that would not be reclaimed until all rows on the page were deleted.
1436:             *
1437:             * @return true if a reclaim space should be scheduled post commit on this
1438:             *         page, false otherwise.
1439:             *
1440:             * @param num_non_deleted_rows threshold number of non-deleted rows to
1441:             *                             schedule reclaim space.
1442:             * @param slot_just_deleted    row on page to check for long row/long column
1443:             *
1444:             * @exception  StandardException  Standard exception policy.
1445:             **/
1446:            public boolean shouldReclaimSpace(int num_non_deleted_rows,
1447:                    int slot_just_deleted) throws StandardException {
1448:                if (SanityManager.DEBUG) {
1449:                    SanityManager.ASSERT(isLatched());
1450:                }
1451:
1452:                boolean ret_val = false;
1453:
1454:                if (internalNonDeletedRecordCount() <= num_non_deleted_rows) {
1455:                    ret_val = true;
1456:                } else {
1457:                    if (!entireRecordOnPage(slot_just_deleted)) {
1458:                        ret_val = true;
1459:                    }
1460:                }
1461:
1462:                return (ret_val);
1463:            }
1464:
1465:            // no need to check for slot on page, call already checked
1466:            protected final boolean isDeletedOnPage(int slot) {
1467:                return getHeaderAtSlot(slot).isDeleted();
1468:            }
1469:
1470:            /** @see Page#isDeletedAtSlot
1471:            	@exception StandardException Standard exception policy. 
1472:             */
1473:            public boolean isDeletedAtSlot(int slot) throws StandardException {
1474:                if (SanityManager.DEBUG) {
1475:                    SanityManager.ASSERT(isLatched());
1476:                }
1477:
1478:                checkSlotOnPage(slot);
1479:
1480:                return isDeletedOnPage(slot);
1481:            }
1482:
1483:            /**
1484:            	Set the aux object.
1485:
1486:            	<BR> MT - single thread required. Calls via the Page interface will have the
1487:            		page latched, thus providing single threadedness. Otherwise calls via this class
1488:            		are only made when the class has no-identity, thus only a single thread can see the object. 
1489:
1490:            	@see Page#setAuxObject
1491:             */
1492:            public void setAuxObject(AuxObject obj) {
1493:                if (SanityManager.DEBUG) {
1494:                    SanityManager.ASSERT((identity == null) || isLatched());
1495:                }
1496:
1497:                if (auxObj != null) {
1498:                    auxObj.auxObjectInvalidated();
1499:                }
1500:
1501:                auxObj = obj;
1502:            }
1503:
1504:            /**
1505:            	Get the aux object.
1506:            	<BR> MT - latched - It is required the caller throws away the returned reference
1507:            	when the page is unlatched.
1508:
1509:            	@see Page#getAuxObject
1510:             */
1511:            public AuxObject getAuxObject() {
1512:                if (SanityManager.DEBUG) {
1513:                    SanityManager.ASSERT(isLatched());
1514:                }
1515:
1516:                return auxObj;
1517:            }
1518:
1519:            /*
1520:             ** Methods from Lockable, just require a single exclusive locker
1521:             */
1522:
1523:            /**
1524:            	Latch me.
1525:            	<BR>
1526:            	MT - single thread required (methods of Lockable)
1527:            	@see Lockable#lockEvent
1528:             */
1529:            public void lockEvent(Latch lockInfo) {
1530:                if (SanityManager.DEBUG) {
1531:                    SanityManager.ASSERT(owner == null,
1532:                            "Should only be called when not locked");
1533:                }
1534:
1535:                synchronized (this ) {
1536:
1537:                    myLatch = lockInfo;
1538:
1539:                    // Move page state from UNLATCHED to PRELATCH, setExclusiveNo*()
1540:                    // routines do the work of completing the latch - using the 
1541:                    // preLatch status.  This is so that
1542:                    // we don't have to wait for a clean() initiated I/O here while
1543:                    // holding the locking system monitor.
1544:                    (owner = (BaseContainerHandle) lockInfo.getQualifier())
1545:                            .addObserver(this );
1546:                    preLatch = true;
1547:                }
1548:            }
1549:
1550:            /**
1551:            	Is another request compatible, no never.
1552:            	<BR> MT - single thread required (methods of Lockable)
1553:            	@see Lockable#requestCompatible
1554:             */
1555:            public boolean requestCompatible(Object requestedQualifier,
1556:                    Object grantedQualifier) {
1557:                if (SanityManager.DEBUG) {
1558:                    SanityManager.ASSERT(owner != null,
1559:                            "Should only be called when locked");
1560:                }
1561:
1562:                return false;
1563:            }
1564:
1565:            /**
1566:            	Is another request compatible, no never.
1567:            	<BR> MT - single thread required (methods of Lockable)
1568:            	@see Lockable#requestCompatible
1569:             */
1570:            public boolean lockerAlwaysCompatible() {
1571:                if (SanityManager.DEBUG) {
1572:                    SanityManager.ASSERT(owner != null,
1573:                            "Should only be called when locked");
1574:                }
1575:
1576:                return false;
1577:            }
1578:
1579:            /**
1580:            	Unlatch me, only to be called from lock manager.
1581:            	<BR> MT - single thread required (methods of Lockable)
1582:
1583:            	@see Lockable#requestCompatible
1584:             */
1585:            public void unlockEvent(Latch lockInfo) {
1586:                if (SanityManager.DEBUG) {
1587:                    SanityManager.ASSERT(owner != null,
1588:                            "Should only be called when locked");
1589:                }
1590:
1591:                synchronized (this ) {
1592:
1593:                    if (SanityManager.DEBUG) {
1594:                        if (nestedLatch != 0)
1595:                            SanityManager
1596:                                    .THROWASSERT("nestedLatch is non-zero on unlockEvent - value = "
1597:                                            + nestedLatch);
1598:                    }
1599:
1600:                    owner.deleteObserver(this );
1601:                    owner = null;
1602:                    myLatch = null;
1603:                    if (inClean)
1604:                        notifyAll();
1605:                }
1606:            }
1607:
1608:            /*
1609:             ** Methods of Observer.
1610:             */
1611:
1612:            /**
1613:            	This object is set to observe the BaseContainerHandle it was obtained by,
1614:            	that handle will notify its observers when it is being closed. In that case
1615:            	we will release the latch on the page held by that container.
1616:
1617:            	<BR>
1618:            	MT - latched
1619:
1620:            	@see Observer#update
1621:             */
1622:
1623:            public void update(Observable obj, Object arg) {
1624:
1625:                if (SanityManager.DEBUG) {
1626:                    SanityManager.ASSERT(isLatched());
1627:                    SanityManager.ASSERT(obj == owner);
1628:                }
1629:
1630:                releaseExclusive();
1631:            }
1632:
1633:            /*
1634:             ** Implementation specific methods
1635:             */
1636:
1637:            /**
1638:            	Get the Page identifer
1639:
1640:            	<BR> MT - RESOLVE
1641:             */
1642:            public PageKey getPageId() {
1643:                if (SanityManager.DEBUG) {
1644:                    SanityManager.ASSERT(identity != null);
1645:                }
1646:
1647:                return identity;
1648:            }
1649:
1650:            /**
1651:            	Get an exclusive latch on the page.
1652:            	<BR>
1653:            	MT - thread safe
1654:            	@exception StandardException Standard Cloudscape policy.
1655:             */
1656:            public void setExclusive(BaseContainerHandle requester)
1657:                    throws StandardException {
1658:
1659:                RawTransaction t = requester.getTransaction();
1660:
1661:                // In some cases latches are held until after a commit or an abort
1662:                // (currently internal and nested top transactions.
1663:                // If this is the case then during an abort a latch
1664:                // request will be made for a latch that is already held.
1665:                // We do not allow the latch to be obtained multiple times
1666:                // because i) lock manager might assume latches are exclusive for
1667:                // performance, ii) holding a page latched means that the page is
1668:                // on the container handle's obervers list, if we latched it twice
1669:                // then the paeg would have to be on the list twice, which is not supported
1670:                // since the page has value equality. To be on the list twice reference
1671:                // equality would be required, which would mean pushing a ReferenceObservable
1672:                // object for every latch; iii) other unknown reasons :-)
1673:                synchronized (this ) {
1674:                    // need synchronized block because owner may be set to null in the
1675:                    // middle if another thread is in the process of unlatching the
1676:                    // page 
1677:                    if ((owner != null) && (t == owner.getTransaction())) {
1678:
1679:                        if (t.inAbort()) {
1680:                            //
1681:                            nestedLatch++;
1682:                            return;
1683:                        }
1684:                    }
1685:                    // just deadlock out ...
1686:                }
1687:
1688:                // Latch the page, owner is set through the Lockable call backs.
1689:                t.getLockFactory().latchObject(t, this , requester,
1690:                        C_LockFactory.WAIT_FOREVER);
1691:
1692:                // latch granted, but cleaner may "own" the page.  
1693:
1694:                if (SanityManager.DEBUG) {
1695:                    SanityManager.ASSERT(isLatched(), "page not latched");
1696:                }
1697:
1698:                synchronized (this ) {
1699:                    // lockEvent() will grant latch, even if cleaner "owns" the page.
1700:                    // Wait here unil cleaner is done.  This is safe as now we own the
1701:                    // latch, and have yet to do anything to the in-memory data 
1702:                    // structures.
1703:                    // 
1704:                    // Previously we would wait in lockEvent, but that caused the code 
1705:                    // to block on I/O while holding the locking system monitor.
1706:
1707:                    while (inClean) {
1708:                        try {
1709:                            // Expect notify from clean() routine.
1710:                            wait();
1711:                        } catch (InterruptedException ie) {
1712:                        }
1713:                    }
1714:
1715:                    // no clean taking place, so safe to move to full LATCHED state.
1716:                    preLatch = false;
1717:                }
1718:
1719:            }
1720:
1721:            /**
1722:            	Get an exclusive latch on the page, but only if I don't have to wait.
1723:            	<BR>
1724:            	MT - thread safe
1725:             */
1726:            boolean setExclusiveNoWait(BaseContainerHandle requester)
1727:                    throws StandardException {
1728:
1729:                RawTransaction t = requester.getTransaction();
1730:
1731:                // comment in setExclusive()
1732:                synchronized (this ) {
1733:                    if ((owner != null) && (t == owner.getTransaction())) {
1734:
1735:                        if (t.inAbort()) {
1736:                            //
1737:                            nestedLatch++;
1738:                            return true;
1739:                        }
1740:                    }
1741:                    // just deadlock out ...
1742:                }
1743:
1744:                // Latch the page, owner is set through the Lockable call backs.
1745:                boolean gotLatch = t.getLockFactory().latchObject(t, this ,
1746:                        requester, C_LockFactory.NO_WAIT);
1747:                if (!gotLatch)
1748:                    return false;
1749:
1750:                synchronized (this ) {
1751:                    // lockEvent() will grant latch, even if cleaner "owns" the page.
1752:                    // Wait here unil cleaner is done.  This is safe as now we own the
1753:                    // latch, and have yet to do anything to the in-memory data 
1754:                    // structures.
1755:                    // 
1756:                    // Previously we would wait in lockEvent, but that caused the code 
1757:                    // to block on I/O while holding the locking system monitor.
1758:
1759:                    while (inClean) {
1760:                        //if (SanityManager.DEBUG)
1761:                        //   SanityManager.DEBUG_PRINT("setExclusiveNoWait", "in while loop.");
1762:
1763:                        try {
1764:                            // Expect notify from clean() routine.
1765:                            wait();
1766:                        } catch (InterruptedException ie) {
1767:                        }
1768:                    }
1769:
1770:                    // no clean taking place, so safe to move to full LATCHED state.
1771:                    preLatch = false;
1772:                }
1773:
1774:                if (SanityManager.DEBUG) {
1775:                    SanityManager.ASSERT(isLatched(), "page not latched");
1776:                }
1777:
1778:                return true;
1779:            }
1780:
1781:            /**
1782:            	Release the exclusive latch on the page.
1783:            	<BR>
1784:            	MT - latched
1785:             */
1786:            protected void releaseExclusive() /* throws StandardException */{
1787:
1788:                if (SanityManager.DEBUG) {
1789:                    if (!isLatched()) {
1790:                        SanityManager
1791:                                .THROWASSERT("releaseExclusive failed, nestedLatch = "
1792:                                        + nestedLatch);
1793:                    }
1794:                }
1795:
1796:                if (nestedLatch > 0) {
1797:                    nestedLatch--;
1798:                    return;
1799:                }
1800:
1801:                RawTransaction t = owner.getTransaction();
1802:                t.getLockFactory().unlatch(myLatch);
1803:            }
1804:
1805:            /*
1806:             ** Manipulation of the in-memory version of the slot table.
1807:             */
1808:
1809:            /**
1810:            	Must be called by any non-abstract sub-class to initialise the slot
1811:            	table.
1812:             */
1813:
1814:            protected final void setHeaderAtSlot(int slot, StoredRecordHeader rh) {
1815:
1816:                if (slot < headers.length) {
1817:                    // check that array "cache" of headers is big enough.
1818:                    if (rh != null) {
1819:                        headers[slot] = rh;
1820:                    }
1821:                } else {
1822:                    // need to grow the array, just allocate new array and copy.
1823:                    StoredRecordHeader[] new_headers = new StoredRecordHeader[slot + 1];
1824:
1825:                    System
1826:                            .arraycopy(headers, 0, new_headers, 0,
1827:                                    headers.length);
1828:
1829:                    headers = new_headers;
1830:
1831:                    headers[slot] = rh;
1832:                }
1833:            }
1834:
1835:            protected final void bumpRecordCount(int number) {
1836:                recordCount += number;
1837:            }
1838:
1839:            public final StoredRecordHeader getHeaderAtSlot(int slot) {
1840:
1841:                if (slot < headers.length) {
1842:                    StoredRecordHeader rh = headers[slot];
1843:
1844:                    return ((rh != null) ? rh : recordHeaderOnDemand(slot));
1845:                } else {
1846:                    return recordHeaderOnDemand(slot);
1847:                }
1848:            }
1849:
1850:            /**
1851:            	Returns true if the entire record of that slot fits inside of this
1852:            	page.  Returns false if part of the record on this slot overflows to
1853:            	other pages, either due to long row or long column. 
1854:
1855:            	<BR>
1856:            	MT - latched
1857:
1858:            	@exception StandardException Standard Cloudscape error policy
1859:             */
1860:            public abstract boolean entireRecordOnPage(int slot)
1861:                    throws StandardException;
1862:
1863:            public abstract StoredRecordHeader recordHeaderOnDemand(int slot);
1864:
1865:            /**
1866:            	Is the given slot number on the page?
1867:
1868:            	<BR>
1869:            	MT - latched
1870:             */
1871:            private final void checkSlotOnPage(int slot)
1872:                    throws StandardException {
1873:
1874:                if (SanityManager.DEBUG) {
1875:                    SanityManager.ASSERT(isLatched());
1876:                }
1877:
1878:                if (slot >= FIRST_SLOT_NUMBER && slot < recordCount) {
1879:                    return;
1880:                }
1881:
1882:                throw StandardException
1883:                        .newException(SQLState.DATA_SLOT_NOT_ON_PAGE);
1884:            }
1885:
1886:            /**
1887:            	Mark the record at the passed in slot as deleted.
1888:
1889:            	return code comes from StoredRecordHeader class:
1890:            		return	1, if delete status from not deleted to deleted
1891:            		return -1, if delete status from deleted to not deleted
1892:            		return  0, if status unchanged.
1893:            	<BR>
1894:            	<B>Any sub-class must call this method when deleting a record.</B>
1895:
1896:            	<BR>
1897:            	MT - latched
1898:
1899:            	@exception StandardException Standard Cloudscape error policy
1900:            	@exception IOException IO error accessing page
1901:             */
1902:            public int setDeleteStatus(int slot, boolean delete)
1903:                    throws StandardException, IOException {
1904:
1905:                if (SanityManager.DEBUG) {
1906:                    // latch check performed in checkSlotOnPage
1907:                    checkSlotOnPage(slot);
1908:                    ;
1909:                }
1910:
1911:                return (getHeaderAtSlot(slot).setDeleted(delete));
1912:            }
1913:
1914:            /**
1915:            	Mark this page as being deallocated
1916:
1917:            	@exception StandardException Cloudscape Standard error policy
1918:             */
1919:            public void deallocatePage() throws StandardException {
1920:                if (SanityManager.DEBUG) {
1921:                    SanityManager.ASSERT(isLatched());
1922:                }
1923:
1924:                if (!owner.updateOK()) {
1925:                    throw StandardException
1926:                            .newException(SQLState.DATA_CONTAINER_READ_ONLY);
1927:                }
1928:
1929:                RawTransaction t = owner.getTransaction();
1930:
1931:                owner.getActionSet().actionInvalidatePage(t, this );
1932:            }
1933:
1934:            /**
1935:            	Mark this page as being allocated and initialize it to a pristine page
1936:            	@exception StandardException Cloudscape Standard error policy
1937:             */
1938:            public void initPage(int initFlag, long pageOffset)
1939:                    throws StandardException {
1940:                if (SanityManager.DEBUG) {
1941:                    SanityManager.ASSERT(isLatched());
1942:                }
1943:
1944:                if (!owner.updateOK()) {
1945:                    throw StandardException
1946:                            .newException(SQLState.DATA_CONTAINER_READ_ONLY);
1947:                }
1948:
1949:                RawTransaction t = owner.getTransaction();
1950:
1951:                owner.getActionSet().actionInitPage(t, this , initFlag,
1952:                        getTypeFormatId(), pageOffset);
1953:            }
1954:
1955:            /**
1956:            	Find the slot for the record with the passed in identifier.
1957:
1958:            	<BR>
1959:            	This method returns the record regardless of its deleted status.
1960:                <BR>
1961:                The "slotHint" argument is a hint about what slot the record id might
1962:                be in.  Callers may save the last slot where the record was across
1963:                latch/unlatches to the page, and then pass that slot back as a hint - 
1964:                if the page has not shuffled slots since the last reference then the
1965:                hint will succeed and a linear search is saved.  If the caller has
1966:                no idea where it may be, then FIRST_SLOT_NUMBER is passed in and a
1967:                linear search is performed.
1968:            	<BR>
1969:            	MT - latched
1970:
1971:                @param recordId  record id of the record to search for.
1972:                @param slotHint "hint" about which slot the record might be in.
1973:            	
1974:             */
1975:            public int findRecordById(int recordId, int slotHint) {
1976:
1977:                if (SanityManager.DEBUG) {
1978:                    SanityManager.ASSERT(isLatched());
1979:                }
1980:
1981:                if (slotHint == FIRST_SLOT_NUMBER)
1982:                    slotHint = recordId - RecordHandle.FIRST_RECORD_ID;
1983:
1984:                int maxSlot = recordCount();
1985:
1986:                if ((slotHint > FIRST_SLOT_NUMBER) && (slotHint < maxSlot)
1987:                        && (recordId == getHeaderAtSlot(slotHint).getId())) {
1988:                    return (slotHint);
1989:                } else {
1990:                    for (int slot = FIRST_SLOT_NUMBER; slot < maxSlot; slot++) {
1991:                        if (recordId == getHeaderAtSlot(slot).getId()) {
1992:                            return slot;
1993:                        }
1994:                    }
1995:                }
1996:
1997:                return -1;
1998:            }
1999:
2000:            /**
2001:            	Find the slot for the first record on the page with an id greater than 
2002:                the passed in identifier.
2003:
2004:            	<BR>
2005:                Returns the slot of the first record on the page with an id greater 
2006:                than the one passed in.  Usefulness of this functionality depends on the
2007:                clients use of the raw store interfaces.  If all "new" records are
2008:                always inserted at the end of the page, and the raw store continues
2009:                to guarantee that all record id's will be allocated in increasing order
2010:                on a given page, then a page is always sorted
2011:                in record id order.  For instance current heap tables function this
2012:                way.  If the client ever inserts at a particular slot number, rather
2013:                than at the "end" then the record id's will not be sorted.
2014:                <BR>
2015:                In the case where all record id's are always sorted on a page, then
2016:                this routine can be used by scan's which "lose" their position because
2017:                the row they have as a position was purged.  They can reposition their
2018:                scan at the "next" row after the row that is now missing from the table.
2019:            	<BR>
2020:            	This method returns the record regardless of its deleted status.
2021:            	<BR>
2022:            	MT - latched
2023:
2024:                @param recordId  record id of the first record on the page with a 
2025:                                 record id higher than the one passed in.  If no 
2026:                                 such record exists, -1 is returned.
2027:             */
2028:            private int findNextRecordById(int recordId) {
2029:                if (SanityManager.DEBUG) {
2030:                    SanityManager.ASSERT(isLatched());
2031:                }
2032:
2033:                int maxSlot = recordCount();
2034:
2035:                for (int slot = FIRST_SLOT_NUMBER; slot < maxSlot; slot++) {
2036:                    if (getHeaderAtSlot(slot).getId() > recordId) {
2037:                        return (slot);
2038:                    }
2039:                }
2040:
2041:                return -1;
2042:            }
2043:
2044:            /**
2045:            	Copy num_rows from srcPage, src_slot into this page starting at dest_slot.
2046:            	This is destination page of the the copy half of copy and Purge.
2047:
2048:            	@see Page#copyAndPurge
2049:             */
2050:            private void copyInto(BasePage srcPage, int src_slot, int num_rows,
2051:                    int dest_slot) throws StandardException {
2052:                if ((dest_slot < 0) || dest_slot > recordCount) {
2053:                    throw StandardException
2054:                            .newException(SQLState.DATA_SLOT_NOT_ON_PAGE);
2055:                }
2056:
2057:                RawTransaction t = owner.getTransaction();
2058:
2059:                // get num_rows row locks, need to predict what those recordIds will be
2060:
2061:                int[] recordIds = new int[num_rows];
2062:
2063:                PageKey pageId = getPageId(); // RESOLVE - MT problem ?
2064:
2065:                // get new recordIds for the rows from this page 
2066:                // RESOLVE: we should also record the amount of reserved space
2067:
2068:                for (int i = 0; i < num_rows; i++) {
2069:                    if (i == 0)
2070:                        recordIds[i] = newRecordId();
2071:                    else
2072:                        recordIds[i] = newRecordId(recordIds[i - 1]);
2073:
2074:                    RecordHandle handle = new RecordId(pageId, recordIds[i], i);
2075:                    owner.getLockingPolicy().lockRecordForWrite(t, handle,
2076:                            false, true);
2077:                }
2078:
2079:                // RESOLVE: need try block here to invalidate self and crash the system
2080:                owner.getActionSet().actionCopyRows(t, this , srcPage,
2081:                        dest_slot, num_rows, src_slot, recordIds);
2082:            }
2083:
2084:            /**
2085:                Remove record at slot.
2086:                <p>
2087:            	Remove the slot at the in-memory slot table, i.e.,
2088:            	slots from 0 to deleteSlot-1 is untouched, deleteSlot is removed from
2089:            	in memory slot table, deleteSlot+1 .. recordCount()-1 move to
2090:            	down one slot.
2091:
2092:            	<BR>
2093:            	MT - latched
2094:             */
2095:            protected void removeAndShiftDown(int slot) {
2096:                if (SanityManager.DEBUG) {
2097:                    SanityManager.ASSERT(isLatched());
2098:
2099:                    SanityManager.ASSERT(slot >= 0 && slot < recordCount);
2100:                }
2101:
2102:                // just copy the records down in the array (copying over the slot
2103:                // entry that is being eliminated) and null out the last entry,
2104:                // it is ok for the array to be larger than necessary.
2105:                //
2106:                // source of copy: slot + 1
2107:                // dest   of copy: slot
2108:                // length of copy: (length of array - source of copy)
2109:                System.arraycopy(headers, slot + 1, headers, slot,
2110:                        headers.length - (slot + 1));
2111:                headers[headers.length - 1] = null;
2112:
2113:                recordCount--;
2114:            }
2115:
2116:            /**
2117:            	Shift all records in the in-memory slot table up one slot,
2118:            	starting at and including the record in slot 'low'
2119:            	A new slot is added to accomdate the move.
2120:
2121:            	<BR>
2122:            	MT - latched
2123:             */
2124:            protected StoredRecordHeader shiftUp(int low) {
2125:
2126:                if (SanityManager.DEBUG) {
2127:                    SanityManager.ASSERT(isLatched());
2128:
2129:                    if ((low < 0) || (low > recordCount)) {
2130:                        SanityManager
2131:                                .THROWASSERT("shiftUp failed, low must be between 0 and recordCount."
2132:                                        + "  low = "
2133:                                        + low
2134:                                        + ", recordCount = "
2135:                                        + recordCount + "\n page = " + this );
2136:                    }
2137:                }
2138:
2139:                if (low < headers.length) {
2140:                    // just copy the records up in the array (copying over the slot
2141:                    // entry that is being eliminated) and null out the entry at "low",
2142:                    // it is ok for the array to be shorter than necessary.
2143:                    //
2144:                    // This code throws away the "last" entry in
2145:                    // the array, which will cause a record header cache miss if it 
2146:                    // is needed.  This delays the object allocation of a new array
2147:                    // object until we really need that entry, vs. doing it on the
2148:                    // insert.
2149:                    //
2150:                    // source of copy: low
2151:                    // dest   of copy: low + 1
2152:                    // length of copy: (length of array - dest of copy)
2153:
2154:                    // adding in the middle
2155:                    System.arraycopy(headers, low, headers, low + 1,
2156:                            headers.length - (low + 1));
2157:
2158:                    headers[low] = null;
2159:                }
2160:
2161:                return (null);
2162:            }
2163:
2164:            /**
2165:            	Try to compact this record.  Deleted record are treated the same way as
2166:            	nondeleted record.  This page must not be an overflow page.  The record
2167:            	may already have been purged from the page.
2168:
2169:              	<P>
2170:            	<B>Locking Policy</B>
2171:            	<P>
2172:            	No locks are obtained.
2173:
2174:            	<BR>
2175:            	MT - latched
2176:
2177:            	<P>
2178:            	<B>NOTE : CAVEAT </B><BR>
2179:            	This operation will physically get rid of any reserved space this
2180:            	record may have, or it may compact the record by merging strung out row
2181:            	pieces together.  Since the freed reserved space is immediately usable
2182:            	by other transactions which latched the page, it is only safe to use
2183:            	this operation if the caller knows that it has exclusive access to the
2184:            	page for the duration of the transaction, i.e., effectively holding a
2185:            	page lock on the page, AND that the record has no uncommitted
2186:            	updates.
2187:
2188:              @param handle Handle to deleted or non-deleted record
2189:              @see ContainerHandle#compactRecord
2190:
2191:              @exception StandardException	Standard Cloudscape error policy
2192:             */
2193:            public void compactRecord(RecordHandle handle)
2194:                    throws StandardException {
2195:                if (SanityManager.DEBUG) {
2196:                    SanityManager.ASSERT(isLatched());
2197:                }
2198:
2199:                if (!owner.updateOK()) {
2200:                    throw StandardException
2201:                            .newException(SQLState.DATA_CONTAINER_READ_ONLY);
2202:                }
2203:
2204:                if (handle.getId() < RecordHandle.FIRST_RECORD_ID) {
2205:                    throw StandardException.newException(
2206:                            SQLState.DATA_INVALID_RECORD_HANDLE, handle);
2207:                }
2208:
2209:                if (handle.getPageNumber() != getPageNumber()) {
2210:                    throw StandardException.newException(
2211:                            SQLState.DATA_WRONG_PAGE_FOR_HANDLE, handle);
2212:                }
2213:
2214:                if (isOverflowPage()) {
2215:                    throw StandardException.newException(
2216:                            SQLState.DATA_UNEXPECTED_OVERFLOW_PAGE, handle);
2217:                }
2218:
2219:                int slot = findRecordById(handle.getId(), handle
2220:                        .getSlotNumberHint());
2221:
2222:                if (slot >= 0) {
2223:                    compactRecord(owner.getTransaction(), slot, handle.getId());
2224:                }
2225:                // else record gone, no compaction necessary
2226:            }
2227:
2228:            /*
2229:             ** Methods that read/store records/fields based upon calling methods
2230:             ** a sub-calls provides to do the actual storage work.
2231:             */
2232:
2233:            /*
2234:             ** Page LastLog Instant control
2235:             */
2236:
2237:            public final LogInstant getLastLogInstant() {
2238:                return lastLog;
2239:            }
2240:
2241:            protected final void clearLastLogInstant() {
2242:                lastLog = null;
2243:            }
2244:
2245:            protected final void updateLastLogInstant(LogInstant instant) {
2246:                if (SanityManager.DEBUG) {
2247:                    SanityManager.ASSERT(isLatched());
2248:                }
2249:
2250:                // we should not null out the log instant even if this page is being
2251:                // updated by a non-logged action, there may have been logged action
2252:                // before this and we don't want to loose that pointer
2253:                if (instant != null)
2254:                    lastLog = instant;
2255:            }
2256:
2257:            /*
2258:             ** Page Version control
2259:             */
2260:
2261:            /**
2262:            	Return the current page version.
2263:             */
2264:            public final long getPageVersion() {
2265:                return pageVersion;
2266:            }
2267:
2268:            /**
2269:            	increment the version by one and return the new version.
2270:             */
2271:            protected final long bumpPageVersion() {
2272:                if (SanityManager.DEBUG) {
2273:                    SanityManager.ASSERT(isLatched());
2274:                }
2275:                return ++pageVersion;
2276:            }
2277:
2278:            /**
2279:            	set it when the page is read from disk.
2280:
2281:            	<BR> MT - single thread required - Only called while the page has no identity which
2282:            	requires that only a single caller can be accessing it.
2283:             */
2284:            public final void setPageVersion(long v) {
2285:                pageVersion = v;
2286:            }
2287:
2288:            /**
2289:            	Set page status based on passed in status flag.
2290:             */
2291:            protected void setPageStatus(byte status) {
2292:                pageStatus = status;
2293:            }
2294:
2295:            /**
2296:            	Get the page status, one of the values in the above page status flag
2297:             */
2298:            public byte getPageStatus() {
2299:                return pageStatus;
2300:            }
2301:
2302:            /*
2303:             ** abstract methods that an implementation must provide.
2304:             **
2305:             ** <BR> MT - latched, page is latched when these methods are called.
2306:             */
2307:
2308:            /**
2309:             * Read the record at the given slot into the given row.
2310:             * <P>
2311:             * This reads and initializes the columns in the row array from the raw 
2312:             * bytes stored in the page associated with the given slot.  If validColumns
2313:             * is non-null then it will only read those columns indicated by the bit
2314:             * set, otherwise it will try to read into every column in row[].  
2315:             * <P>
2316:             * If there are more columns than entries in row[] then it just stops after
2317:             * every entry in row[] is full.
2318:             * <P>
2319:             * If there are more entries in row[] than exist on disk, the requested 
2320:             * excess columns will be set to null by calling the column's object's
2321:             * restoreToNull() routine 
2322:             * (ie.  ((Object) column).restoreToNull() ).
2323:             * <P>
2324:             * If a qualifier list is provided then the row will only be read from
2325:             * disk if all of the qualifiers evaluate true.  Some of the columns may
2326:             * have been read into row[] in the process of evaluating the qualifier.
2327:             *
2328:             * <BR> MT - latched, page is latched when this methods is called.
2329:             *
2330:             *
2331:             * @param slot              the slot number
2332:             * @param row (out)         filled in sparse row
2333:             * @param fetchDesc         A set of information about the fetch: what
2334:             *                          columns to fetch, any qualifiers, ...
2335:             * @param rh                the record handle for the row at top level,
2336:             *                          and is used in OverflowInputStream to lock the 
2337:             *                          row for Blobs/Clobs.
2338:             * @param isHeadRow         Is the head row portion of the row, false if
2339:             *                          a long row and the 2-N'th portion of the long
2340:             *                          row.
2341:             *
2342:             * @return  false if a qualifier_list is provided and the row does not 
2343:             *          qualifier (no row read in that case), else true.
2344:             *
2345:             * @exception StandardException	Standard Cloudscape error policy
2346:             **/
2347:            protected abstract boolean restoreRecordFromSlot(int slot,
2348:                    Object[] row, FetchDescriptor fetchDesc, RecordHandle rh,
2349:                    StoredRecordHeader recordHeader, boolean isHeadRow)
2350:                    throws StandardException;
2351:
2352:            /**
2353:            	Read portion of a log record at the given slot into the given byteHolder.
2354:
2355:            	<BR> MT - latched, page is latched when this methods is called.
2356:
2357:
2358:            	@exception StandardException	Standard Cloudscape error policy
2359:             */
2360:            protected abstract void restorePortionLongColumn(
2361:                    OverflowInputStream fetchStream) throws StandardException,
2362:                    IOException;
2363:
2364:            /**
2365:            	Create a new record identifier.
2366:
2367:            	<BR> MT - latched, page is latched when this methods is called.
2368:
2369:            	@exception StandardException	Standard Cloudscape error policy
2370:             */
2371:            public abstract int newRecordId() throws StandardException;
2372:
2373:            /**
2374:            	Create a new record identifier, and bump to next recordid.
2375:
2376:            	<BR> MT - latched, page is latched when this methods is called.
2377:
2378:            	@exception StandardException	Standard Cloudscape error policy
2379:             */
2380:            public abstract int newRecordIdAndBump() throws StandardException;
2381:
2382:            /**
2383:            	Create a new record identifier, the passed in one is the last one created.
2384:            	Use this method to collect and reserve multiple recordIds in one
2385:            	stroke.  Given the same input recordId, the subclass MUST return the
2386:            	same recordId every time.
2387:
2388:            	<BR> MT - latched, page is latched when this methods is called.
2389:
2390:            	@exception StandardException	Standard Cloudscape error policy
2391:             */
2392:            protected abstract int newRecordId(int recordId)
2393:                    throws StandardException;
2394:
2395:            /**
2396:            	Is there space for copying this many rows which takes this many bytes
2397:            	on the page
2398:
2399:            	<BR> MT - latched, page is latched when this methods is called.
2400:
2401:            	@exception StandardException Standard Cloudscape policy.
2402:             */
2403:            public abstract boolean spaceForCopy(int num_rows, int[] spaceNeeded)
2404:                    throws StandardException;
2405:
2406:            /**
2407:            	Return the total number of bytes used, reserved, or wasted by the
2408:            	record at this slot.
2409:
2410:            	<BR> MT - latched, page is latched when this methods is called.
2411:
2412:            	@exception StandardException Standard Cloudscape policy.
2413:             */
2414:            public abstract int getTotalSpace(int slot)
2415:                    throws StandardException;
2416:
2417:            /**
2418:            	Return the total number of bytes reserved by the
2419:            	record at this slot.
2420:
2421:            	<BR> MT - latched, page is latched when this methods is called.
2422:
2423:            	@exception IOException Thrown by InputStream methods potential I/O errors
2424:             */
2425:            public abstract int getReservedCount(int slot) throws IOException;
2426:
2427:            /*
2428:             ** Methods that our super-class (BasePage) requires we implement.
2429:             ** Here we only implement the methods that correspond to the logical
2430:             ** operations that require logging, any other methods that are storage
2431:             ** specific we leave to our sub-class.
2432:             **
2433:             ** All operations that are logged must bump this page's version number
2434:             ** and update this page's last log instant.  
2435:             ** These should be sanity checked on each logAndDo (similarly, it should
2436:             ** be checked in CompensationOperation.doMe)
2437:             */
2438:
2439:            /*
2440:             ** Methods that any sub-class must implement. These allow generic log operations.
2441:             */
2442:
2443:            /**
2444:            	Get the stored length of a record. This must match the amount of data
2445:            	written by logColumn and logField.
2446:
2447:            	<BR> MT - latched - page latch must be held
2448:             */
2449:
2450:            public abstract int getRecordLength(int slot) throws IOException;
2451:
2452:            /**
2453:            	Restore a storable row from a InputStream that was used to
2454:            	store the row after a logRecord call.
2455:
2456:            	<BR> MT - latched - page latch must be held
2457:
2458:            	@exception StandardException	Standard Cloudscape error policy
2459:            	@exception IOException object exceeds the available data in the stream.
2460:
2461:             */
2462:            public abstract void restoreRecordFromStream(LimitObjectInput in,
2463:                    Object[] row) throws StandardException, IOException;
2464:
2465:            /**
2466:            	Log a currently stored record to the output stream.
2467:            	The logged version of the record must be readable by storeRecord.
2468:
2469:            	<BR> MT - latched - page latch must be held
2470:
2471:
2472:            	@param slot		Slot number the record is stored in.
2473:            	@param flag		LOG_RECORD_*, the reason for logging the record.
2474:            	@param recordId Record identifier of the record.
2475:            	@param validColumns which columns needs to be logged
2476:            	@param out		Where to write the logged form.
2477:            	@param headRowHandle	the recordHandle of the head row piece, used
2478:            					for post commit cleanup for update. 
2479:
2480:            	@exception StandardException	Standard Cloudscape error policy
2481:             */
2482:            public abstract void logRecord(int slot, int flag, int recordId,
2483:                    FormatableBitSet validColumns, OutputStream out,
2484:                    RecordHandle headRowHandle) throws StandardException,
2485:                    IOException;
2486:
2487:            /**
2488:            	Log the row that will be stored at the given slot to the given OutputStream.
2489:            	The logged form of the Row must be readable by storeRecord.
2490:
2491:            	<BR> MT - latched - page latch must be held
2492:
2493:            	@param slot				Slot number the record will be stored in.
2494:            	@param forInsert		True if the row is being logged for an insert,
2495:            							false for an update.
2496:            	@param recordId			Record identifier of the record.
2497:            	@param row				The row version of the record.
2498:            	@param validColumns		FormatableBitSet of which columns in row are valid,
2499:            							null indicates all are valid
2500:            	@param out				Where to write the logged form.
2501:            	@param startColumn		The first column that is being logged in this row.
2502:            							This is used when logging portion of long rows.
2503:            	@param insertFlag		To indicate whether the insert would allow overflow.
2504:            	@param realStartColumn	This is used when a long column is detected.
2505:            							Portion of the row may already be logged and stored
2506:            							in the 'out' buffer.  After we log the long column,
2507:            							the saved buffer was passed here, and we need to
2508:            							continue to log the row.  realStartColumn is the starting
2509:            							column for the continuation of the logRow operation.
2510:            							Pass in (-1) if realStartColumn is not significant.
2511:            	@param realSpaceOnPage	Being used in conjunction with realStartColumn,
2512:            							to indicate the real free space left on the page.
2513:
2514:            	@exception StandardException	Standard Cloudscape error policy
2515:             */
2516:            public abstract int logRow(int slot, boolean forInsert,
2517:                    int recordId, Object[] row, FormatableBitSet validColumns,
2518:                    DynamicByteArrayOutputStream out, int startColumn,
2519:                    byte insertFlag, int realStartColumn, int realSpaceOnPage,
2520:                    int overflowThreshold) throws StandardException,
2521:                    IOException;
2522:
2523:            /**
2524:            	Log a currently stored field.
2525:            	The logged version of the field must be readable by storeField.
2526:
2527:            	<BR> MT - latched - page latch must be held
2528:
2529:            	@param slot		Slot number the record is stored in.
2530:            	@param fieldNumber Number of the field (starts at 0).
2531:            	@param out		Where to write the logged form.
2532:
2533:            	@exception StandardException	Standard Cloudscape error policy
2534:             */
2535:            public abstract void logField(int slot, int fieldNumber,
2536:                    OutputStream out) throws StandardException, IOException;
2537:
2538:            /**
2539:            	Log a to be stored column.
2540:
2541:            	<BR> MT - latched - page latch must be held
2542:
2543:            	@param slot		slot of the current record
2544:            	@param fieldId	field number of the column being updated
2545:            	@param column column version of the field.
2546:            	@param out		Where to write the logged form.
2547:
2548:            	@exception StandardException	Standard Cloudscape error policy
2549:             */
2550:            public abstract void logColumn(int slot, int fieldId,
2551:                    Object column, DynamicByteArrayOutputStream out,
2552:                    int overflowThreshold) throws StandardException,
2553:                    IOException;
2554:
2555:            /**
2556:            	Log a to be stored long column.  return -1 when done.
2557:
2558:            	<BR> MT - latched - page latch must be held
2559:
2560:            	@param slot			slot of the current record
2561:            	@param recordId		the id of the long column record
2562:            	@param column		column version of the field.
2563:            	@param out			Where to write the logged form.
2564:
2565:            	@exception StandardException	Standard Cloudscape error policy
2566:             */
2567:            public abstract int logLongColumn(int slot, int recordId,
2568:                    Object column, DynamicByteArrayOutputStream out)
2569:                    throws StandardException, IOException;
2570:
2571:            /**
2572:            	Read a previously stored record written by logRecord or logRow and store
2573:            	it on the data page at the given slot with the given record identifier.
2574:            	Any previously stored record must be replaced.
2575:
2576:            	<BR> MT - latched - page latch must be held
2577:
2578:            	@exception StandardException Standard Cloudscape error policy
2579:            	@exception IOException Thrown by InputStream methods potential I/O errors
2580:            	while writing the page
2581:            	
2582:             */
2583:            public abstract void storeRecord(LogInstant instant, int slot,
2584:                    boolean forInsert, ObjectInput in)
2585:                    throws StandardException, IOException;
2586:
2587:            /**
2588:            	Read a previously stored field written by logField or logColumn and store
2589:            	it on the data page at thge given slot with the given record identifier
2590:            	and field number. Any previously stored field is replaced.
2591:
2592:            	<BR> MT - latched - page latch must be held
2593:
2594:            	@exception StandardException Standard Cloudscape error policy
2595:            	@exception IOException Thrown by InputStream methods and potential I/O errors
2596:            	while writing the page.
2597:             */
2598:            public abstract void storeField(LogInstant instant, int slot,
2599:                    int fieldId, ObjectInput in) throws StandardException,
2600:                    IOException;
2601:
2602:            /**
2603:            	Reserve the required number of bytes for the record in the specified slot.
2604:
2605:            	<BR> MT - latched - page latch must be held
2606:
2607:            	@exception StandardException Standard Cloudscape error policy
2608:            	@exception IOException Thrown by InputStream methods and potential I/O errors
2609:            	while writing the page.
2610:             */
2611:            public abstract void reserveSpaceForSlot(LogInstant instant,
2612:                    int slot, int spaceToReserve) throws StandardException,
2613:                    IOException;
2614:
2615:            /**
2616:            	Skip a previously stored field written by logField or logColumn.
2617:
2618:            	<BR> MT - latched - page latch must be held
2619:            	
2620:            	@exception StandardException Standard Cloudscape error policy
2621:            	@exception IOException Thrown by InputStream methods
2622:
2623:             */
2624:            public abstract void skipField(ObjectInput in)
2625:                    throws StandardException, IOException;
2626:
2627:            public abstract void skipRecord(ObjectInput in)
2628:                    throws StandardException, IOException;
2629:
2630:            /**
2631:            	Set the delete status of a record from the page.
2632:
2633:            	<BR> MT - latched - page latch must be held
2634:
2635:            	@param slot the slot to delete or undelete
2636:            	@param delete set delete status to this value 
2637:
2638:            	@exception StandardException Standard Cloudscape error policy
2639:            	@exception IOException IO error accessing page
2640:             */
2641:            public abstract void setDeleteStatus(LogInstant instant, int slot,
2642:                    boolean delete) throws StandardException, IOException;
2643:
2644:            /**
2645:            	Purge a record from the page.
2646:
2647:            	<BR> MT - latched - page latch must be held
2648:
2649:            	@param slot the slot to purge
2650:            	@param recordId the id of the record that is to be purged
2651:
2652:            	@exception StandardException Standard Cloudscape error policy
2653:            	@exception IOException Thrown by potential I/O errors
2654:            	while writing the page.
2655:             */
2656:            public abstract void purgeRecord(LogInstant instant, int slot,
2657:                    int recordId) throws StandardException, IOException;
2658:
2659:            /**
2660:            	Subclass implementation of compactRecord.
2661:            	@see BasePage#compactRecord
2662:            	@exception StandardException Standard Cloudscape error policy
2663:             */
2664:            protected abstract void compactRecord(RawTransaction t, int slot,
2665:                    int recordId) throws StandardException;
2666:
2667:            /**
2668:            	Set the page status underneath a log record
2669:
2670:            	<BR> MT - latched - page latch must be held
2671:
2672:            	@param instant the log instant of the log record
2673:            	@param status the page status
2674:
2675:            	@exception StandardException Standard Cloudscape error policy
2676:             */
2677:            public abstract void setPageStatus(LogInstant instant, byte status)
2678:                    throws StandardException;
2679:
2680:            /**
2681:            	initialize a page for the first time or for reuse
2682:
2683:            	All subtypes are expected to overwrite this method if it has something to clean up
2684:
2685:            	@exception StandardException Standard Cloudscape error policy
2686:             */
2687:            public abstract void initPage(LogInstant instant, byte status,
2688:                    int recordId, boolean overflow, boolean reuse)
2689:                    throws StandardException;
2690:
2691:            /**
2692:            	Set the reserved space for this row to value.
2693:            	@exception StandardException Standard Cloudscape error policy
2694:             */
2695:            public abstract void setReservedSpace(LogInstant instant, int slot,
2696:                    int value) throws StandardException, IOException;
2697:
2698:            /**
2699:            	Return true if the page is an overflow page, false if not.
2700:            	For implementation that don't have overflow pages, return false.
2701:             */
2702:            public abstract boolean isOverflowPage();
2703:
2704:            /**
2705:            	Returns false if an insert is not to be allowed in the page.
2706:             */
2707:            public abstract boolean allowInsert();
2708:
2709:            /**
2710:            	Returns true if an insert is allowed in the page and the page is
2711:            	relatively unfilled - let specific implementation decide what
2712:            	relatively unfilled means
2713:             */
2714:            public abstract boolean unfilled();
2715:
2716:            /**
2717:            	Set the number of rows in the container - the page uses this to decide
2718:            	whether it needs to aggressive set the container's row count when it
2719:            	changes. 
2720:             */
2721:            public abstract void setContainerRowCount(long count);
2722:
2723:            /*
2724:             * returns the page data array, that is actually written to the disk.
2725:             */
2726:            protected abstract byte[] getPageArray() throws StandardException;
2727:
2728:            /*
2729:             ** Debugging methods
2730:             */
2731:
2732:            /** Debugging, print slot table information */
2733:            protected String slotTableToString() {
2734:                String str = null;
2735:
2736:                if (SanityManager.DEBUG) {
2737:                    StoredRecordHeader rh;
2738:                    str = new String();
2739:
2740:                    for (int slot = FIRST_SLOT_NUMBER; slot < recordCount; slot++) {
2741:                        rh = getHeaderAtSlot(slot);
2742:                        if (rh != null)
2743:                            str += "Slot " + slot + " recordId " + rh.getId();
2744:                        else
2745:                            str += "Slot " + slot + " null record";
2746:                        str += "\n";
2747:                    }
2748:                }
2749:                return str;
2750:            }
2751:
2752:            /**
2753:            	This lockable wants to participate in the Virtual Lock table.
2754:             */
2755:            public boolean lockAttributes(int flag, Hashtable attributes) {
2756:                if (SanityManager.DEBUG) {
2757:                    SanityManager
2758:                            .ASSERT(attributes != null,
2759:                                    "cannot call lockProperties with null attribute list");
2760:                }
2761:
2762:                if ((flag & VirtualLockTable.LATCH) == 0)
2763:                    return false;
2764:
2765:                // by the time this is called, the page may be unlatched.
2766:                PageKey pageId = identity;
2767:
2768:                // not latched
2769:                if (pageId == null)
2770:                    return false;
2771:
2772:                attributes.put(VirtualLockTable.CONTAINERID, new Long(pageId
2773:                        .getContainerId().getContainerId()));
2774:                attributes.put(VirtualLockTable.LOCKNAME, pageId.toString());
2775:                attributes.put(VirtualLockTable.LOCKTYPE, "LATCH");
2776:
2777:                // don't new unecesary things for now
2778:                // attributes.put(VirtualLockTable.SEGMENTID, new Long(pageId.getContainerId().getSegmentId()));
2779:                // attributes.put(VirtualLockTable.PAGENUM, new Long(pageId.getPageNumber()));
2780:
2781:                return true;
2782:            }
2783:
2784:        }
ww__w___._ja___v___a___2__s___.c_o___m_ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.