KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > store > access > btree > BTreePostCommit


1 /*
2
3    Derby - Class org.apache.derby.impl.store.access.btree.BTreePostCommit
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.btree;
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.AccessFactory;
31 import org.apache.derby.iapi.store.access.AccessFactoryGlobals;
32 import org.apache.derby.iapi.store.access.ConglomerateController;
33 import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;
34 import org.apache.derby.iapi.store.access.TransactionController;
35 import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo;
36 import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;
37
38 import org.apache.derby.iapi.store.access.Qualifier;
39
40 import org.apache.derby.iapi.store.raw.ContainerHandle;
41 import org.apache.derby.iapi.store.raw.FetchDescriptor;
42 import org.apache.derby.iapi.store.raw.LockingPolicy;
43 import org.apache.derby.iapi.store.raw.Page;
44 import org.apache.derby.iapi.store.raw.RecordHandle;
45 import org.apache.derby.iapi.store.raw.Transaction;
46
47 import org.apache.derby.iapi.types.DataValueDescriptor;
48
49 import org.apache.derby.iapi.services.io.FormatableBitSet;
50 import org.apache.derby.iapi.reference.SQLState;
51
52 /**
53
54 The BTreePostCommit class implements the Serviceable protocol.
55
56 In it's role as a Serviceable object, it stores the state necessary to
57 find a page in a btree that may have committed delete's to reclaim.
58
59 In it's role as a PostCommitProcessor it looks up the page described, and
60 reclaims space in the btree. It first trys to clean up any deleted commits
61 on the page. It then will shrink the tree if it is going to delete all
62 rows from the page (RESOLVE - not done yet).
63
64 **/

65
66 class BTreePostCommit implements Serviceable
67 {
68     private AccessFactory access_factory = null;
69     private long page_number = ContainerHandle.INVALID_PAGE_NUMBER;
70
71     protected BTree btree = null;
72
73     /* Constructors for This class: */
74     BTreePostCommit(
75     AccessFactory access_factory,
76     BTree btree,
77     long input_page_number)
78     {
79         this.access_factory = access_factory;
80         this.btree = btree;
81         this.page_number = input_page_number;
82     }
83
84     /* Private/Protected methods of This class: */
85
86     /* Public Methods of This class: */
87
88     /* Public Methods of Serviceable class: */
89
90     /**
91      * The urgency of this post commit work.
92      * <p>
93      * This determines where this Serviceable is put in the post commit
94      * queue. Post commit work in the btree can be safely delayed until there
95      * is not user work to do.
96      *
97      * @return false, this work should not be serviced ASAP
98      **/

99     public boolean serviceASAP()
100     {
101         return(true);
102     }
103
104
105     // @return true, if this work needs to be done on a user thread immediately
106
public boolean serviceImmediately()
107     {
108         return false;
109     }
110
111     private final void doShrink(
112     OpenBTree open_btree,
113     DataValueDescriptor[] shrink_row)
114         throws StandardException
115     {
116         ControlRow root = null;
117
118         /*
119         System.out.println(
120             "Calling shrink on tree with levels = " +
121             open_btree.getHeight() + "\n");
122         */

123
124         // Get the root page back, and perform a split following the
125
// to-be-inserted key. The split releases the root page latch.
126
root = ControlRow.Get(open_btree, BTree.ROOTPAGEID);
127
128         root.shrinkFor(open_btree, shrink_row);
129
130         root = null;
131
132         // on return from shrinkFor the root pointer is invalid. The
133
// latch has been released, the root page may have changed from
134
// a branch to a leaf.
135

136         return;
137     }
138
139     /**
140      * perform the work described in the postcommit work.
141      * <p>
142      * In this implementation the only work that can be executed by this
143      * post commit processor is this class itself.
144      * <p>
145      *
146      * @return Returns Serviceable.DONE when work has completed, or
147      * returns Serviceable.REQUEUE if work needs to be requeued.
148      *
149      * @param contextMgr the context manager started by the
150      * post commit daemon
151      *
152      * @exception StandardException Standard exception policy.
153      **/

154     public int performWork(ContextManager contextMgr)
155         throws StandardException
156     {
157
158         // requeue if work was not completed in this try because of locks
159
boolean requeue_work = false;
160
161         TransactionManager tc = (TransactionManager)
162             this.access_factory.getAndNameTransaction(
163                 contextMgr, AccessFactoryGlobals.SYS_TRANS_NAME);
164
165         TransactionManager internal_xact = tc.getInternalTransaction();
166
167         if (SanityManager.DEBUG)
168         {
169             if (SanityManager.DEBUG_ON("verbose_btree_post_commit"))
170                 System.out.println("starting internal xact\n");
171         }
172
173         OpenBTree open_btree = new OpenBTree();
174
175         try
176         {
177             // Get lock on base table.
178

179             // The current space reclamation algorithm requires a table level
180
// lock on the btree - this is mostly because the shrink algorithm
181
// is not multi-user. This lock is requested NOWAIT as it does
182
// not want to impedede normal operation on the table. If the lock
183
// were to wait then the current lock manager livelock algorithm
184
// would block all subsequent lock requests on this btree even if
185
// they are compatible with the current holder of the lock.
186
//
187
// There are currently 3 outstanding enhancement requests:
188
// track 4237 - retry the work intelligently
189
// track 4238 - if can't get table lock, at least reclaim the rows
190
// track 4239 - do row level lock shrink - very hard to do.
191
//
192
ConglomerateController base_cc =
193                 btree.lockTable(
194                     internal_xact,
195                     (ContainerHandle.MODE_FORUPDATE |
196                      ContainerHandle.MODE_LOCK_NOWAIT),
197                     TransactionController.MODE_TABLE,
198                     TransactionController.ISOLATION_REPEATABLE_READ);
199
200             open_btree.init(
201                 (TransactionManager) null,
202                 internal_xact,
203                 (ContainerHandle) null, // open the container
204
internal_xact.getRawStoreXact(),
205                 false,
206                 ContainerHandle.MODE_FORUPDATE,
207                 TransactionController.MODE_TABLE,
208                 btree.getBtreeLockingPolicy(
209                     internal_xact.getRawStoreXact(),
210                     TransactionController.MODE_TABLE,
211                     LockingPolicy.MODE_CONTAINER,
212                     TransactionController.ISOLATION_REPEATABLE_READ,
213                     base_cc,
214                     open_btree),
215                 btree,
216                 (LogicalUndo) null, // No logical undo necessry.
217
(DynamicCompiledOpenConglomInfo) null);
218
219             DataValueDescriptor[] shrink_key =
220                 purgeCommittedDeletes(open_btree, this.page_number);
221
222             // RESOLVE (mikem) - move this call when doing row level locking.
223
if (shrink_key != null)
224                 doShrink(open_btree, shrink_key);
225
226             open_btree.close();
227         }
228         catch (StandardException se)
229         {
230
231             
232             //2 kinds of errors here expected here. Either container not found or dead lock.
233
// It is possible by the time this post commit work gets scheduled
234
// that the container has been dropped and that the open container
235
// call will return null - in this case just return assuming no
236
// work to be done.
237

238             //If it is a locking error, work is requeued. (4237)
239

240             if (se.getMessageId().equals(SQLState.LOCK_TIMEOUT) ||
241                 se.getMessageId().equals(SQLState.DEADLOCK))
242             {
243                 requeue_work = true;
244             }
245
246             //RESSOLVE-mike (4238) If you can't get a table level lock for btree space recovery in
247
//the post commit thread, maybe you should at least reclaim the
248
//rows on the page while you are at it. Use the same algorithm
249
//as exists in BTreeController.java. row level shrink is still a
250
//big problem and a separate track exists for it.
251

252
253         }
254         finally
255         {
256             internal_xact.commit();
257             internal_xact.destroy();
258         }
259
260         return(requeue_work ? Serviceable.REQUEUE : Serviceable.DONE);
261     }
262
263     private final DataValueDescriptor[] getShrinkKey(
264     OpenBTree open_btree,
265     ControlRow control_row,
266     int slot_no)
267         throws StandardException
268     {
269         DataValueDescriptor[] shrink_key =
270             open_btree.getConglomerate().createTemplate();
271
272         control_row.page.fetchFromSlot(
273             (RecordHandle) null,
274             slot_no, shrink_key,
275             (FetchDescriptor) null,
276             true);
277
278         return(shrink_key);
279     }
280
281     /**
282      * Reclaim space taken up by committed deleted rows.
283      * <p>
284      * This routine assumes it has been called by an internal transaction which
285      * has performed no work so far, and that it has an exclusive table lock.
286      * These assumptions mean that any deleted rows encountered must be from
287      * committed transactions (otherwise we could not have gotten the exclusive
288      * table lock).
289      * <p>
290      * RESOLVE (mikem) - under row locking this routine must do more work to
291      * determine a deleted row is a committed deleted row.
292      *
293      * @param open_btree The btree already opened.
294      * @param pageno The page number of the page to look for committed deletes.
295      *
296      * @exception StandardException Standard exception policy.
297      **/

298     private final DataValueDescriptor[] purgeCommittedDeletes(
299     OpenBTree open_btree,
300     long pageno)
301         throws StandardException
302     {
303         ControlRow control_row = null;
304         DataValueDescriptor[] shrink_key = null;
305
306         try
307         {
308             // The following can fail either if it can't get the latch or
309
// somehow the page requested no longer exists. In either case
310
// the post commit work will just skip it.
311
control_row = ControlRow.GetNoWait(open_btree, pageno);
312
313             if (control_row != null)
314             {
315                 Page page = control_row.page;
316
317                 // The number records that can be reclaimed is:
318
// total recs - control row - recs_not_deleted
319
int num_possible_commit_delete =
320                     page.recordCount() - 1 - page.nonDeletedRecordCount();
321
322                 if (num_possible_commit_delete > 0)
323                 {
324                     // loop backward so that purges which affect the slot table
325
// don't affect the loop (ie. they only move records we
326
// have already looked at).
327
for (int slot_no = page.recordCount() - 1;
328                          slot_no > 0;
329                          slot_no--)
330                     {
331                         if (page.isDeletedAtSlot(slot_no))
332                         {
333
334                             if (page.recordCount() == 2)
335                             {
336                                 // About to purge last row from page so
337
// remember the key so we can shrink the
338
// tree.
339
shrink_key = this.getShrinkKey(
340                                     open_btree, control_row, slot_no);
341                             }
342
343                             page.purgeAtSlot(slot_no, 1, true);
344
345                             if (SanityManager.DEBUG)
346                             {
347                                 if (SanityManager.DEBUG_ON(
348                                         "verbose_btree_post_commit"))
349                                 {
350                                     System.out.println(
351                                         "Purging row[" + slot_no + "]" +
352                                         "on page:" + pageno + ".\n");
353                                 }
354                             }
355                         }
356                     }
357                 }
358
359                 if (page.recordCount() == 1)
360                 {
361                     if (SanityManager.DEBUG)
362                     {
363                         if (SanityManager.DEBUG_ON("verbose_btree_post_commit"))
364                         {
365                             System.out.println("Chance to shrink.\n");
366                         }
367                     }
368                 }
369             }
370             else
371             {
372                 if (SanityManager.DEBUG)
373                 {
374                     if (SanityManager.DEBUG_ON("verbose_btree_post_commit"))
375                     {
376                         System.out.println(
377                             "Get No Wait returned null. page num = " + pageno +
378                             "\n");
379                     }
380                 }
381             }
382         }
383         finally
384         {
385             if (control_row != null)
386                 control_row.release();
387         }
388
389         return(shrink_key);
390     }
391
392 }
393
Popular Tags