001: /*
002:
003: Derby - Class org.apache.derby.impl.store.access.conglomerate.GenericConglomerateController
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.access.conglomerate;
023:
024: import org.apache.derby.iapi.reference.SQLState;
025:
026: import org.apache.derby.iapi.services.sanity.SanityManager;
027:
028: import org.apache.derby.iapi.error.StandardException;
029:
030: import org.apache.derby.iapi.store.access.conglomerate.Conglomerate;
031: import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo;
032: import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;
033:
034: import org.apache.derby.iapi.store.access.ConglomerateController;
035: import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;
036: import org.apache.derby.iapi.store.access.Qualifier;
037: import org.apache.derby.iapi.store.access.RowUtil;
038: import org.apache.derby.iapi.store.access.SpaceInfo;
039:
040: import org.apache.derby.iapi.store.raw.ContainerHandle;
041: import org.apache.derby.iapi.store.raw.FetchDescriptor;
042: import org.apache.derby.iapi.store.raw.Page;
043: import org.apache.derby.iapi.store.raw.RecordHandle;
044: import org.apache.derby.iapi.store.raw.Transaction;
045:
046: import org.apache.derby.iapi.types.DataValueDescriptor;
047:
048: import org.apache.derby.iapi.types.RowLocation;
049:
050: import org.apache.derby.iapi.services.io.FormatableBitSet;
051:
052: import java.util.Properties;
053:
054: /**
055: **/
056:
057: public abstract class GenericConglomerateController extends
058: GenericController implements ConglomerateController {
059:
060: /**************************************************************************
061: * Fields of the class
062: **************************************************************************
063: */
064:
065: /**************************************************************************
066: * Constructors for This class:
067: **************************************************************************
068: */
069:
070: /**************************************************************************
071: * Private/Protected methods of This class:
072: **************************************************************************
073: */
074:
075: /**************************************************************************
076: * Public Methods of This class:
077: **************************************************************************
078: */
079:
080: /**************************************************************************
081: * Public Methods implementing ConglomerateController which just
082: * delegate to OpenConglomerate:
083: **************************************************************************
084: */
085:
086: /**************************************************************************
087: * Public Methods implementing ConglomerateController:
088: **************************************************************************
089: */
090:
091: /**
092: * @see ConglomerateController#close
093: **/
094: public void close() throws StandardException {
095: super .close();
096:
097: // If we are closed due to catching an error in the middle of init,
098: // xact_manager may not be set yet.
099: if ((open_conglom != null)
100: && (open_conglom.getXactMgr() != null))
101: open_conglom.getXactMgr().closeMe(this );
102: }
103:
104: /**
105: * Close conglomerate controller as part of terminating a transaction.
106: * <p>
107: * Use this call to close the conglomerate controller resources as part of
108: * committing or aborting a transaction. The normal close() routine may
109: * do some cleanup that is either unnecessary, or not correct due to the
110: * unknown condition of the controller following a transaction ending error.
111: * Use this call when closing all controllers as part of an abort of a
112: * transaction.
113: * <p)
114: * This call is meant to only be used internally by the Storage system,
115: * clients of the storage system should use the simple close() interface.
116: * <p>
117: * RESOLVE (mikem) - move this call to ConglomerateManager so it is
118: * obvious that non-access clients should not call this.
119: *
120: * @param closeHeldScan If true, means to close controller even if
121: * it has been opened to be kept opened
122: * across commit. This is
123: * used to close these controllers on abort.
124: *
125: * @return boolean indicating that the close has resulted in a real close
126: * of the controller. A held scan will return false if
127: * called by closeForEndTransaction(false), otherwise it
128: * will return true. A non-held scan will always return
129: * true.
130: *
131: * @exception StandardException Standard exception policy.
132: **/
133: public boolean closeForEndTransaction(boolean closeHeldScan)
134: throws StandardException {
135: super .close();
136:
137: if ((!open_conglom.getHold()) || closeHeldScan) {
138: // If we are closed due to catching an error in the middle of init,
139: // xact_manager may not be set yet.
140: if ((open_conglom != null)
141: && (open_conglom.getXactMgr() != null))
142: open_conglom.getXactMgr().closeMe(this );
143:
144: return (true);
145:
146: } else {
147: return (false);
148: }
149: }
150:
151: /**
152: * @see ConglomerateController#delete
153: **/
154: public boolean delete(RowLocation loc) throws StandardException {
155: if (open_conglom.isClosed()) {
156: if (open_conglom.getHold()) {
157: if (open_conglom.isClosed())
158: open_conglom.reopen();
159: } else {
160: throw (StandardException.newException(
161: SQLState.HEAP_IS_CLOSED, open_conglom
162: .getConglomerate().getId()));
163: }
164: }
165:
166: RowPosition pos = new RowPosition();
167:
168: getRowPositionFromRowLocation(loc, pos);
169:
170: if (!open_conglom.latchPage(pos)) {
171: return false;
172: }
173:
174: open_conglom.lockPositionForWrite(pos,
175: false /* not an insert */, true);
176:
177: boolean ret_val = true;
178:
179: // RESOLVE (mikem) - RECID - performance could be better if we did not
180: // have to call isDeletedAtSlot().
181:
182: if (pos.current_page.isDeletedAtSlot(pos.current_slot)) {
183: ret_val = false;
184: } else {
185: // Delete the row
186: pos.current_page.deleteAtSlot(pos.current_slot, true,
187: (LogicalUndo) null);
188:
189: // try to reclaim rows when the page is only full of deleted rows,
190: // or in the special case of the first page when all rows except the
191: // "control row" are deleted. Or if the row we just deleted is
192: // a long row or has a long column.
193: if (pos.current_page.shouldReclaimSpace(pos.current_page
194: .getPageNumber() == 1 ? 1 : 0, pos.current_slot)) {
195: queueDeletePostCommitWork(pos);
196: }
197: }
198:
199: pos.current_page.unlatch();
200:
201: return (ret_val);
202: }
203:
204: /**
205: * @see ConglomerateController#fetch
206: **/
207: public boolean fetch(RowLocation loc, DataValueDescriptor[] row,
208: FormatableBitSet validColumns) throws StandardException {
209: if (open_conglom.isClosed()) {
210: if (open_conglom.getHold()) {
211: if (open_conglom.isClosed())
212: open_conglom.reopen();
213: } else {
214: throw (StandardException.newException(
215: SQLState.HEAP_IS_CLOSED, open_conglom
216: .getConglomerate().getId()));
217: }
218: }
219:
220: if (SanityManager.DEBUG) {
221: // Make sure valid columns are in the list. The RowUtil
222: // call is too expensive to make in a released system for
223: // every fetch.
224: int invalidColumn = RowUtil.columnOutOfRange(row,
225: validColumns, open_conglom.getFormatIds().length);
226:
227: if (invalidColumn >= 0) {
228: throw (StandardException.newException(
229: SQLState.HEAP_TEMPLATE_MISMATCH, new Long(
230: invalidColumn), new Long(open_conglom
231: .getFormatIds().length)));
232: }
233: }
234:
235: // Get the record handle out of its wrapper.
236:
237: RowPosition pos = new RowPosition();
238:
239: getRowPositionFromRowLocation(loc, pos);
240:
241: if (!open_conglom.latchPage(pos)) {
242: return (false);
243: }
244:
245: // Do not get U row lock - only get X or S. There is no good point
246: // currently to convert the U lock to an S lock, we don't know when
247: // the calling code is through with the lock.
248: // RESOLVE (mikem) - talk to language and see if it is worth it to
249: // get U lock and have language call back when we should take
250: // appropriate action on the U lock.
251:
252: if (open_conglom.isForUpdate()) {
253: open_conglom.lockPositionForWrite(pos,
254: false /* not an insert */, true);
255: } else {
256: open_conglom.lockPositionForRead(pos, (RowPosition) null,
257: false, true);
258: }
259:
260: // Fetch the row.
261: // RESOLVE (STO061) - don't know whether the fetch is for update or not.
262: //
263: // RESOLVE (mikem) - get rid of new here.
264: boolean ret_val = (pos.current_page.fetchFromSlot(
265: pos.current_rh, pos.current_slot, row,
266: new FetchDescriptor(row.length, validColumns,
267: (Qualifier[][]) null), false) != null);
268:
269: // RESOLVE (mikem) - should be some way to hide this in the unlock call,
270: // and just always make the unlock call.
271:
272: if (!open_conglom.isForUpdate())
273: open_conglom.unlockPositionAfterRead(pos);
274:
275: pos.current_page.unlatch();
276:
277: return (ret_val);
278: }
279:
280: /**
281: * @see ConglomerateController#fetch
282: **/
283: public boolean fetch(RowLocation loc, DataValueDescriptor[] row,
284: FormatableBitSet validColumns, boolean waitForLock)
285: throws StandardException {
286: if (open_conglom.isClosed()) {
287: if (open_conglom.getHold()) {
288: if (open_conglom.isClosed())
289: open_conglom.reopen();
290: } else {
291: throw (StandardException.newException(
292: SQLState.HEAP_IS_CLOSED, open_conglom
293: .getConglomerate().getId()));
294: }
295: }
296:
297: if (SanityManager.DEBUG) {
298: // Make sure valid columns are in the list. The RowUtil
299: // call is too expensive to make in a released system for
300: // every fetch.
301: int invalidColumn = RowUtil.columnOutOfRange(row,
302: validColumns, open_conglom.getFormatIds().length);
303:
304: if (invalidColumn >= 0) {
305: throw (StandardException.newException(
306: SQLState.HEAP_TEMPLATE_MISMATCH, new Long(
307: invalidColumn), new Long(open_conglom
308: .getFormatIds().length)));
309: }
310: }
311:
312: // Get the record handle out of its wrapper.
313:
314: RowPosition pos = new RowPosition();
315:
316: getRowPositionFromRowLocation(loc, pos);
317:
318: if (!open_conglom.latchPage(pos)) {
319: return false;
320: }
321:
322: // Do not get U row lock - only get X or S. There is not good point
323: // currently to convert the U lock to an S lock, we don't know when
324: // the calling code is through with the lock.
325: // RESOLVE (mikem) - talk to language and see if it is worth it to
326: // get U lock and have language call back when we should take
327: // appropriate action on the U lock.
328:
329: if (open_conglom.isForUpdate()) {
330: open_conglom.lockPositionForWrite(pos,
331: false /* not an insert */, waitForLock);
332: } else {
333: open_conglom.lockPositionForRead(pos, (RowPosition) null,
334: false, waitForLock);
335: }
336:
337: // Fetch the row.
338: // RESOLVE (STO061) - don't know whether the fetch is for update or not.
339: //
340: //
341: // RESOLVE (mikem) - get rid of new here.
342: boolean ret_val = (pos.current_page.fetchFromSlot(
343: pos.current_rh, pos.current_slot, row,
344: new FetchDescriptor(row.length, validColumns,
345: (Qualifier[][]) null), false) != null);
346:
347: // RESOLVE (mikem) - should be some way to hide this in the unlock call,
348: // and just always make the unlock call.
349: if (!open_conglom.isForUpdate())
350: open_conglom.unlockPositionAfterRead(pos);
351:
352: pos.current_page.unlatch();
353:
354: return (ret_val);
355: }
356:
357: /**
358: * @see ConglomerateController#replace
359: **/
360: public boolean replace(RowLocation loc, DataValueDescriptor[] row,
361: FormatableBitSet validColumns) throws StandardException {
362: if (open_conglom.isClosed()) {
363: if (open_conglom.getHold()) {
364: if (open_conglom.isClosed())
365: open_conglom.reopen();
366: } else {
367: throw (StandardException.newException(
368: SQLState.HEAP_IS_CLOSED, open_conglom
369: .getConglomerate().getId()));
370: }
371: }
372:
373: if (SanityManager.DEBUG) {
374: // Make sure valid columns are in the list. The RowUtil
375: // call is too expensive to make in a released system for
376: // every fetch.
377: int invalidColumn = RowUtil.columnOutOfRange(row,
378: validColumns, open_conglom.getFormatIds().length);
379:
380: if (invalidColumn >= 0) {
381: throw (StandardException.newException(
382: SQLState.HEAP_TEMPLATE_MISMATCH, new Long(
383: invalidColumn), new Long(open_conglom
384: .getFormatIds().length)));
385: }
386: }
387:
388: RowPosition pos = new RowPosition();
389:
390: getRowPositionFromRowLocation(loc, pos);
391:
392: if (!open_conglom.latchPage(pos)) {
393: return false;
394: }
395:
396: open_conglom.lockPositionForWrite(pos, false, true);
397:
398: boolean ret_val = true;
399:
400: if (pos.current_page.isDeletedAtSlot(pos.current_slot)) {
401: ret_val = false;
402: } else {
403: // Update the record.
404: pos.current_page.updateAtSlot(pos.current_slot, row,
405: validColumns);
406: }
407:
408: pos.current_page.unlatch();
409:
410: return (ret_val);
411: }
412: }
|