Source code: org/apache/derby/impl/store/raw/data/ContainerOperation.java
1 /*
2
3 Derby - Class org.apache.derby.impl.store.raw.data.ContainerOperation
4
5 Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable.
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11 http://www.apache.org/licenses/LICENSE-2.0
12
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18
19 */
20
21 package org.apache.derby.impl.store.raw.data;
22
23 import org.apache.derby.iapi.services.io.FormatIdUtil;
24 import org.apache.derby.iapi.services.io.StoredFormatIds;
25 import org.apache.derby.iapi.services.sanity.SanityManager;
26
27 import org.apache.derby.iapi.store.raw.Compensation;
28 import org.apache.derby.iapi.store.raw.ContainerHandle;
29 import org.apache.derby.iapi.store.raw.LockingPolicy;
30 import org.apache.derby.iapi.store.raw.Transaction;
31 import org.apache.derby.iapi.store.raw.Undoable;
32
33 import org.apache.derby.iapi.store.raw.xact.RawTransaction;
34 import org.apache.derby.iapi.store.raw.data.RawContainerHandle;
35 import org.apache.derby.iapi.store.raw.log.LogInstant;
36
37 import org.apache.derby.iapi.error.StandardException;
38
39 import org.apache.derby.iapi.util.ByteArray;
40
41 import java.io.ObjectOutput;
42 import java.io.InputStream;
43 import java.io.ObjectInput;
44 import java.io.IOException;
45 import org.apache.derby.iapi.services.io.LimitObjectInput;
46
47 /**
48 Log operation to create, drop or remove a container.
49
50 Both the doMe or the undoMe of a create actually caused the container
51 header to be modified and flushed before the log record is flushed. This
52 is necessary for 2 reasons, one is that of ensuring enough disk space, and
53 the other is because unlike any other operation, the log record create
54 container is in the log stream before the container is in the container
55 cache. What this mean is that if a checkpoint started after the container
56 operation but before the container is kept or is dirtied in the container
57 cache, then checkpoint will not know to wait for the container to be kept
58 or cleaned. The checkpoint will erroneous assume that the operation does
59 not need to be redone since its log instant is before the checkpoint but in
60 fact the change has not been flushed to disk.
61
62 A drop or remove container does not have this problem. The container exist
63 and is in kept state when the operation is logged so the checkpoint will
64 not overlook it and it doesn't need to flush the container header. In the
65 case of remove, the stub is flushed for a different reason - that of
66 ensuring disk space.
67
68 */
69 public class ContainerOperation extends ContainerBasicOperation implements Undoable
70 {
71 protected byte operation; // create, drop, or remove
72
73 // in previous version of contianerOperation, there may not
74 // be a createByteArray
75 transient protected boolean hasCreateByteArray = true;
76
77 protected ByteArray createByteArray; // information necessary to
78 // recreate the container
79
80 protected static final byte CREATE = (byte)1;
81 protected static final byte DROP = (byte)2;
82 protected static final byte REMOVE = (byte)4;
83
84 protected ContainerOperation(RawContainerHandle hdl, byte operation)
85 throws StandardException
86 {
87 super(hdl);
88 this.operation = operation;
89 }
90
91 /*
92 * Formatable methods
93 */
94
95 // no-arg constructor, required by Formatable
96 public ContainerOperation() { super(); }
97
98 public void writeExternal(ObjectOutput out) throws IOException
99 {
100 super.writeExternal(out);
101 out.writeByte(operation);
102
103 if (operation == CREATE)
104 {
105 try
106 {
107 createByteArray = containerHdl.logCreateContainerInfo();
108 }
109 catch (StandardException se)
110 {
111 throw new IOException(se.toString());
112 }
113
114 createByteArray.writeExternal(out);
115 }
116 }
117
118 /**
119 @exception IOException cannot read log record from log stream
120 @exception ClassNotFoundException cannot read ByteArray object
121 */
122 public void readExternal(ObjectInput in)
123 throws IOException, ClassNotFoundException
124 {
125 super.readExternal(in);
126 operation = in.readByte();
127
128 if (operation == CREATE && hasCreateByteArray)
129 {
130 createByteArray = new ByteArray();
131 createByteArray.readExternal(in);
132 }
133 }
134
135 /**
136 Return my format identifier.
137 */
138 public int getTypeFormatId() {
139 return StoredFormatIds.LOGOP_CONTAINER;
140 }
141
142
143 /*
144 * override ContainerBasicOperation's findContainerForLoadTran
145 */
146 /**
147 Find container for load tran.
148 <p>
149 If we are in load tran, and the operation is a create, the container
150 may not (should not?) exist yet. We need to recreate it.
151
152 @exception StandardException Standard Cloudscape policy.
153 */
154 protected RawContainerHandle findContainerForLoadTran(RawTransaction xact)
155 throws StandardException
156 {
157 if (SanityManager.DEBUG)
158 SanityManager.ASSERT(createByteArray != null,
159 "cannot reCreate container in load tran, createByteArray is null");
160
161 long sid = containerId.getSegmentId();
162 long cid = containerId.getContainerId();
163
164 xact.reCreateContainerForLoadTran(sid, cid, createByteArray);
165
166 // now we should be able to open this container
167 return xact.openDroppedContainer(containerId, (LockingPolicy)null);
168 }
169
170 /**
171 @exception StandardException Standard Cloudscape error policy
172 */
173 public final void doMe(Transaction tran, LogInstant instant,
174 LimitObjectInput in)
175 throws StandardException
176 {
177
178 switch (operation)
179 {
180 case DROP:
181 containerHdl.dropContainer(instant, true);
182 //
183 // RESOLVE: if it hasn't been stubbified, even at redo time, we will
184 // want to earmark this as a post commit work because we know it will
185 // not be wasted effort.
186 //
187 break;
188
189 case REMOVE:
190 containerHdl.removeContainer(instant);
191 break;
192
193 case CREATE:
194 break;
195 // nothing to do with create container, it has already been synced to
196 // disk. If the container is subsequently dropped or even removed,
197 // that's fine too. Don't bother to find it.
198 }
199
200 releaseResource(tran);
201 }
202
203
204 /**
205 Undo of create, drop or remove
206
207 @param tran the transaction that is undoing this operation
208 @param hdl the container handle. This is found here during runtime
209 undo - in which case we made the CLR and passed in the containerHdl
210 found in generateUndo and it is passed back to this; or it is found in
211 the CLR's needsRedo and is passed in and this operation never found the
212 container. Either case, release resource at the end is safe
213 @param CLRInstant the log instant of the CLR
214 @param in optional data
215
216 @exception StandardException Standard Cloudscape error policy
217 */
218 public void undoMe(Transaction tran, RawContainerHandle hdl,
219 LogInstant CLRInstant, LimitObjectInput in)
220 throws StandardException
221 {
222 switch(operation)
223 {
224 case DROP:
225 if (SanityManager.DEBUG) {
226 SanityManager.ASSERT(hdl != null, "container handle is null");
227 SanityManager.ASSERT(hdl.getContainerStatus() != RawContainerHandle.COMMITTED_DROP,
228 "Undoing a drop but the container status is not dropped");
229 }
230 hdl.dropContainer(CLRInstant, false); // not dropped
231 break;
232
233 case CREATE:
234 // remove the container
235 hdl.removeContainer(CLRInstant);
236 break;
237
238 case REMOVE:
239 if (SanityManager.DEBUG) {
240 SanityManager.THROWASSERT("cannot undo REMOVE, should not have generated a CLR in the first place");
241 }
242 break;
243 }
244 releaseResource(tran);
245
246 }
247
248 /**
249 @see org.apache.derby.iapi.store.raw.Undoable
250 @exception StandardException Standard Cloudscape error policy
251 */
252 public Compensation generateUndo(Transaction tran, LimitObjectInput in)
253 throws StandardException
254 {
255 if (operation == REMOVE)
256 return null; // cannot undo REMOVE
257 else
258 {
259 RawContainerHandle undoContainerHandle = findContainer(tran);
260
261 // mark the container as pre-dirtied so that if a checkpoint
262 // happens after the log record is sent to the log stream, the
263 // cache cleaning will wait for this change.
264 //
265 // RESOLVE: don't do this now because if undo failed, this
266 // container will be "stuck" in the preDirty state and checkpoint
267 // will be stuck
268 // undoContainerHandle.preDirty(true);
269 //
270
271 return new ContainerUndoOperation(undoContainerHandle, this);
272 }
273 }
274
275 /** debug */
276 public String toString()
277 {
278 if (SanityManager.DEBUG)
279 {
280 String str = super.toString();
281 switch(operation)
282 {
283 case CREATE: str += " CREATE container " + containerId;
284 break;
285 case DROP: str += " DROP container " + containerId;
286 break;
287 case REMOVE: str += " REMOVE container " + containerId;
288 break;
289 }
290 return str;
291 }
292 else
293 return null;
294 }
295
296
297 }