KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.store.access.btree.index.B2IRowLocking3
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.index;
23
24 import org.apache.derby.iapi.services.sanity.SanityManager;
25
26 import org.apache.derby.iapi.error.StandardException;
27
28 import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;
29
30 import org.apache.derby.iapi.store.access.ConglomerateController;
31
32 import org.apache.derby.iapi.store.access.RowUtil;
33 import org.apache.derby.iapi.store.access.TransactionController;
34
35 import org.apache.derby.iapi.store.raw.FetchDescriptor;
36 import org.apache.derby.iapi.store.raw.LockingPolicy;
37 import org.apache.derby.iapi.store.raw.Page;
38 import org.apache.derby.iapi.store.raw.RecordHandle;
39 import org.apache.derby.iapi.store.raw.Transaction;
40
41 import org.apache.derby.iapi.types.DataValueDescriptor;
42
43 import org.apache.derby.iapi.types.RowLocation;
44
45 import org.apache.derby.impl.store.access.btree.BTree;
46 import org.apache.derby.impl.store.access.btree.BTreeLockingPolicy;
47 import org.apache.derby.impl.store.access.btree.ControlRow;
48 import org.apache.derby.impl.store.access.btree.LeafControlRow;
49 import org.apache.derby.impl.store.access.btree.OpenBTree;
50 import org.apache.derby.impl.store.access.btree.BTreeRowPosition;
51 import org.apache.derby.impl.store.access.btree.WaitError;
52
53 /**
54
55 Implements the jdbc serializable isolation level using row locks.
56 <p>
57 Holds read and write locks until end of transaction.
58 Obtains previous key locks to protect from phantom reads.
59
60 **/

61 class B2IRowLocking3 implements BTreeLockingPolicy
62 {
63
64     /**************************************************************************
65      * Private/Protected fields of This class:
66      **************************************************************************
67      */

68
69     /**
70      * The container id of the base container for this index. Used to build
71      * record handles to make lock calls on.
72      **/

73     protected ConglomerateController base_cc;
74
75     /**
76      * The OpenBtree to use if we have to lock anything in the btree vs.
77      * base row locking.
78      **/

79     protected OpenBTree open_btree;
80
81     /**
82      * The locking policy to use to get and release the scan locks. We could
83      * cache this somewhere better.
84      **/

85     private LockingPolicy scan_locking_policy;
86
87     /**
88      * The transaction to associate lock requests with.
89      **/

90     private Transaction rawtran;
91
92     /**************************************************************************
93      * Constructors for This class:
94      **************************************************************************
95      */

96     B2IRowLocking3(
97     Transaction rawtran,
98     int lock_level,
99     LockingPolicy locking_policy,
100     ConglomerateController base_cc,
101     OpenBTree open_btree)
102     {
103         this.rawtran = rawtran;
104         this.base_cc = base_cc;
105         this.open_btree = open_btree;
106         this.scan_locking_policy =
107             rawtran.newLockingPolicy(
108                 LockingPolicy.MODE_RECORD,
109                 TransactionController.ISOLATION_READ_COMMITTED, true);
110     }
111
112     /**************************************************************************
113      * Private methods of This class:
114      **************************************************************************
115      */

116
117     private boolean _lockScan(
118     RecordHandle rh,
119     boolean forUpdate,
120     boolean wait)
121         throws StandardException
122     {
123         boolean ret_val = true;
124
125         // only get the scan lock if we are record locking.
126

127         if (!forUpdate)
128         {
129             ret_val =
130                 scan_locking_policy.lockRecordForRead(
131                     rawtran, open_btree.getContainerHandle(),
132                     rh, wait, false);
133         }
134         else
135         {
136             ret_val =
137                 scan_locking_policy.lockRecordForWrite(
138                     rawtran, rh, false, wait);
139         }
140
141         return(ret_val);
142     }
143
144     /**
145      * Lock key previous to first key in btree.
146      * <p>
147      * In the previous key locking protocol repeatable read and phantom
148      * protection is guaranteed by locking a range of keys in the btree.
149      * The range is defined by the key previous to the first key you look
150      * at and all subsequent keys you look at. The first key in the index
151      * is a special case, as there are no keys previous to it. In that
152      * case a special key is declared the "previous key" to the first key
153      * in the btree and is locked instead.
154      * <p>
155      * In this implementation that first key is defined to be in the base
156      * container, page ContainerHandle.FIRST_PAGE_NUMBER, record id
157      * PREVIOUS_KEY_HANDLE.
158      * <p>
159      * Note that the previous key is the same for all indexes on a given
160      * conglomerate. It seemed better for all locks on a base table to have
161      * the same containerid, rather than having some locks generated from
162      * a btree have a containerid from base table and some having a containerid
163      * from the btree. If this turns out to be a problem we could either
164      * have 2 different containerid's, be more creative with the record id, or
165      * even add more to the lock key.
166      *
167      * @param aux_leaf If non-null, this leaf is unlatched if the
168      * routine has to wait on the lock.
169      * @param lock_operation Whether to lock exclusive or share.
170      * @param lock_duration For what duration should the lock be held,
171      * if INSTANT_DURATION, then the routine will
172      * guarantee that lock was acquired while holding
173      * the latch, but then immediately release the
174      * lock. If COMMIT_DURATION or MANUAL_DURATION
175      * then the lock be held when routine returns
176      * successfully.
177      *
178      * @exception StandardException Standard exception policy.
179      **/

180     private boolean lockPreviousToFirstKey(
181     LeafControlRow current_leaf,
182     LeafControlRow aux_leaf,
183     int lock_operation,
184     int lock_duration)
185         throws StandardException
186     {
187         // This is first row in table, lock the special key that
188
// represents the key previous to the first key of the table.
189

190         // First try to get the lock NOWAIT, while latch is held.
191
boolean ret_status =
192             base_cc.lockRow(
193                 BTree.ROOTPAGEID,
194                 RecordHandle.PREVIOUS_KEY_HANDLE,
195                 lock_operation,
196                 false /* NOWAIT */,
197                 lock_duration);
198
199         if (!ret_status)
200         {
201             current_leaf.release();
202             current_leaf = null;
203
204             if (aux_leaf != null)
205             {
206                 aux_leaf.release();
207                 aux_leaf = null;
208             }
209
210             // Couldn't get the lock NOWAIT, release latch and wait for lock.
211
base_cc.lockRow(
212                 BTree.ROOTPAGEID,
213                 RecordHandle.PREVIOUS_KEY_HANDLE,
214                 lock_operation,
215                 true /* WAIT */,
216                 lock_duration);
217         }
218
219         return(ret_status);
220     }
221
222
223     /**
224      * Lock a btree row (row is at given slot in page).
225      * <p>
226      * Lock the row at the given slot in the page. Meant to be used if caller
227      * only has the slot on the page to be locked, and has not read the row
228      * yet. This routine fetches the row location field from the page, and then
229      * locks that rowlocation in the base container.
230      * <p>
231      * Lock a btree row, enforcing the standard lock/latch protocol.
232      * On return the row is locked. Return status indicates if the lock
233      * was waited for, which will mean a latch was dropped while waiting.
234      * In general a false status means that the caller will either have
235      * to research the tree unless some protocol has been implemented that
236      * insures that the row will not have moved while the latch was dropped.
237      * <p>
238      * This routine request a row lock NOWAIT on the in-memory row
239      * "current_row.". If the lock is granted the routine will return true.
240      * If the lock cannot be granted NOWAIT, then the routine will release
241      * the latch on "current_leaf" and "aux_leaf" (if aux_leaf is non-null),
242      * and then it will request a WAIT lock on the row.
243      * <p>
244      *
245      * @param btree The conglomerate we are locking.
246      * @param current_leaf Latched current leaf where "current" key is.
247      * @param aux_leaf If non-null, this leaf is unlatched if the
248      * routine has to wait on the lock.
249      * @param current_slot Slot of row to lock.
250      * @param lock_fetch_desc Descriptor for fetching just the RowLocation,
251      * used for locking.
252      * @param check_changed_rowloc
253      * whether to check for the changed rowloc or not.
254      * @param lock_operation Whether lock is for key prev to insert or not.
255      * @param lock_duration For what duration should the lock be held,
256      * if INSTANT_DURATION, then the routine will
257      * guarantee that lock was acquired while holding
258      * the latch, but then immediately release the
259      * lock. If COMMIT_DURATION or MANUAL_DURATION
260      * then the lock be held when routine returns
261      * successfully.
262      *
263      * @exception StandardException Standard exception policy.
264      **/

265     private boolean lockRowOnPage(
266     BTree btree,
267     LeafControlRow current_leaf,
268     LeafControlRow aux_leaf,
269     int current_slot,
270     boolean check_changed_rowloc,
271     FetchDescriptor lock_fetch_desc,
272     DataValueDescriptor[] lock_template,
273     RowLocation lock_row_loc,
274     int lock_operation,
275     int lock_duration)
276         throws StandardException
277     {
278         if (SanityManager.DEBUG)
279         {
280             SanityManager.ASSERT(current_leaf != null);
281
282             if (current_slot <= 0 ||
283                 current_slot >= current_leaf.getPage().recordCount())
284             {
285                 SanityManager.THROWASSERT(
286                     "current_slot = " + current_slot +
287                     "; current_leaf.getPage().recordCount() = " +
288                         current_leaf.getPage().recordCount());
289             }
290
291
292             if (!(btree instanceof B2I))
293             {
294                 SanityManager.THROWASSERT(
295                     "btree not instance of B2I, it is " +
296                     btree.getClass().getName());
297             }
298
299             SanityManager.ASSERT(lock_template != null, "template is null");
300
301             // For now the RowLocation is expected to be the object located in
302
// the last column of the lock_template, this may change if we
303
// ever support rows with RowLocations somewhere else.
304
SanityManager.ASSERT(
305                 lock_row_loc == lock_template[lock_template.length - 1],
306                 "row_loc is not the object in last column of lock_template.");
307         }
308
309         // Fetch the row location to lock.
310
RecordHandle rec_handle =
311             current_leaf.getPage().fetchFromSlot(
312                 (RecordHandle) null, current_slot,
313                 lock_template, lock_fetch_desc, true);
314
315         // First try to get the lock NOWAIT, while latch is held.
316
boolean ret_status =
317             base_cc.lockRow(
318                 lock_row_loc,
319                 lock_operation,
320                 false /* NOWAIT */, lock_duration);
321
322         if (!ret_status)
323         {
324             // Could not get the lock NOWAIT, release latch and wait for lock.
325

326             if (current_leaf != null)
327             {
328                 current_leaf.release();
329                 current_leaf = null;
330             }
331             if (aux_leaf != null)
332             {
333                 aux_leaf.release();
334                 aux_leaf = null;
335             }
336
337             base_cc.lockRow(
338                 lock_row_loc,
339                 lock_operation,
340                 true /* WAIT */, lock_duration);
341         }
342
343         return(ret_status);
344     }
345
346     private boolean searchLeftAndLockPreviousKey(
347     B2I b2i,
348     LeafControlRow current_leaf,
349     int current_slot,
350     FetchDescriptor lock_fetch_desc,
351     DataValueDescriptor[] lock_template,
352     RowLocation lock_row_loc,
353     OpenBTree open_btree,
354     int lock_operation,
355     int lock_duration)
356         throws StandardException
357     {
358         boolean latches_released = false;
359         LeafControlRow prev_leaf;
360         LeafControlRow prev_prev_leaf;
361
362         try
363         {
364             // Move left in tree, page latch will be requested nowait,
365
// and WaitError will be thrown if latch not granted.
366

367             prev_leaf =
368                 (LeafControlRow) current_leaf.getLeftSibling(open_btree);
369
370         }
371         catch (WaitError e)
372         {
373             long previous_pageno = current_leaf.getleftSiblingPageNumber();
374
375             // error going from mainpage to first left page. Release
376
// current page latch and continue the search.
377
current_leaf.release();
378             current_leaf = null;
379
380             // wait on the left page, which we could not get before.
381
prev_leaf = (LeafControlRow)
382                 ControlRow.Get(open_btree, previous_pageno);
383
384             latches_released = true;
385         }
386        
387         while (true)
388         {
389             try
390             {
391                 // loop searching left in the btree until you either find
392
// a record to lock, or you reach the leftmost empty leaf.
393

394                 if (prev_leaf.getPage().recordCount() > 1)
395                 {
396                     // lock the last row on the page, which is the previous
397
// record to the first row on the next page.
398

399                     boolean ret_status =
400                         lockRowOnPage(
401                             b2i,
402                             prev_leaf,
403                             current_leaf,
404                             prev_leaf.getPage().recordCount() - 1,
405                             false,
406                             lock_fetch_desc,
407                             lock_template,
408                             lock_row_loc,
409                             lock_operation,
410                             lock_duration);
411
412                     if (!ret_status)
413                     {
414                         prev_leaf = null;
415                         current_leaf = null;
416                         latches_released = true;
417                     }
418
419                     break;
420                 }
421                 else if (prev_leaf.isLeftmostLeaf())
422                 {
423                     // Table's first row, lock the key that represents the
424
// key previous to first key of the table.
425
boolean ret_status =
426                         lockPreviousToFirstKey(
427                             prev_leaf, current_leaf,
428                             lock_operation, lock_duration);
429
430                     if (!ret_status)
431                     {
432                         prev_leaf = null;
433                         current_leaf = null;
434                         latches_released = true;
435                     }
436
437                     break;
438                 }
439
440                 // Move left in tree, page latch will be requested nowait,
441
// and WaitError will be thrown if latch not granted.
442
// Release latches on pages between "current_leaf" and
443
// where the search leads, so that at most 3 latched pages
444
// (current_leaf, prev_leaf, prev_prev_leaf) are held during
445
// the search. Do left ladder locking as you walk left,
446
// but be ready to release l
447

448                 prev_prev_leaf =
449                     (LeafControlRow) prev_leaf.getLeftSibling(open_btree);
450                 prev_leaf.release();
451                 prev_leaf = prev_prev_leaf;
452                 prev_prev_leaf = null;
453             }
454             catch (WaitError e)
455             {
456                 long previous_pageno = prev_leaf.getleftSiblingPageNumber();
457
458                 // error going left. Release current page latch and
459
// original page latch continue the search.
460
current_leaf.release();
461                 current_leaf = null;
462                 prev_leaf.release();
463                 prev_leaf = null;
464
465                 // wait on the left page, which we could not get before.
466
prev_leaf = (LeafControlRow)
467                     ControlRow.Get(open_btree, previous_pageno);
468
469                 latches_released = true;
470             }
471         }
472         if (prev_leaf != null)
473             prev_leaf.release();
474
475         return(!latches_released);
476
477     }
478
479     /**************************************************************************
480      * Protected methods of This class:
481      **************************************************************************
482      */

483
484     /**
485      * Lock a row as part of doing the scan.
486      * <p>
487      * Lock the row at the given slot (or the previous row if slot is 0).
488      * Get the scan lock on the page if "request_scan_lock" is true.
489      * <p>
490      * If this routine returns true all locks were acquired while maintaining
491      * the latch on leaf. If this routine returns false, locks may or may
492      * not have been acquired, and the routine should be called again after
493      * the client has researched the tree to reget the latch on the
494      * appropriate page.
495      * (p>
496      * As a sided effect stores the value of the record handle of the current
497      * scan lock.
498      *
499      * @return Whether locks were acquired without releasing latch on leaf.
500      *
501      * @param open_btree The open_btree to associate latches with -
502      * used if routine has to scan backward.
503      * @param btree the conglomerate info.
504      * @param pos The position of the row to lock.
505      * @param request_row_lock Whether to request the row lock, should
506      * only be requested once per page in the scan.
507      * @param request_scan_lock Whether to request the page scan lock, should
508      * only be requested once per page in the scan.
509      * @param lock_fetch_desc The fetch descriptor to use to fetch the
510      * row location for the lock request.
511      * @param lock_template A scratch area to use to read in rows.
512      * @param previous_key_lock Is this a previous key lock call?
513      * @param forUpdate Is the scan for update or for read only.
514      *
515      * @exception StandardException Standard exception policy.
516      **/

517     protected boolean _lockScanRow(
518     OpenBTree open_btree,
519     BTree btree,
520     BTreeRowPosition pos,
521     boolean request_row_lock,
522     boolean request_scan_lock,
523     FetchDescriptor lock_fetch_desc,
524     DataValueDescriptor[] lock_template,
525     RowLocation lock_row_loc,
526     boolean previous_key_lock,
527     boolean forUpdate,
528     int lock_operation)
529         throws StandardException
530     {
531         boolean latch_released = false;
532         B2I b2i = (B2I) btree;
533
534         if (request_row_lock)
535         {
536             // In order to implement a serialized scan based on previous
537
// key locking, this method acquires a row lock on
538
// the base table's row from the index row at [startpage/startslot].
539
// This will be the 'previous key'.
540

541             if (pos.current_slot == 0)
542             {
543                 // this call will take care of searching left in the btree
544
// to find the previous row to lock, 0 is the control row and
545
// not a valid thing to lock as a previous key.
546

547                 // it is ok to call the non-scan as this is just a special
548
// case of a previous key lock call. The only scan code that
549
// will call this routine with slot == 0 will retry if this
550
// routine returns that a latch was released.
551

552                 latch_released =
553                     !lockNonScanPreviousRow(
554                         btree,
555                         pos.current_leaf,
556                         1 /* lock row previous to row at slot 1 */,
557                         lock_fetch_desc,
558                         lock_template,
559                         lock_row_loc,
560                         open_btree,
561                         lock_operation,
562                         TransactionManager.LOCK_COMMIT_DURATION);
563
564                 // special test to see if latch release code works
565
if (SanityManager.DEBUG)
566                 {
567                     latch_released =
568                         OpenBTree.test_errors(
569                             open_btree,
570                             "B2iRowLocking3_1_lockScanRow", false,
571                             this, pos.current_leaf, latch_released);
572                 }
573             }
574             else
575             {
576                 // Just lock the row at "slot"
577

578                 latch_released =
579                     !lockRowOnPage(
580                         btree,
581                         pos.current_leaf,
582                         (LeafControlRow) null /* no other latch currently */,
583                         pos.current_slot,
584                         true,
585                         lock_fetch_desc,
586                         lock_template,
587                         lock_row_loc,
588                         lock_operation,
589                         TransactionManager.LOCK_COMMIT_DURATION);
590
591                 // special test to see if latch release code works
592
if (SanityManager.DEBUG)
593                 {
594                     latch_released =
595                         OpenBTree.test_errors(
596                             open_btree,
597                             "B2iRowLocking3_2_lockScanRow", false,
598                             this, pos.current_leaf, latch_released);
599                 }
600             }
601         }
602
603         if (request_scan_lock && !latch_released)
604         {
605             // Get the scan lock on the start page.
606

607             // Get shared RECORD_ID_PROTECTION_HANDLE lock to make sure that
608
// we wait for scans in other transactions to move off of this page
609
// before we split.
610

611
612             latch_released =
613                 !lockScan(
614                     pos.current_leaf,
615                     (LeafControlRow) null, // no other latch currently
616
false,
617                     ConglomerateController.LOCK_READ);// read scan lock position
618

619             // special test to see if latch release code works
620
if (SanityManager.DEBUG)
621             {
622                 /* RESOLVE - need to get a container here */
623                 latch_released =
624                     OpenBTree.test_errors(
625                         open_btree,
626                         "B2iRowLocking3_3_lockScanRow", true,
627                         this, pos.current_leaf, latch_released);
628             }
629         }
630
631         return(!latch_released);
632     }
633
634     /**************************************************************************
635      * Public Methods of This class:
636      **************************************************************************
637      */

638
639
640     /**************************************************************************
641      * Abstract Protected lockScan*() locking methods of BTree:
642      * lockScan - lock the scan page
643      * lockScanForReclaimSpace - lock page for reclaiming deleted rows.
644      * lockScanRow - lock row and possibly the scan page
645      * unlockScan - unlock the scan page
646      * unlockScanRecordAfterRead- unlock the scan record
647      **************************************************************************
648      */

649
650     /**
651      * Lock a control row page for scan.
652      * <p>
653      * Scanners get shared lock on the page while positioned on a row within
654      * the page, splitter/purgers/mergers get exclusive lock on the page.
655      *
656      * See BTree.lockScan() for more info.
657      *
658      * @exception StandardException Standard exception policy.
659      **/

660     public boolean lockScan(
661     LeafControlRow current_leaf,
662     ControlRow aux_control_row,
663     boolean forUpdate,
664     int lock_operation)
665         throws StandardException
666     {
667         // The scan page lock is implemented as a row lock on the reserved
668
// row id on the page (RecordHandle.RECORD_ID_PROTECTION_HANDLE).
669
RecordHandle scan_lock_rh =
670             current_leaf.getPage().makeRecordHandle(
671                 RecordHandle.RECORD_ID_PROTECTION_HANDLE);
672
673         // First try to get the lock NOWAIT, while latch is held.
674
boolean ret_status =
675             _lockScan(scan_lock_rh, forUpdate, false /* NOWAIT */);
676
677         if (!ret_status)
678         {
679             current_leaf.release();
680             current_leaf = null;
681
682             if (aux_control_row != null)
683             {
684                 aux_control_row.release();
685                 aux_control_row = null;
686             }
687
688             // Could not get the lock NOWAIT, release latch and wait
689
// for the lock.
690
_lockScan(scan_lock_rh, forUpdate, true /* WAIT */);
691
692             // once we get the lock, give it up as we need to get the lock
693
// while we have the latch. When the lock manager gives us the
694
// ability to do instantaneous locks do that. We just wait on the
695
// lock to give the split a chance to finish before we interfere.
696

697             if (!forUpdate)
698             {
699                 scan_locking_policy.unlockRecordAfterRead(
700                     rawtran, open_btree.getContainerHandle(),
701                     scan_lock_rh, false, true);
702             }
703             else
704             {
705                 // RESOLVE - need instantaneous locks as there is no way
706
// currently to release a write lock. This lock will only
707
// be requested by split, and will be released by internal
708
// transaction.
709
}
710         }
711
712         return(ret_status);
713     }
714
715     /**
716      * Lock a control row page for reclaiming deleted rows.
717      * <p>
718      * When reclaiming deleted rows during split need to get an exclusive
719      * scan lock on the page, which will mean there are no other scans
720      * positioned on the page. If there are other scans positioned, just
721      * give up on reclaiming space now.
722      *
723      * @return true if lock was granted nowait, else false and not lock was
724      * granted.
725      *
726      * @exception StandardException Standard exception policy.
727      **/

728     public boolean lockScanForReclaimSpace(
729     LeafControlRow current_leaf)
730         throws StandardException
731     {
732         // The scan page lock is implemented as a row lock on the reserved
733
// row id on the page (RecordHandle.RECORD_ID_PROTECTION_HANDLE).
734
RecordHandle scan_lock_rh =
735             current_leaf.getPage().makeRecordHandle(
736                 RecordHandle.RECORD_ID_PROTECTION_HANDLE);
737
738         // First try to get the lock NOWAIT, while latch is held.
739
return(
740             _lockScan(scan_lock_rh, true /* update */, false /* NOWAIT */));
741     }
742
743     /**
744      * Lock a btree row to determine if it is a committed deleted row.
745      * <p>
746      * @see BTreeLockingPolicy#lockScanCommittedDeletedRow
747      *
748      * @exception StandardException Standard exception policy.
749      **/

750     public boolean lockScanCommittedDeletedRow(
751     OpenBTree open_btree,
752     LeafControlRow leaf,
753     DataValueDescriptor[] template,
754     FetchDescriptor lock_fetch_desc,
755     int slot_no)
756         throws StandardException
757     {
758         if (SanityManager.DEBUG)
759         {
760             SanityManager.ASSERT(leaf != null);
761
762             if (slot_no <= 0 || slot_no >= leaf.getPage().recordCount())
763             {
764                 SanityManager.THROWASSERT(
765                     "slot_no = " + slot_no +
766                     "; leaf.getPage().recordCount() = " +
767                         leaf.getPage().recordCount());
768             }
769
770             SanityManager.ASSERT(template != null, "template is null");
771         }
772
773         RowLocation row_loc = (RowLocation)
774             template[((B2I) open_btree.getConglomerate()).rowLocationColumn];
775
776         // Fetch the row location to lock.
777
leaf.getPage().fetchFromSlot(
778             (RecordHandle) null, slot_no, template, lock_fetch_desc, true);
779
780         // Request the lock NOWAIT, return status
781
return(
782             base_cc.lockRow(row_loc,
783                 ConglomerateController.LOCK_UPD,
784                 false /* NOWAIT */,
785                 TransactionManager.LOCK_COMMIT_DURATION));
786     }
787
788     /**
789      * Lock a row as part of doing the scan.
790      * <p>
791      * Lock the row at the given slot (or the previous row if slot is 0).
792      * Get the scan lock on the page if "request_scan_lock" is true.
793      * <p>
794      * If this routine returns true all locks were acquired while maintaining
795      * the latch on leaf. If this routine returns false, locks may or may
796      * not have been acquired, and the routine should be called again after
797      * the client has researched the tree to reget the latch on the
798      * appropriate page.
799      * (p>
800      * As a sided effect stores the value of the record handle of the current
801      * scan lock.
802      *
803      * @return Whether locks were acquired without releasing latch on leaf.
804      *
805      * @param open_btree The open_btree to associate latches with -
806      * used if routine has to scan backward.
807      * @param btree the conglomerate info.
808      * @param pos The position of the row to lock.
809      * @param request_scan_lock Whether to request the page scan lock, should
810      * only be requested once per page in the scan.
811      * @param lock_template A scratch area to use to read in rows.
812      * @param previous_key_lock Is this a previous key lock call?
813      * @param forUpdate Is the scan for update or for read only.
814      *
815      * @exception StandardException Standard exception policy.
816      **/

817     public boolean lockScanRow(
818     OpenBTree open_btree,
819     BTree btree,
820     BTreeRowPosition pos,
821     boolean request_scan_lock,
822     FetchDescriptor lock_fetch_desc,
823     DataValueDescriptor[] lock_template,
824     RowLocation lock_row_loc,
825     boolean previous_key_lock,
826     boolean forUpdate,
827     int lock_operation)
828         throws StandardException
829     {
830         return(
831             _lockScanRow(
832                 open_btree,
833                 btree,
834                 pos,
835                 true, // request the row lock (always true for iso 3 )
836
request_scan_lock,
837                 lock_fetch_desc,
838                 lock_template,
839                 lock_row_loc,
840                 previous_key_lock,
841                 forUpdate,
842                 lock_operation));
843     }
844
845     /**
846      * Release read lock on a row.
847      *
848      * For serializable, there is no work to do.
849      *
850      *
851      **/

852     public void unlockScanRecordAfterRead(
853     BTreeRowPosition pos,
854     boolean forUpdate)
855         throws StandardException
856     {
857         return;
858     }
859
860     /**
861      * Release the lock gotten by calling lockScan. This call can only be
862      * made to release read scan locks, write scan locks must be held until
863      * end of transaction.
864      * <p>
865      * See BTree.unlockScan() for more info.
866      *
867      **/

868     public void unlockScan(
869     long page_number)
870     {
871         // This is first row in table, lock the special key that
872
// represents the key previous to the first key of the table.
873
try
874         {
875             RecordHandle scan_lock_rh =
876                 open_btree.makeRecordHandle(
877                     page_number, RecordHandle.RECORD_ID_PROTECTION_HANDLE);
878
879             scan_locking_policy.unlockRecordAfterRead(
880                 rawtran, open_btree.getContainerHandle(),
881                 scan_lock_rh, false, true);
882         }
883         catch (StandardException se)
884         {
885             if (SanityManager.DEBUG)
886                 SanityManager.THROWASSERT("error from make RecordHandle.");
887         }
888
889     }
890
891     /**************************************************************************
892      * Abstract Protected lockNonScan*() locking methods of BTree:
893      *
894      * lockNonScanPreviousRow - lock the row previous to the current
895      * lockNonScanRow - lock the input row
896      **************************************************************************
897      */

898
899     /**
900      * Lock the row previous to the input row.
901      * <p>
902      * See BTree.lockPreviousRow() for more info.
903      *
904      * @exception StandardException Standard exception policy.
905      **/

906     public boolean lockNonScanPreviousRow(
907     BTree btree,
908     LeafControlRow current_leaf,
909     int current_slot,
910     FetchDescriptor lock_fetch_desc,
911     DataValueDescriptor[] lock_template,
912     RowLocation lock_row_loc,
913     OpenBTree open_btree,
914     int lock_operation,
915     int lock_duration)
916         throws StandardException
917     {
918         boolean ret_status;
919
920         if (SanityManager.DEBUG)
921         {
922             SanityManager.ASSERT(btree instanceof B2I);
923         }
924
925         if (current_slot > 1)
926         {
927             // Easy case, just lock the key previous to the current one.
928

929             // Lock (current_slot - 1)
930

931             ret_status =
932                 lockRowOnPage(
933                     btree,
934                     current_leaf, (LeafControlRow) null,
935                     current_slot - 1,
936                     false,
937                     lock_fetch_desc,
938                     lock_template,
939                     lock_row_loc,
940                     lock_operation, lock_duration);
941         }
942         else
943         {
944             // Should only be called while pointing at a valid location, 0
945
// is not a valid key slot - it is the control row.
946
if (SanityManager.DEBUG)
947                 SanityManager.ASSERT(current_slot == 1);
948
949             if (current_leaf.isLeftmostLeaf())
950             {
951                 // This is first row in table, lock the special key that
952
// represents the key previous to the first key of the table.
953
ret_status =
954                     lockPreviousToFirstKey(
955                         current_leaf, (LeafControlRow) null,
956                         lock_operation, lock_duration);
957             }
958             else
959             {
960                 // The previous key is on a previous page, search left
961
// through the pages to find the key to latch.
962

963                 // RESOLVE RLL (mikem) - do I need to do the
964
// RECORD_ID_PROTECTION_HANDLE lock.
965
// First guarantee that record id's will not move off this
966
// current page while searching for previous key, by getting
967
// the RECORD_ID_PROTECTION_HANDLE lock on the current page.
968
// Since we have a latch on the cur
969

970                 // RESOLVE RLL (mikem) - NO RECORD_ID PROTECTION IN EFFECT.
971
// caller must research, get new locks if this routine
972
// releases latches.
973
ret_status = this.searchLeftAndLockPreviousKey(
974                     (B2I) btree,
975                     current_leaf, current_slot,
976                     lock_fetch_desc, lock_template, lock_row_loc,
977                     open_btree, lock_operation, lock_duration);
978             }
979         }
980
981         return(ret_status);
982     }
983
984     /**
985      * Lock the in memory row.
986      * <p>
987      * See BTree.lockRow() for more info.
988      *
989      * @exception StandardException Standard exception policy.
990      **/

991     public boolean lockNonScanRow(
992     BTree btree,
993     LeafControlRow current_leaf,
994     LeafControlRow aux_leaf,
995     DataValueDescriptor[] current_row,
996     int lock_operation)
997         throws StandardException
998     {
999         if (SanityManager.DEBUG)
1000        {
1001            SanityManager.ASSERT(btree instanceof B2I);
1002        }
1003        B2I b2i = (B2I) btree;
1004
1005        // First try to get the lock NOWAIT, while latch is held.
1006
boolean ret_status =
1007            base_cc.lockRow(
1008                (RowLocation) current_row[b2i.rowLocationColumn],
1009                lock_operation,
1010                false /* NOWAIT */,
1011                TransactionManager.LOCK_COMMIT_DURATION);
1012
1013        if (!ret_status)
1014        {
1015            // Could not get the lock NOWAIT, release latch and wait for lock.
1016

1017            if (current_leaf != null)
1018            {
1019                current_leaf.release();
1020                current_leaf = null;
1021            }
1022            if (aux_leaf != null)
1023            {
1024                aux_leaf.release();
1025                aux_leaf = null;
1026            }
1027
1028            base_cc.lockRow(
1029                (RowLocation) current_row[b2i.rowLocationColumn],
1030                lock_operation,
1031                true /* WAIT */,
1032                TransactionManager.LOCK_COMMIT_DURATION);
1033        }
1034
1035        return(ret_status);
1036    }
1037
1038    public boolean lockNonScanRowOnPage(
1039    BTree btree,
1040    LeafControlRow current_leaf,
1041    int current_slot,
1042    FetchDescriptor lock_fetch_desc,
1043    DataValueDescriptor[] lock_template,
1044    RowLocation lock_row_loc,
1045    int lock_operation)
1046        throws StandardException
1047    {
1048        return(
1049            lockRowOnPage(
1050                btree,
1051                current_leaf,
1052                null,
1053                current_slot,
1054                false,
1055                lock_fetch_desc,
1056                lock_template,
1057                lock_row_loc,
1058                lock_operation,
1059                TransactionManager.LOCK_COMMIT_DURATION));
1060    }
1061}
1062
Popular Tags