KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.store.access.heap.HeapScan
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
25 /**
26
27   A heap scan object represents an instance of an scan on a heap conglomerate.
28
29 **/

30
31 import org.apache.derby.iapi.reference.SQLState;
32
33 import org.apache.derby.iapi.services.sanity.SanityManager;
34
35 import org.apache.derby.iapi.services.io.Storable;
36
37 import org.apache.derby.iapi.error.StandardException;
38
39 import org.apache.derby.iapi.store.access.conglomerate.Conglomerate;
40 import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo;
41 import org.apache.derby.iapi.store.access.conglomerate.ScanManager;
42 import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;
43
44 import org.apache.derby.iapi.store.access.ConglomerateController;
45 import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;
46 import org.apache.derby.iapi.store.access.Qualifier;
47 import org.apache.derby.iapi.store.access.RowUtil;
48 import org.apache.derby.iapi.store.access.ScanInfo;
49 import org.apache.derby.iapi.store.access.ScanController;
50 import org.apache.derby.iapi.store.access.SpaceInfo;
51 import org.apache.derby.iapi.store.access.TransactionController;
52
53 import org.apache.derby.iapi.types.RowLocation;
54
55 import org.apache.derby.iapi.store.raw.ContainerHandle;
56 import org.apache.derby.iapi.store.raw.LockingPolicy;
57 import org.apache.derby.iapi.store.raw.Transaction;
58 import org.apache.derby.iapi.store.raw.Page;
59 import org.apache.derby.iapi.store.raw.RecordHandle;
60
61 import org.apache.derby.iapi.types.DataValueDescriptor;
62
63 import org.apache.derby.impl.store.access.conglomerate.ConglomerateUtil;
64 import org.apache.derby.impl.store.access.conglomerate.GenericScanController;
65 import org.apache.derby.impl.store.access.conglomerate.RowPosition;
66
67 import org.apache.derby.iapi.store.access.BackingStoreHashtable;
68 import org.apache.derby.iapi.services.io.FormatableBitSet;
69
70 import java.util.Hashtable JavaDoc;
71 import java.util.Vector JavaDoc;
72
73 class HeapCompressScan
74     extends HeapScan
75 {
76
77     /**************************************************************************
78      * Constants of HeapScan
79      **************************************************************************
80      */

81
82     /**************************************************************************
83      * Fields of HeapScan
84      **************************************************************************
85      */

86     private long pagenum_to_start_moving_rows = -1;
87
88
89
90     /**************************************************************************
91      * Constructors for This class:
92      **************************************************************************
93      */

94
95     /**
96      ** The only constructor for a HeapCompressScan returns a scan in the
97      ** closed state, the caller must call open.
98      **/

99     
100     public HeapCompressScan()
101     {
102     }
103
104     /**************************************************************************
105      * Protected override implementation of routines in
106      * GenericController class:
107      **************************************************************************
108      */

109
110     public int fetchNextGroup(
111     DataValueDescriptor[][] row_array,
112     RowLocation[] old_rowloc_array,
113     RowLocation[] new_rowloc_array)
114         throws StandardException
115     {
116         return(fetchRowsForCompress(
117                     row_array, old_rowloc_array, new_rowloc_array));
118     }
119
120     /**
121      * Fetch the next N rows from the table.
122      * <p>
123      * Utility routine used by both fetchSet() and fetchNextGroup().
124      *
125      * @exception StandardException Standard exception policy.
126      **/

127     private int fetchRowsForCompress(
128     DataValueDescriptor[][] row_array,
129     RowLocation[] oldrowloc_array,
130     RowLocation[] newrowloc_array)
131         throws StandardException
132     {
133         int ret_row_count = 0;
134         DataValueDescriptor[] fetch_row = null;
135
136         if (SanityManager.DEBUG)
137         {
138             SanityManager.ASSERT(row_array != null);
139             SanityManager.ASSERT(row_array[0] != null,
140                     "first array slot in fetchNextGroup() must be non-null.");
141         }
142
143         if (getScanState() == SCAN_INPROGRESS)
144         {
145             positionAtResumeScan(scan_position);
146         }
147         else if (getScanState() == SCAN_INIT)
148         {
149             // For first implementation of defragment use a conservative
150
// approach, only move rows from the last "number of free pages"
151
// of the container. Should always at least be able to empty
152
// that number of pages.
153
SpaceInfo info =
154                 open_conglom.getContainer().getSpaceInfo();
155
156             pagenum_to_start_moving_rows = info.getNumAllocatedPages();
157
158             positionAtStartForForwardScan(scan_position);
159         }
160         else if (getScanState() == SCAN_HOLD_INPROGRESS)
161         {
162             reopenAfterEndTransaction();
163
164             if (SanityManager.DEBUG)
165             {
166                 SanityManager.ASSERT(
167                     scan_position.current_rh != null, this.toString());
168             }
169
170             // reposition the scan at the row just before the next one to
171
// return.
172
// This routine handles the mess of repositioning if the row or
173
// the page has disappeared. This can happen if a lock was not
174
// held on the row while not holding the latch.
175
open_conglom.latchPageAndRepositionScan(scan_position);
176
177             setScanState(SCAN_INPROGRESS);
178         }
179         else if (getScanState() == SCAN_HOLD_INIT)
180         {
181             reopenAfterEndTransaction();
182
183             positionAtStartForForwardScan(scan_position);
184
185         }
186         else
187         {
188             if (SanityManager.DEBUG)
189                 SanityManager.ASSERT(getScanState() == SCAN_DONE);
190
191             return(0);
192         }
193
194         // At this point:
195
// scan_position.current_page is latched.
196
// scan_position.current_slot is the slot on scan_position.current_page
197
// just before the "next" record this routine should process.
198

199         // loop through successive pages and successive slots on those
200
// pages. Stop when either the last page is reached
201
// (scan_position.current_page will be null).
202
// Along the way apply qualifiers to skip rows which don't qualify.
203

204         while (scan_position.current_page != null)
205         {
206             while ((scan_position.current_slot + 1) <
207                     scan_position.current_page.recordCount())
208             {
209                 // Allocate a new row to read the row into.
210
if (fetch_row == null)
211                 {
212                      // point at allocated row in array if one exists.
213
if (row_array[ret_row_count] == null)
214                     {
215                         row_array[ret_row_count] =
216                           open_conglom.getRuntimeMem().get_row_for_export();
217                     }
218
219                     fetch_row = row_array[ret_row_count];
220                 }
221
222                 // move scan current position forward.
223
scan_position.positionAtNextSlot();
224
225                 this.stat_numrows_visited++;
226
227                 if (scan_position.current_page.isDeletedAtSlot(
228                         scan_position.current_slot))
229                 {
230                     // At this point assume table level lock, and that this
231
// transcation did not delete the row, so any
232
// deleted row must be a committed deleted row which can
233
// be purged.
234
scan_position.current_page.purgeAtSlot(
235                         scan_position.current_slot, 1, false);
236
237                     // raw store shuffles following rows down, so
238
// postion the scan at previous slot, so next trip
239
// through loop will pick up correct row.
240
scan_position.positionAtPrevSlot();
241                     continue;
242                 }
243
244                 if (scan_position.current_page.getPageNumber() >
245                         pagenum_to_start_moving_rows)
246                 {
247                     // Give raw store a chance to move the row for compression
248
RecordHandle[] old_handle = new RecordHandle[1];
249                     RecordHandle[] new_handle = new RecordHandle[1];
250                     long[] new_pageno = new long[1];
251
252                     if (scan_position.current_page.moveRecordForCompressAtSlot(
253                             scan_position.current_slot,
254                             fetch_row,
255                             old_handle,
256                             new_handle) == 1)
257                     {
258                         // raw store moved the row, so bump the row count but
259
// postion the scan at previous slot, so next trip
260
// through loop will pick up correct row.
261
// The subsequent rows will have been moved forward
262
// to take place of moved row.
263
scan_position.positionAtPrevSlot();
264
265                         ret_row_count++;
266                         stat_numrows_qualified++;
267
268
269                         setRowLocationArray(
270                             oldrowloc_array, ret_row_count - 1, old_handle[0]);
271                         setRowLocationArray(
272                             newrowloc_array, ret_row_count - 1, new_handle[0]);
273
274                         fetch_row = null;
275
276                     }
277                 }
278             }
279
280             this.stat_numpages_visited++;
281
282             if (scan_position.current_page.recordCount() == 0)
283             {
284                 // need to set the scan position before removing page
285
scan_position.current_pageno =
286                     scan_position.current_page.getPageNumber();
287
288                 open_conglom.getContainer().removePage(
289                     scan_position.current_page);
290
291                 // removePage unlatches the page, and page not available
292
// again until after commit.
293
scan_position.current_page = null;
294             }
295             else
296             {
297                 positionAfterThisPage(scan_position);
298                 scan_position.unlatch();
299             }
300
301
302             if (ret_row_count > 0)
303             {
304                 // rows were moved on this page, give caller a chance to
305
// process those and free up access to the table.
306
return(ret_row_count);
307             }
308             else
309             {
310                 // no rows were moved so go ahead and commit the transaction
311
// to allow other threads a chance at table. Compress does
312
// need to sync as long as transaction either completely
313
// commits or backs out, either is fine.
314
/*
315                 open_conglom.getXactMgr().commitNoSync(
316                     TransactionController.RELEASE_LOCKS);
317                 open_conglom.reopen();
318                 */

319                 positionAtResumeScan(scan_position);
320
321             }
322         }
323
324         // Reached last page of scan.
325
positionAtDoneScan(scan_position);
326
327         // we need to decrement when we stop scan at the end of the table.
328
this.stat_numpages_visited--;
329
330         return(ret_row_count);
331     }
332
333     /**
334      * Reposition the scan upon entering the fetchRows loop.
335      * <p>
336      * Called upon entering fetchRows() while in the SCAN_INPROGRESS state.
337      * Do work necessary to look at rows in the current page of the scan.
338      * <p>
339      * The default implementation uses a record handle to maintain a scan
340      * position. It will get the latch again on the current
341      * scan position and set the slot to the current record handle.
342      *
343      * @exception StandardException Standard exception policy.
344      **/

345     protected void positionAtResumeScan(
346     RowPosition pos)
347         throws StandardException
348     {
349         // reposition the scan at the row just before the next one to return.
350
// This routine handles the mess of repositioning if the row or the
351
// page has disappeared. This can happen if a lock was not held on the
352
// row while not holding the latch.
353
open_conglom.latchPageAndRepositionScan(scan_position);
354     }
355
356     /**
357      * Move the scan from SCAN_INIT to SCAN_INPROGRESS.
358      * <p>
359      * This routine is called to move the scan from SCAN_INIT to
360      * SCAN_INPROGRESS. Upon return from this routine it is expected
361      * that scan_position is set such that calling the generic
362      * scan loop will reach the first row of the scan. Note that this
363      * usually means setting the scan_postion to one before the 1st
364      * row to be returned.
365      * <p>
366      *
367      * @exception StandardException Standard exception policy.
368      **/

369     protected void positionAtStartForForwardScan(
370     RowPosition pos)
371         throws StandardException
372     {
373         if (pos.current_rh == null)
374         {
375             // 1st positioning of scan (delayed from openScan). Do not
376
// compress the first page, there is no previous page to move
377
// rows to, and moving the special Heap metadata row from the
378
// first page would cause problems. Setting to next page is
379
// why this scan overrides generic implementation.
380
pos.current_page =
381                 open_conglom.getContainer().getNextPage(
382                     ContainerHandle.FIRST_PAGE_NUMBER);
383
384             // set up for scan to continue at beginning of page following
385
// the first page of the container.
386
pos.current_slot = Page.FIRST_SLOT_NUMBER - 1;
387         }
388         else
389         {
390             // 1st positioning of scan following a reopenScanByRowLocation
391

392             // reposition the scan at the row just before the next one to
393
// return. This routine handles the mess of repositioning if the
394
// row or the page has disappeared. This can happen if a lock was
395
// not held on the row while not holding the latch.
396
open_conglom.latchPageAndRepositionScan(pos);
397
398             // set up for scan to at the specified record handle (position one
399
// before it so that the loop increment and find it).
400
pos.current_slot -= 1;
401         }
402
403         pos.current_rh = null;
404         this.stat_numpages_visited = 1;
405         this.setScanState(SCAN_INPROGRESS);
406     }
407
408
409     /**************************************************************************
410      * Private/Protected methods of This class:
411      **************************************************************************
412      */

413
414     /**
415      * Set scan position to just after current page.
416      * <p>
417      * Used to set the position of the scan if a record handle is not
418      * avaliable. In this case current_rh will be set to null, and
419      * current_pageno will be set to the current page number.
420      * On resume of the scan, the scan will be set to just before the first
421      * row returned form a getNextPage(current_pageno) call.
422      * <p>
423      * A positionAtResumeScan(scan_position) is necessary to continue the
424      * scan after this call.
425      *
426      * @exception StandardException Standard exception policy.
427      **/

428     private void positionAfterThisPage(
429     RowPosition pos)
430         throws StandardException
431     {
432         pos.current_rh = null;
433         pos.current_pageno = pos.current_page.getPageNumber();
434     }
435
436     /*
437     ** Methods of ScanManager
438     */

439
440 }
441
Popular Tags