--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.store.raw.data.CopyRowsOperation\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.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.services.io.FormatIdUtil;\r
+import org.apache.derby.iapi.services.io.StoredFormatIds;\r
+\r
+import org.apache.derby.iapi.store.raw.Page;\r
+import org.apache.derby.iapi.store.raw.RecordHandle;\r
+import org.apache.derby.iapi.store.raw.Transaction;\r
+import org.apache.derby.iapi.store.raw.log.LogInstant;\r
+import org.apache.derby.iapi.store.raw.xact.RawTransaction; \r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.services.io.CompressedNumber;\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+import org.apache.derby.iapi.util.ByteArray;\r
+import org.apache.derby.iapi.services.io.DynamicByteArrayOutputStream;\r
+\r
+\r
+import java.io.OutputStream;\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
+ Represents copying num_rows from one page to another page.\r
+\r
+ <PRE>\r
+ @format_id LOGOP_COPY_ROWS\r
+ the formatId is written by FormatIdOutputStream when this object is\r
+ written out by writeObject\r
+ @purpose copy some rows from one page to another\r
+ @upgrade\r
+ @disk_layout\r
+ PhysicalPageOperation the superclass\r
+ num_rows(CompressedInt) number of rows to copy\r
+ destSlot(CompressedInt) the first slot number at the destination page\r
+ recordIds(CompressedInt[num_rows]) the recordIds at the destination page\r
+\r
+ OptionalData the after image of the rows to be inserted into the\r
+ destination page\r
+ @end_format\r
+ </PRE>\r
+*/\r
+public class CopyRowsOperation extends PhysicalPageOperation {\r
+\r
+ protected int num_rows;\r
+ protected int destSlot; // copy into this page starting from destSlot\r
+ protected int[] recordIds; // num_rows of recordIds (use these for undo)\r
+ protected int[] reservedSpace; // number of bytes to reserve for each row.\r
+\r
+ transient protected ByteArray preparedLog; \r
+\r
+ public CopyRowsOperation(RawTransaction t, BasePage destPage, BasePage srcPage, \r
+ int destSlot, int num_rows,\r
+ int srcSlot, int[] recordIds)\r
+ throws StandardException\r
+ {\r
+ super(destPage);\r
+\r
+ this.num_rows = num_rows;\r
+ this.destSlot = destSlot;\r
+ this.recordIds = recordIds;\r
+\r
+ try {\r
+ reservedSpace = new int[num_rows];\r
+ for (int i = 0; i < num_rows; i++) {\r
+ reservedSpace[i] = srcPage.getReservedCount(i + srcSlot);\r
+ }\r
+\r
+ writeOptionalDataToBuffer(t, srcPage, srcSlot);\r
+ } catch (IOException ioe) {\r
+ throw StandardException.newException(\r
+ SQLState.DATA_UNEXPECTED_EXCEPTION, ioe);\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Formatable methods\r
+ */\r
+\r
+ // no-arg constructor, required by Formatable \r
+ public CopyRowsOperation() { super(); }\r
+/*\r
+ public CopyRowsOperation(BasePage destPage) { super(destPage); }\r
+*/\r
+ public void writeExternal(ObjectOutput out) throws IOException \r
+ {\r
+ super.writeExternal(out);\r
+\r
+ CompressedNumber.writeInt(out, num_rows);\r
+ CompressedNumber.writeInt(out, destSlot);\r
+ \r
+ for (int i = 0; i < num_rows; i++) {\r
+ CompressedNumber.writeInt(out, recordIds[i]);\r
+ CompressedNumber.writeInt(out, reservedSpace[i]);\r
+ }\r
+ }\r
+\r
+ /**\r
+ Read this in\r
+ @exception IOException error reading from log stream\r
+ @exception ClassNotFoundException log stream corrupted\r
+ */\r
+ public void readExternal(ObjectInput in) \r
+ throws IOException, ClassNotFoundException\r
+ {\r
+ super.readExternal(in);\r
+\r
+ num_rows = CompressedNumber.readInt(in);\r
+ destSlot = CompressedNumber.readInt(in);\r
+\r
+ recordIds = new int[num_rows];\r
+ reservedSpace = new int[num_rows];\r
+ for (int i = 0; i < num_rows; i++) {\r
+ recordIds[i] = CompressedNumber.readInt(in);\r
+ reservedSpace[i] = CompressedNumber.readInt(in);\r
+ }\r
+ }\r
+\r
+ /**\r
+ Return my format identifier.\r
+ */\r
+ public int getTypeFormatId() {\r
+ return StoredFormatIds.LOGOP_COPY_ROWS;\r
+ }\r
+\r
+ /*\r
+ * Loggable methods\r
+ */\r
+ /**\r
+ @exception IOException Can be thrown by any of the methods of ObjectInput.\r
+ @exception StandardException Standard Derby error policy. \r
+ \r
+ @see org.apache.derby.iapi.store.raw.Loggable#doMe\r
+ */\r
+ public void doMe(Transaction xact, LogInstant instant, LimitObjectInput in)\r
+ throws StandardException, IOException\r
+ {\r
+ /*\r
+ * this operation's do me will bump the page version by more than 1\r
+ */\r
+ for (int i = 0; i < num_rows; i++)\r
+ {\r
+ page.storeRecord(instant, destSlot+i, true, in);\r
+\r
+ if (reservedSpace[i] > 0)\r
+ page.reserveSpaceForSlot(instant, destSlot + i, reservedSpace[i]);\r
+ }\r
+ }\r
+\r
+ /*\r
+ * PhysicalPageOperation method\r
+ */\r
+\r
+ /**\r
+ to undo this operation, purge all records that were copied over.\r
+\r
+ @exception IOException Can be thrown by any of the methods of ObjectInput.\r
+ @exception StandardException Standard Derby error policy\r
+ @see PhysicalPageOperation#undoMe\r
+ */\r
+ public void undoMe(Transaction xact, BasePage undoPage,\r
+ LogInstant CLRInstant, LimitObjectInput in)\r
+ throws StandardException, IOException \r
+ {\r
+ // purge the records in the stored version\r
+ // since we search for each recordId, it doesn't matter whether we\r
+ // purge from high to low. In most cases, it will be in order so do it\r
+ // from high to low to save some work.\r
+\r
+ int slot;\r
+\r
+ for (int i = num_rows-1; i >= 0; i--)\r
+ {\r
+ slot = undoPage.findRecordById(recordIds[i], i);\r
+ undoPage.purgeRecord(CLRInstant, slot, recordIds[i]);\r
+ }\r
+\r
+ undoPage.setAuxObject(null);\r
+ }\r
+\r
+ /*\r
+ * PageBasicOperation method to support BeforeImageLogging\r
+ */\r
+\r
+ /**\r
+ * restore the before image of the page\r
+ *\r
+ * @exception IOException problem reading the complete log record from the input stream\r
+ * @exception StandardException Standard Derby Error Policy\r
+ */\r
+ public void restoreMe(Transaction xact, BasePage undoPage,\r
+ LogInstant CLRInstant, LimitObjectInput in)\r
+ throws StandardException, IOException \r
+ {\r
+ undoMe(xact, undoPage, CLRInstant, in);\r
+ }\r
+\r
+ /*\r
+ methods to support prepared log\r
+ \r
+ the following two methods should not be called during recover\r
+ */\r
+\r
+ public ByteArray getPreparedLog()\r
+ {\r
+ return (this.preparedLog);\r
+ }\r
+\r
+ /**\r
+ Write the rows that are to be copied into this page\r
+\r
+ @exception IOException Can be thrown by any of the methods of ObjectOutput.\r
+ @exception StandardException Standard Derby policy. \r
+\r
+ */\r
+ private void writeOptionalDataToBuffer(RawTransaction t, BasePage srcPage, int srcSlot)\r
+ throws StandardException, IOException\r
+ {\r
+ if (SanityManager.DEBUG) {\r
+ SanityManager.ASSERT(this.page != null);\r
+ SanityManager.ASSERT(srcPage != null);\r
+ }\r
+\r
+ DynamicByteArrayOutputStream logBuffer = t.getLogBuffer();\r
+ int optionalDataStart = logBuffer.getPosition();\r
+\r
+ if (SanityManager.DEBUG) {\r
+ SanityManager.ASSERT(optionalDataStart == 0,\r
+ "Buffer for writing the optional data should start at position 0");\r
+ }\r
+\r
+ // check to make sure the destination page have the necessary space to\r
+ // take the rows\r
+ int[] spaceNeeded = new int[num_rows];\r
+ int startPosition = logBuffer.getPosition();\r
+\r
+ for (int i = 0; i < num_rows; i++)\r
+ {\r
+ // the recordId passed in is the record Id this row will have at\r
+ // the destination page, not the record Id this row has on the\r
+ // srcPage.\r
+ srcPage.logRecord(i + srcSlot, BasePage.LOG_RECORD_DEFAULT,\r
+ recordIds[i], (FormatableBitSet) null, logBuffer,\r
+ (RecordHandle)null);\r
+ spaceNeeded[i] = logBuffer.getPosition() - startPosition;\r
+ startPosition = logBuffer.getPosition();\r
+\r
+ // now spaceNeeded[i] has the actual record size. However, the src\r
+ // page may actually leave more space for the record due to\r
+ // reserved space. Because we want to copy the reserve space as well,\r
+ // we need to take into account that amount.\r
+ spaceNeeded[i] += reservedSpace[i];\r
+ }\r
+\r
+ // page is the destination page.\r
+ if (!page.spaceForCopy(num_rows, spaceNeeded))\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.DATA_NO_SPACE_FOR_RECORD);\r
+ }\r
+\r
+ int optionalDataLength = logBuffer.getPosition() - optionalDataStart;\r
+ \r
+ if (SanityManager.DEBUG) {\r
+ if (optionalDataLength != logBuffer.getUsed())\r
+ SanityManager.THROWASSERT("wrong optional data length, optionalDataLength = "\r
+ + optionalDataLength + ", logBuffer.getUsed() = " + logBuffer.getUsed());\r
+ }\r
+\r
+ // set the position to the beginning of the buffer\r
+ logBuffer.setPosition(optionalDataStart);\r
+\r
+ this.preparedLog = new ByteArray(logBuffer.getByteArray(), optionalDataStart,\r
+ optionalDataLength);\r
+ }\r
+\r
+ /**\r
+ DEBUG: Print self.\r
+ */\r
+ public String toString()\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ String str = super.toString() +\r
+ "CopyRows : " + num_rows + " to slots starting at " + destSlot;\r
+\r
+ for (int i = 0; i < num_rows; i++)\r
+ {\r
+ str += " (recordId=" + recordIds[i] + ")";\r
+ }\r
+ return str;\r
+ }\r
+ else\r
+ return null;\r
+ }\r
+}\r