--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.store.raw.data.PageBasicOperation\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.store.raw.data;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.impl.store.raw.data.BasePage;\r
+\r
+import org.apache.derby.iapi.store.raw.ContainerHandle;\r
+import org.apache.derby.iapi.store.raw.LockingPolicy;\r
+import org.apache.derby.iapi.store.raw.Loggable;\r
+import org.apache.derby.iapi.store.raw.Page;\r
+import org.apache.derby.iapi.store.raw.RePreparable;\r
+import org.apache.derby.iapi.store.raw.Transaction;\r
+import org.apache.derby.iapi.store.raw.PageKey;\r
+\r
+import org.apache.derby.iapi.store.raw.xact.RawTransaction;\r
+import org.apache.derby.iapi.store.raw.data.RawContainerHandle;\r
+import org.apache.derby.iapi.store.raw.log.LogInstant;\r
+import org.apache.derby.iapi.store.raw.RawStoreFactory;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+\r
+import org.apache.derby.iapi.services.io.CompressedNumber;\r
+import org.apache.derby.iapi.util.ByteArray;\r
+import org.apache.derby.iapi.services.io.DynamicByteArrayOutputStream;\r
+import org.apache.derby.iapi.services.property.PropertyUtil;\r
+\r
+import java.io.InputStream;\r
+import java.io.ObjectOutput;\r
+import java.io.ObjectInput;\r
+import java.io.IOException;\r
+import org.apache.derby.iapi.services.io.LimitObjectInput;\r
+\r
+/**\r
+ A PageBasicOperation changed the content of a page, this is the root class of all\r
+ page oriented operation. Each PageBasicOperation record change(s)\r
+ that apply to <B>one and only one page</B>. The pageID that is changed\r
+ must be recorded in the log operation - in other words, redo\r
+ must be physical (or more correctly, in Gray's term, physiological, since\r
+ changes are logical <B>within</B> a page).\r
+ <BR>Undo can be logical, but the undo logic must be hidden in\r
+ generateUndo. By the time a compensation operation is logged as a\r
+ LogOperation, the page that needs roll back must be determined.\r
+\r
+ <PRE>\r
+ @format_id no format id, an abstract class.\r
+ @purpose provide methods for logical undo\r
+ @upgrade\r
+ @disk_layout\r
+ pageId(PageKey) the page this operation applies to\r
+ pageVersion(CompressedLong) the page version this operation applied to\r
+ OptionalData none\r
+ @end_format\r
+ </PRE>\r
+\r
+ @see Loggable\r
+*/\r
+\r
+public abstract class PageBasicOperation implements Loggable, RePreparable \r
+{\r
+\r
+\r
+ /* page info this operation changed */\r
+ private PageKey pageId;\r
+ private long pageVersion;\r
+\r
+\r
+ /* runtime page and data necessary to maintain it */\r
+ transient protected BasePage page;\r
+ transient protected RawContainerHandle containerHdl;\r
+ transient protected boolean foundHere;\r
+\r
+ protected PageBasicOperation(BasePage page) \r
+ {\r
+ if (SanityManager.DEBUG) \r
+ {\r
+ SanityManager.ASSERT(\r
+ page != null, \r
+ "cannot create page operation on a null page pointer");\r
+ }\r
+\r
+ // runtime info\r
+ this.page = page;\r
+\r
+ // info which will be logged.\r
+ pageId = page.getPageId();\r
+ pageVersion = page.getPageVersion();\r
+ }\r
+\r
+ // no-arg constructor, required by Formatable\r
+ public PageBasicOperation() \r
+ {\r
+ }\r
+\r
+ public String toString()\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ return "Page Operation: " + pageId.toString() +\r
+ " pageVersion " + pageVersion + " : ";\r
+ }\r
+ else\r
+ return null;\r
+ }\r
+\r
+ /*\r
+ * Formatable methods\r
+ */\r
+\r
+\r
+ public void writeExternal(ObjectOutput out) throws IOException\r
+ {\r
+ pageId.writeExternal(out);\r
+ CompressedNumber.writeLong(out, pageVersion);\r
+ }\r
+\r
+ public void readExternal(ObjectInput in) \r
+ throws IOException, ClassNotFoundException\r
+ {\r
+ pageId = PageKey.read(in);\r
+\r
+ pageVersion = CompressedNumber.readLong(in);\r
+ }\r
+\r
+ /*\r
+ * Loggable methods\r
+ */\r
+\r
+ /** Returns true if this op should be redone during recovery redo,\r
+ if so, get and latched the page.\r
+\r
+ @exception StandardException Standard Derby policy.\r
+ */\r
+ public final boolean needsRedo(Transaction xact)\r
+ throws StandardException\r
+ {\r
+ if (findpage(xact) == null) // committed dropped container\r
+ return false;\r
+\r
+ long pversion = page.getPageVersion();\r
+ if (pversion == pageVersion)\r
+ return true;\r
+\r
+ releaseResource(xact);\r
+\r
+ if (pversion > pageVersion)\r
+ return false;\r
+ else\r
+ throw StandardException.newException(\r
+ SQLState.DATA_MISSING_LOG, pageId, \r
+ new Long(pversion), \r
+ new Long(pageVersion));\r
+ }\r
+\r
+ /** Release latched page and any other resources acquired during a previous\r
+ findpage, safe to call multiple times.\r
+\r
+ In this RawStore implementataion, resource is acquired by a log\r
+ operation in one of two places\r
+ <nl>\r
+ <li> during runtime or recovery undo in PageOperation.generateUndo()\r
+ <li> during recovery redo in PageBasicOperation.needsRedo()\r
+ </nl>\r
+ */\r
+ public void releaseResource(Transaction xact)\r
+ {\r
+ if (!foundHere) // don't release anything not found by this\r
+ return;\r
+\r
+ if (page != null)\r
+ {\r
+ page.unlatch();\r
+ page = null;\r
+ }\r
+\r
+ if (containerHdl != null)\r
+ {\r
+ containerHdl.close();\r
+ containerHdl = null;\r
+ }\r
+\r
+ foundHere = false;\r
+ }\r
+\r
+ /**\r
+ A page operation is a RAWSTORE log record\r
+ */\r
+ public int group()\r
+ {\r
+ return(Loggable.RAWSTORE | Loggable.XA_NEEDLOCK);\r
+ }\r
+\r
+ /**\r
+ the default for optional data is set to null. If an operation has optional data,\r
+ the operation need to prepare the optional data for this method.\r
+\r
+ WARNING: If a log operation extends this class, and the operation has optional data,\r
+ it MUST overwrite this method to return a ByteArray that contains the optional data. \r
+\r
+ @exception StandardException Standard Derby policy.\r
+ */\r
+ public ByteArray getPreparedLog() throws StandardException\r
+ {\r
+ return (ByteArray) null;\r
+ }\r
+\r
+ /**************************************************************************\r
+ * Public Methods of RePreparable Interface:\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ * reclaim locks associated with the changes in this log record.\r
+ * <p>\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public void reclaimPrepareLocks(\r
+ Transaction t,\r
+ LockingPolicy locking_policy)\r
+ throws StandardException\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.DEBUG_PRINT("", "PageBasicOperation.reclaimPrepareLocks().");\r
+ }\r
+\r
+ /*\r
+ * Methods specific to this class\r
+ */\r
+ \r
+ /**\r
+ Reset the pageNumber\r
+ */\r
+ protected final void resetPageNumber(long pageNumber)\r
+ {\r
+ pageId = new PageKey(pageId.getContainerId(), pageNumber);\r
+ }\r
+\r
+ protected final PageKey getPageId() {\r
+ return pageId;\r
+ }\r
+\r
+ /** Find the page the operation applies to and latch it, this only\r
+ uses the segmentId, containerId, and pageId stored in this log\r
+ record to find the page.\r
+\r
+ @return null if container is dropped and committed (possibly\r
+ stubbified), else return the latched page\r
+\r
+ @exception StandardException Standard Derby policy.\r
+ */\r
+ public final BasePage findpage(Transaction xact) throws StandardException \r
+ {\r
+ releaseResource(xact);\r
+\r
+ RawTransaction rtran = (RawTransaction)xact;\r
+ containerHdl = rtran.openDroppedContainer(pageId.getContainerId(),\r
+ (LockingPolicy) null);\r
+\r
+ if (containerHdl == null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.DATA_CONTAINER_VANISHED, pageId.getContainerId());\r
+ }\r
+\r
+ foundHere = true;\r
+\r
+ // if container is dropped and committed, cannot look at any page, \r
+ // it may be a container stub\r
+ if (containerHdl.getContainerStatus() == RawContainerHandle.COMMITTED_DROP)\r
+ {\r
+ releaseResource(xact);\r
+ return null;\r
+ }\r
+\r
+ StandardException getPageException = null;\r
+ try\r
+ {\r
+ // get and latch page - we don't know the status of the page or what\r
+ // kind of page we are looking for, get any type of page\r
+ page = (BasePage)(containerHdl.getAnyPage(pageId.getPageNumber()));\r
+ }\r
+ catch (StandardException se)\r
+ {\r
+ getPageException = se;\r
+ }\r
+ \r
+ //Try to initialize the page if page not found exception occurs during\r
+ //recovery and the page version is zero(Init Page).\r
+ //We do this if derby.storage.patchInitPageRecoverError is set.\r
+ if (page == null && getPageException != null && pageVersion == 0)\r
+ if (PropertyUtil.getSystemBoolean(RawStoreFactory.PATCH_INITPAGE_RECOVER_ERROR))\r
+ page = getPageForRedoRecovery(xact);\r
+ \r
+ // maybe we are in rollforward recovery and this is an init page operation,\r
+ // give subclass a chance to create the page\r
+ if (page == null && getPageException != null)\r
+ {\r
+ //if are rolloforward recovery reload the page using load tran methods\r
+ //that initialize the page. because in rollforward recovery, we \r
+ //might be actually recreating the page container did not exist \r
+ //in the backup when we started the rollforward recovery.\r
+\r
+ if (rtran.inRollForwardRecovery())\r
+ {\r
+ if (SanityManager.DEBUG) \r
+ if(SanityManager.DEBUG_ON("LoadTran"))\r
+ SanityManager.DEBUG_PRINT(\r
+ "Trace", "got null page " + pageId + \r
+ " and getPageException, attempt last ditch effort");\r
+\r
+ page = getPageForRedoRecovery(xact);\r
+ \r
+ if (SanityManager.DEBUG) \r
+ if(SanityManager.DEBUG_ON("LoadTran"))\r
+ SanityManager.DEBUG_PRINT(\r
+ "Trace"," getPageForRedoRecovery, got page=" + \r
+ (page != null));\r
+ } \r
+ }\r
+\r
+ if (page == null)\r
+ {\r
+ if (getPageException != null)\r
+ {\r
+ throw getPageException; // that is the original error\r
+ }\r
+ else\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.DATA_MISSING_PAGE, pageId);\r
+ }\r
+ }\r
+\r
+ return page;\r
+ }\r
+\r
+ /**\r
+ Subclass (e.g., init page) that wishes to do something about missing\r
+ pages in load tran should override this method to return the page\r
+\r
+ @exception StandardException Derby Standard error policy\r
+ */\r
+ protected BasePage getPageForRedoRecovery(Transaction xact)\r
+ throws StandardException\r
+ {\r
+ return null;\r
+ }\r
+\r
+ public final Page getPage() {\r
+ return page;\r
+ }\r
+\r
+ public final long getPageVersion() {\r
+ return pageVersion;\r
+ }\r
+\r
+\r
+ /**\r
+ Undo the change indicated by this log operation and optional data.\r
+ The page the undo should apply to is the latched undoPage.\r
+ The undoPage must be the same page as the doMe page and the undo\r
+ operation must restore the before image of the row that changed. \r
+\r
+ <BR> this can only be used under special circumstances: namely\r
+ table level locking, and no internal or nested transaction, and all\r
+ operations are rollec back with restoreMe instead of undoMe.\r
+\r
+ <BR><B>This method is here to support BeforeImageLogging</B>\r
+\r
+ @param xact the Transaction doing the rollback\r
+ @param undoPage the page to rollback changes on\r
+ @param CLRinstant the log instant of this (PageUndo) operation\r
+ @param in optional data for the rollback operation\r
+\r
+ @exception IOException Can be thrown by any of the methods of ObjectInput.\r
+ @exception StandardException Standard Derby policy. \r
+ */\r
+ abstract public void restoreMe(Transaction xact, BasePage undoPage,\r
+ LogInstant CLRinstant, LimitObjectInput in) \r
+ throws StandardException, IOException;\r
+\r
+\r
+}\r