001: /*
002:
003: Derby - Class org.apache.derby.impl.store.raw.data.LogicalUndoOperation
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.store.raw.data;
023:
024: import org.apache.derby.impl.store.raw.data.BasePage;
025:
026: import org.apache.derby.iapi.services.io.FormatIdUtil;
027: import org.apache.derby.iapi.services.io.StoredFormatIds;
028: import org.apache.derby.iapi.services.sanity.SanityManager;
029:
030: import org.apache.derby.iapi.store.raw.Compensation;
031: import org.apache.derby.iapi.store.raw.Loggable;
032: import org.apache.derby.iapi.store.raw.Transaction;
033: import org.apache.derby.iapi.store.raw.Undoable;
034:
035: import org.apache.derby.iapi.store.raw.log.LogInstant;
036:
037: import org.apache.derby.iapi.error.StandardException;
038:
039: import org.apache.derby.iapi.services.io.CompressedNumber;
040: import org.apache.derby.iapi.util.ByteArray;
041:
042: import java.io.OutputStream;
043: import java.io.ObjectOutput;
044: import java.io.ObjectInput;
045: import java.io.IOException;
046:
047: import org.apache.derby.iapi.services.io.LimitObjectInput;
048:
049: /**
050: LogicalUndoOperation is a compensation operation that rolls back the change of
051: an LogicalUndoable operation. A LogicalUndoOperation itself is not undo-able, i.e,
052: it is loggable but not undoable.
053:
054: <PRE>
055: @format_id LOGOP_PAGE_LOGICAL_UNDO
056: the formatId is written by FormatIdOutputStream when this object is
057: written out by writeObject
058: @purpose undo a logical log operation
059: @upgrade
060: @disk_layout
061: PageBasicOperation the super class
062: recordId(CompressedInt) the recordId of the changed row (this may not
063: be the recordId during rollback if the record moved from one
064: page to another)
065: OptionalData none (compensation operation never have optional data)
066: @end_format
067: </PRE>
068:
069: */
070: public class LogicalUndoOperation extends PageBasicOperation implements
071: Compensation {
072:
073: protected int recordId; // the record id to call undoOp.undoMe with
074:
075: /** The operation to be rolled back */
076: transient private LogicalPageOperation undoOp = null;
077:
078: protected LogicalUndoOperation(BasePage page) {
079: super (page);
080: }
081:
082: /** Set up a compensation operation during run time rollback */
083: public LogicalUndoOperation(BasePage page, int recordId,
084: LogicalPageOperation op) {
085: super (page);
086: undoOp = op;
087: this .recordId = recordId;
088: }
089:
090: /**
091: Return my format identifier.
092: */
093:
094: // no-arg constructor, required by Formatable
095: public LogicalUndoOperation() {
096: super ();
097: }
098:
099: public int getTypeFormatId() {
100: return StoredFormatIds.LOGOP_PAGE_LOGICAL_UNDO;
101: }
102:
103: /**
104: Write this out.
105: @exception IOException error writing to log stream
106: */
107: public void writeExternal(ObjectOutput out) throws IOException {
108: super .writeExternal(out);
109: CompressedNumber.writeInt(out, recordId);
110: }
111:
112: /**
113: Read this in
114: @exception IOException error reading from log stream
115: @exception ClassNotFoundException log stream corrupted
116: */
117: public void readExternal(ObjectInput in) throws IOException,
118: ClassNotFoundException {
119: super .readExternal(in);
120: recordId = CompressedNumber.readInt(in);
121: }
122:
123: public void restoreMe(Transaction xact, BasePage undoPage,
124: LogInstant CLRinstant, LimitObjectInput in) {
125: // Not undoable
126: if (SanityManager.DEBUG)
127: SanityManager
128: .THROWASSERT("cannot call restore me on PhysicalUndoOperation");
129: }
130:
131: /**
132: Compensation methods
133: */
134:
135: /** Set up a LogicalOperation during recovery redo. */
136: public void setUndoOp(Undoable op) {
137: if (SanityManager.DEBUG) {
138: SanityManager.ASSERT(op instanceof LogicalPageOperation);
139: }
140:
141: undoOp = (LogicalPageOperation) op;
142: }
143:
144: /**
145: Loggable methods
146: */
147:
148: /** Apply the undo operation, in this implementation of the
149: RawStore, it can only call the undoMe method of undoOp
150:
151: @param xact the Transaction that is doing the rollback
152: @param instant the log instant of this undo operation
153: @param in optional data
154:
155: @exception IOException Can be thrown by any of the methods of ObjectInput.
156: @exception StandardException Standard Cloudscape policy.
157:
158: */
159: public final void doMe(Transaction xact, LogInstant instant,
160: LimitObjectInput in) throws StandardException, IOException {
161:
162: long oldversion = 0; // sanity check
163: LogInstant oldLogInstant = null; // sanity check
164: if (SanityManager.DEBUG) {
165: oldLogInstant = this .page.getLastLogInstant();
166: oldversion = this .page.getPageVersion();
167:
168: SanityManager.ASSERT(oldversion == this .getPageVersion());
169: SanityManager.ASSERT(oldLogInstant == null
170: || instant == null
171: || oldLogInstant.lessThan(instant));
172: }
173:
174: // if this is called during runtime rollback, PageOp.generateUndo found
175: // the page and have it latched there.
176: // if this is called during recovery redo, this.needsRedo found the page and
177: // have it latched here
178: //
179: // in either case, this.page is the correct page and is latched.
180: //
181: // recordId is generated by generateUndo and is stored here. If this
182: // is a physical undo, recordId is identical to that which is stored in
183: // undoOp. If this is logical undo, it will be different if this.page
184: // is different from the undoOp's page (which is where the rollfoward
185: // change went to, and the record might have moved by now).
186: //
187: undoOp.undoMe(xact, this .page, recordId, instant, in);
188:
189: if (SanityManager.DEBUG) {
190: SanityManager.ASSERT(oldversion < this .page
191: .getPageVersion());
192: SanityManager.ASSERT(instant == null
193: || instant.equals(this .page.getLastLogInstant()));
194: }
195:
196: releaseResource(xact);
197: }
198:
199: /* make sure resource found in undoOp is released */
200: public void releaseResource(Transaction xact) {
201: if (undoOp != null)
202: undoOp.releaseResource(xact);
203: super .releaseResource(xact);
204: }
205:
206: /* Undo operation is a COMPENSATION log operation */
207: public int group() {
208: return super .group() | Loggable.COMPENSATION
209: | Loggable.RAWSTORE;
210: }
211:
212: public final ByteArray getPreparedLog() {
213: // should never ever write optional data because this implementation of
214: // the recovery system will never read this and pass this on to dome.
215: // Instead, the optional data of the undoOp will be used - since
216: // this.doMe can only call undoOP.undoMe, this has no use for any
217: // optional data.
218: return (ByteArray) null;
219: }
220:
221: /**
222: DEBUG: Print self.
223: */
224: public String toString() {
225: if (SanityManager.DEBUG) {
226: String str = "CLR : (logical undo) " + super .toString()
227: + " undoRecordId = " + recordId;
228: if (undoOp != null)
229: str += "\n" + undoOp.toString();
230: else
231: str += " undo Operation not set";
232: return str;
233: } else
234: return null;
235: }
236:
237: }
|