001: /*
002:
003: Derby - Class org.apache.derby.impl.store.raw.log.LogRecord
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.log;
023:
024: import org.apache.derby.iapi.reference.SQLState;
025:
026: import org.apache.derby.iapi.services.sanity.SanityManager;
027: import org.apache.derby.iapi.services.io.FormatIdUtil;
028: import org.apache.derby.iapi.services.io.StoredFormatIds;
029: import org.apache.derby.iapi.services.io.Formatable;
030:
031: import org.apache.derby.iapi.error.StandardException;
032:
033: import org.apache.derby.iapi.store.raw.Loggable;
034: import org.apache.derby.iapi.store.raw.Compensation;
035: import org.apache.derby.iapi.store.raw.RePreparable;
036: import org.apache.derby.iapi.store.raw.Undoable;
037:
038: import org.apache.derby.iapi.store.raw.xact.TransactionId;
039:
040: import org.apache.derby.iapi.services.io.CompressedNumber;
041:
042: import java.io.ObjectOutput;
043: import java.io.ObjectInput;
044: import java.io.IOException;
045:
046: /**
047: The log record written out to disk. This log record includes:
048: <P>
049: The is a holder object that may be setup using the setValue() and re-used
050: rather than creating a new object for each actual log record.
051:
052: <P> <PRE>
053: The format of a log record is
054:
055: @format_id LOG_RECORD
056: the formatId is written by FormatIdOutputStream when this object is
057: written out by writeObject
058: @purpose The log record described every change to the persistent store
059: @upgrade
060: @disk_layout
061: loggable group(CompressedInt) the loggable's group value
062: xactId(TransactionId) The Transaction this log belongs to
063: op(Loggable) the log operation
064: @end_format
065: </PRE>
066:
067: */
068: public class LogRecord implements Formatable {
069:
070: private TransactionId xactId; // the transaction Id
071: private Loggable op; // the loggable
072: private int group; // the loggable's group value
073:
074: // the objectInput stream that contains the loggable object. The
075: // objectification of the transaction Id and the the loggable object is
076: // delayed from readExternal time to getTransactionId and getLoggable time
077: // to give the log scan an opportunity to discard the loggable based on
078: // group value and xactId.
079: transient ObjectInput input;
080:
081: private static final int formatLength = FormatIdUtil
082: .getFormatIdByteLength(StoredFormatIds.LOG_RECORD);
083:
084: public LogRecord() {
085: }
086:
087: /*
088: * Formatable methods
089: */
090:
091: /**
092: Write this out.
093: @exception IOException error writing to log stream
094: */
095: public void writeExternal(ObjectOutput out) throws IOException {
096: CompressedNumber.writeInt(out, group);
097: out.writeObject(xactId);
098: out.writeObject(op);
099: }
100:
101: /**
102: Read this in
103: @exception IOException error reading from log stream
104: @exception ClassNotFoundException corrupted log stream
105: */
106: public void readExternal(ObjectInput in) throws IOException,
107: ClassNotFoundException {
108: group = CompressedNumber.readInt(in);
109: input = in; // tie the input to this logRecord
110:
111: xactId = null; // delay reading these until later
112: op = null;
113: }
114:
115: /**
116: Return my format identifier.
117: */
118: public int getTypeFormatId() {
119: return StoredFormatIds.LOG_RECORD;
120: }
121:
122: /*
123: * class specific methods
124: */
125: public void setValue(TransactionId xactId, Loggable op) {
126: this .xactId = xactId;
127: this .op = op;
128:
129: this .group = op.group();
130: }
131:
132: public static int formatOverhead() {
133: return formatLength;
134: }
135:
136: public static int maxGroupStoredSize() {
137: return CompressedNumber.MAX_INT_STORED_SIZE;
138: }
139:
140: public static int maxTransactionIdStoredSize(TransactionId tranId) {
141: return tranId.getMaxStoredSize();
142: }
143:
144: public static int getStoredSize(int group, TransactionId xactId) {
145:
146: if (SanityManager.DEBUG) {
147: SanityManager.ASSERT(xactId == null,
148: "size calculation are based on xactId being null");
149: }
150:
151: return formatLength
152: + CompressedNumber.sizeInt(group)
153: + FormatIdUtil
154: .getFormatIdByteLength(StoredFormatIds.NULL_FORMAT_ID);
155: }
156:
157: public TransactionId getTransactionId() throws IOException,
158: ClassNotFoundException {
159: if (xactId != null)
160: return xactId;
161:
162: if (SanityManager.DEBUG)
163: SanityManager
164: .ASSERT(input != null,
165: "xactId not objectified but object input is not set");
166:
167: Object obj = input.readObject();
168: if (SanityManager.DEBUG) {
169: SanityManager.ASSERT(obj instanceof TransactionId,
170: "log record not getting expected TransactionId");
171: }
172: xactId = (TransactionId) obj;
173:
174: return xactId;
175: }
176:
177: public Loggable getLoggable() throws IOException,
178: ClassNotFoundException {
179:
180: if (op != null) // If log operation is already objectified,
181: return op; // then just return it.
182:
183: if (SanityManager.DEBUG)
184: SanityManager
185: .ASSERT(input != null,
186: "logop not objectified but object input is not set");
187:
188: if (xactId == null) // xactId is not read off yet
189: {
190: xactId = (TransactionId) input.readObject();
191: }
192:
193: Object obj = input.readObject();
194:
195: if (SanityManager.DEBUG) {
196: if (!(obj instanceof Loggable))
197: SanityManager
198: .THROWASSERT("log record not getting expected Loggable: got : "
199: + obj.getClass().getName());
200: }
201: op = (Loggable) obj;
202:
203: input = null;
204:
205: return op;
206: }
207:
208: public RePreparable getRePreparable() throws IOException,
209: ClassNotFoundException {
210: return ((RePreparable) getLoggable());
211: }
212:
213: /**
214: Skip over the loggable. Set the input stream to point ot after the
215: loggable as if the entire log record has been sucked in by the log
216: record
217:
218: @exception StandardException if the loggable is not found, log is corrupt
219: */
220: public void skipLoggable() throws StandardException {
221: if (op != null) // loggable already read off
222: return;
223:
224: try {
225: if (xactId == null)
226: xactId = (TransactionId) input.readObject(); // get rid of the transactionId
227:
228: if (op == null)
229: op = (Loggable) input.readObject(); // get rid of the loggable
230: } catch (ClassNotFoundException cnfe) {
231: throw StandardException.newException(
232: SQLState.LOG_CORRUPTED, cnfe);
233: } catch (IOException ioe) {
234: throw StandardException.newException(
235: SQLState.LOG_CORRUPTED, ioe);
236: }
237: }
238:
239: public Undoable getUndoable() throws IOException,
240: ClassNotFoundException {
241: if (op == null)
242: getLoggable(); // objectify it
243:
244: if (op instanceof Undoable)
245: return (Undoable) op;
246: else
247: return null;
248: }
249:
250: public boolean isCLR() {
251: return ((group & Loggable.COMPENSATION) != 0);
252: }
253:
254: public boolean isFirst() {
255: return ((group & Loggable.FIRST) != 0);
256: }
257:
258: public boolean isComplete() {
259: return ((group & Loggable.LAST) != 0);
260: }
261:
262: public boolean isPrepare() {
263: return ((group & Loggable.PREPARE) != 0);
264: }
265:
266: public boolean requiresPrepareLocks() {
267: return ((group & Loggable.XA_NEEDLOCK) != 0);
268: }
269:
270: public boolean isCommit() {
271: if (SanityManager.DEBUG) {
272: SanityManager.ASSERT(
273: (group & Loggable.LAST) == Loggable.LAST,
274: "calling isCommit on log record that is not last");
275: SanityManager
276: .ASSERT(
277: (group & (Loggable.COMMIT | Loggable.ABORT)) != 0,
278: "calling isCommit on log record before commit status is recorded");
279: }
280: return ((group & Loggable.COMMIT) != 0);
281: }
282:
283: public boolean isAbort() {
284: if (SanityManager.DEBUG) {
285: SanityManager.ASSERT(
286: (group & Loggable.LAST) == Loggable.LAST,
287: "calling isAbort on log record that is not last");
288: SanityManager
289: .ASSERT(
290: (group & (Loggable.COMMIT | Loggable.ABORT)) != 0,
291: "calling isAbort on log record before abort status is recorded");
292: }
293: return ((group & Loggable.ABORT) != 0);
294: }
295:
296: public int group() {
297: return group;
298: }
299:
300: public boolean isChecksum() {
301: return ((group & Loggable.CHECKSUM) != 0);
302: }
303: }
|