KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > store > access > heap > HeapPostCommit


1 /*
2
3    Derby - Class org.apache.derby.impl.store.access.heap.HeapPostCommit
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.store.access.heap;
23
24 import org.apache.derby.iapi.services.context.ContextManager;
25 import org.apache.derby.iapi.services.daemon.Serviceable;
26 import org.apache.derby.iapi.services.monitor.Monitor;
27 import org.apache.derby.iapi.services.sanity.SanityManager;
28 import org.apache.derby.iapi.error.StandardException;
29
30 import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;
31
32 import org.apache.derby.iapi.store.access.AccessFactory;
33 import org.apache.derby.iapi.store.access.AccessFactoryGlobals;
34
35 import org.apache.derby.iapi.store.access.ConglomerateController;
36 import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;
37 import org.apache.derby.iapi.store.access.Qualifier;
38 import org.apache.derby.iapi.store.access.RowUtil;
39 import org.apache.derby.iapi.store.access.TransactionController;
40
41 import org.apache.derby.iapi.store.raw.ContainerHandle;
42 import org.apache.derby.iapi.store.raw.FetchDescriptor;
43 import org.apache.derby.iapi.store.raw.LockingPolicy;
44 import org.apache.derby.iapi.store.raw.Page;
45 import org.apache.derby.iapi.store.raw.RecordHandle;
46 import org.apache.derby.iapi.store.raw.Transaction;
47
48 import org.apache.derby.iapi.reference.SQLState;
49
50 /**
51
52 The HeapPostCommit class implements the Serviceable protocol.
53
54 In it's role as a Serviceable object, it stores the state necessary to
55 find a page in a heap that may have committed delete's to reclaim.
56
57 It looks up the page described, and reclaims space in the conglomerate.
58 It first trys to clean up any deleted commits on the page. It will then
59 deallocate the page if no rows remain on the page. All work is done while
60 holding the latch on the page, and locks are never "waited" on while holding
61 this latch.
62
63 This implementation uses record level locking to reclaim the space.
64 For the protocols to work correctly all other heap methods must be
65 prepared for a record or a page to "disappear" if they don't hold a latch and/or
66 a lock. An example of the problem case is a scan which does not hold locks
67 on it's current position (group scan works this way), which is positioned
68 on a row deleted by another xact, it must be prepared to continue the
69 scan after getting an error if the current page/row disapppears.
70
71 **/

72
73 class HeapPostCommit implements Serviceable
74 {
75     /**************************************************************************
76      * Fields of the class
77      **************************************************************************
78      */

79
80     private AccessFactory access_factory = null;
81     private Heap heap = null;
82     private long page_number = ContainerHandle.INVALID_PAGE_NUMBER;
83
84
85     /**************************************************************************
86      * Constructors for This class:
87      **************************************************************************
88      */

89     HeapPostCommit(
90     AccessFactory access_factory,
91     Heap heap,
92     long input_page_number)
93     {
94         this.access_factory = access_factory;
95         this.heap = heap;
96         this.page_number = input_page_number;
97     }
98
99     /**************************************************************************
100      * Private/Protected methods of This class:
101      **************************************************************************
102      */

103
104     /**
105      * Reclaim space taken up by committed deleted rows.
106      * <p>
107      * This routine assumes it has been called by an internal transaction which
108      * has performed no work so far, and that it has an exclusive intent table
109      * lock. It will attempt obtain exclusive row locks on deleted rows, where
110      * successful those rows can be reclaimed as they must be "committed
111      * deleted" rows.
112      * <p>
113      * This routine will latch the page and hold the latch due to interface
114      * requirement from Page.purgeAtSlot.
115      *
116      * @param heap_control The heap, already opened.
117      * @param pageno number of page to look for committed deletes.
118      *
119      * @see Page#purgeAtSlot
120      * @exception StandardException Standard exception policy.
121      **/

122     private final void purgeCommittedDeletes(
123     HeapController heap_control,
124     long pageno)
125         throws StandardException
126     {
127         // The following can fail either if it can't get the latch or
128
// somehow the page requested no longer exists.
129

130     //resolve - what will happen if the user page doesnt exist
131

132         // wait to get the latch on the page
133
Page page = heap_control.getUserPageWait(pageno);
134         boolean purgingDone = false;
135
136         if (page != null)
137         {
138             try
139             {
140                 // The number records that can be reclaimed is:
141
// total recs - recs_not_deleted
142
int num_possible_commit_delete =
143                     page.recordCount() - page.nonDeletedRecordCount();
144
145                 if (num_possible_commit_delete > 0)
146                 {
147                     // loop backward so that purges which affect the slot table
148
// don't affect the loop (ie. they only move records we
149
// have already looked at).
150
for (int slot_no = page.recordCount() - 1;
151                          slot_no >= 0;
152                          slot_no--)
153                     {
154                         boolean row_is_committed_delete =
155                             page.isDeletedAtSlot(slot_no);
156
157                         if (row_is_committed_delete)
158                         {
159                             // At this point we only know that the row is
160
// deleted, not whether it is committed.
161

162                             // see if we can purge the row, by getting an
163
// exclusive lock on the row. If it is marked
164
// deleted and we can get this lock, then it
165
// must be a committed delete and we can purge
166
// it.
167

168                             RecordHandle rh =
169                                 page.fetchFromSlot(
170                                     (RecordHandle) null,
171                                     slot_no,
172                                     RowUtil.EMPTY_ROW,
173                                     RowUtil.EMPTY_ROW_FETCH_DESCRIPTOR,
174                                     true);
175
176                             row_is_committed_delete =
177                                 heap_control.lockRowAtSlotNoWaitExclusive(rh);
178
179                             if (row_is_committed_delete)
180                             {
181                                 purgingDone = true;
182
183                                 page.purgeAtSlot(slot_no, 1, false);
184
185                                 if (SanityManager.DEBUG)
186                                 {
187                                     if (SanityManager.DEBUG_ON(
188                                             "verbose_heap_post_commit"))
189                                     {
190                                         SanityManager.DEBUG_PRINT(
191                                             "HeapPostCommit",
192                                             "Purging row[" + slot_no + "]" +
193                                             "on page:" + pageno + ".\n");
194                                     }
195                                 }
196                             }
197                         }
198                     }
199                 }
200                 if (page.recordCount() == 0)
201                 {
202                     purgingDone = true;
203
204                     // Deallocate the current page with 0 rows on it.
205
heap_control.removePage(page);
206
207                     // removePage guarantees to unlatch the page even if an
208
// exception is thrown. The page is protected against reuse
209
// because removePage locks it with a dealloc lock, so it
210
// is OK to release the latch even after a purgeAtSlot is
211
// called.
212
// @see ContainerHandle#removePage
213

214                     if (SanityManager.DEBUG)
215                     {
216                         if (SanityManager.DEBUG_ON("verbose_heap_post_commit"))
217                         {
218                             SanityManager.DEBUG_PRINT(
219                                 "HeapPostCommit",
220                                 "Calling Heap removePage().; pagenumber="+pageno+"\n");
221                         }
222                     }
223                 }
224             }
225             finally
226             {
227                 // If no purge happened on the page and the page is not
228
// removed, feel free to unlatch it. Otherwise, let
229
// transaction commit take care of it.
230
if (!purgingDone)
231                 {
232                     page.unlatch();
233                     page = null;
234                 }
235             }
236         }
237         else
238         {
239             if (SanityManager.DEBUG)
240             {
241                 if (SanityManager.DEBUG_ON("verbose_heap_post_commit"))
242                 {
243                     SanityManager.DEBUG_PRINT(
244                         "HeapPostCommit",
245                         "Get No Wait returned null. page num = " +
246                         pageno + "\n");
247
248                     SanityManager.showTrace(new Throwable JavaDoc());
249                 }
250             }
251         }
252         return;
253     }
254
255     /**************************************************************************
256      * Public Methods implementing the Serviceable interface:
257      **************************************************************************
258      */

259
260     /**
261      * The urgency of this post commit work.
262      * <p>
263      * This determines where this Serviceable is put in the post commit
264      * queue. Post commit work in the heap can be safely delayed until there
265      * is not user work to do.
266      *
267      * @return false, this work should not be serviced ASAP
268      **/

269     public boolean serviceASAP()
270     {
271         return(true);
272     }
273
274     // @return true, if this work needs to be done on a user thread immediately
275
public boolean serviceImmediately()
276     {
277         return false;
278     }
279
280
281     /**
282      * perform the work described in the postcommit work.
283      * <p>
284      * In this implementation the only work that can be executed by this
285      * post commit processor is this class itself.
286      * <p>
287      *
288      * @return Returns Serviceable.DONE when work has completed, or
289      * returns Serviceable.REQUEUE if work needs to be requeued.
290      *
291      * @param contextMgr the context manager started by the post commit daemon
292      *
293      * @exception StandardException Standard exception policy.
294      **/

295     public int performWork(ContextManager contextMgr)
296         throws StandardException
297     {
298         TransactionManager tc = (TransactionManager)
299             this.access_factory.getAndNameTransaction(
300                 contextMgr, AccessFactoryGlobals.SYS_TRANS_NAME);
301
302         TransactionManager internal_xact = tc.getInternalTransaction();
303
304         // only requeue if work was not completed in this try.
305
boolean requeue_work = false;
306
307         HeapController heapcontroller;
308
309         if (SanityManager.DEBUG)
310         {
311             if (SanityManager.DEBUG_ON("verbose_heap_post_commit"))
312                 SanityManager.DEBUG_PRINT(
313                     "HeapPostCommit", "starting internal xact\n");
314         }
315
316         try
317         {
318             // This call will attempt to open the heap table locked with
319
// table level IX mode, preparing to do record level locked space
320
// reclamation.
321
//
322
// The call will either succeed immediately, or throw an exception
323
// which could mean the container does not exist or that the lock
324
// could not be granted immediately.
325

326             //Reversed the fix for 4255:
327
//page reclaimation is done asynchronosly by raswstore daemon
328
//not good to WAIT FOR LOCKS , as it can freeze the daemon
329
//If we can not get the lock this reclamation request will
330
//requeued.
331

332             heapcontroller = (HeapController)
333                 heap.open(
334                     internal_xact,
335                     internal_xact.getRawStoreXact(),
336                     false,
337                     ContainerHandle.MODE_FORUPDATE |
338                     ContainerHandle.MODE_LOCK_NOWAIT,
339                     TransactionController.MODE_RECORD,
340                     internal_xact.getRawStoreXact().newLockingPolicy(
341                         LockingPolicy.MODE_RECORD,
342                         TransactionController.ISOLATION_REPEATABLE_READ, true),
343                     heap,
344                     (DynamicCompiledOpenConglomInfo) null);
345
346             // We got a table intent lock, all deleted rows we encounter can
347
// be reclaimed, once an "X" row lock is obtained on them.
348

349             // Process all the rows on the page while holding the latch.
350
purgeCommittedDeletes(heapcontroller, this.page_number);
351
352         }
353         catch (StandardException se)
354         {
355             // exception might have occured either container got dropper or lock not granted.
356
// It is possible by the time this post commit work gets scheduled
357
// that the container has been dropped and that the open container
358
// call will return null - in this case just return assuming no
359
// work to be done.
360

361             //If this expcetion is because lock could not be obtained , work is requeued.
362
if (se.getMessageId().equals(SQLState.LOCK_TIMEOUT) ||
363                 se.getMessageId().equals(SQLState.DEADLOCK))
364             {
365                 requeue_work = true;
366             }
367
368             // Do not close the controller because that will unlatch the
369
// page. Let the commit and destroy do release the latch and
370
// close the controller.
371
// heapcontroller.close();
372
}
373             
374         // It is ok to not sync this post work. If no subsequent log record
375
// is sync'd to disk then it is ok that this transaction not make
376
// it to the database. If any subsequent transaction is sync'd to
377
// the log file, then this transaction will be sync'd as part of that
378
// work.
379

380         internal_xact.commitNoSync(Transaction.RELEASE_LOCKS);
381         internal_xact.destroy();
382
383
384         if (SanityManager.DEBUG)
385         {
386             if (SanityManager.DEBUG_ON("verbose_heap_post_commit"))
387             {
388                 if (requeue_work)
389                     SanityManager.DEBUG_PRINT(
390                         "HeapPostCommit",
391                         "requeueing on page num = " + page_number);
392             }
393         }
394
395         return(requeue_work ? Serviceable.REQUEUE : Serviceable.DONE);
396     }
397 }
398
399
Popular Tags