|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.221 2006/11/05 22:42:07 tgl Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.222 2006/11/17 18:00:14 tgl Exp $ |
12 | 12 | *
|
13 | 13 | *
|
14 | 14 | * INTERFACE ROUTINES
|
@@ -2359,6 +2359,8 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, Buffer *buffer,
|
2359 | 2359 | ItemId lp;
|
2360 | 2360 | PageHeader dp;
|
2361 | 2361 | TransactionId xid;
|
| 2362 | + TransactionId xmax; |
| 2363 | + uint16 old_infomask; |
2362 | 2364 | uint16 new_infomask;
|
2363 | 2365 | LOCKMODE tuple_lock_type;
|
2364 | 2366 | bool have_tuple_lock = false;
|
@@ -2395,6 +2397,25 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, Buffer *buffer,
|
2395 | 2397 |
|
2396 | 2398 | LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
|
2397 | 2399 |
|
| 2400 | + /* |
| 2401 | + * If we wish to acquire share lock, and the tuple is already |
| 2402 | + * share-locked by a multixact that includes any subtransaction of the |
| 2403 | + * current top transaction, then we effectively hold the desired lock |
| 2404 | + * already. We *must* succeed without trying to take the tuple lock, |
| 2405 | + * else we will deadlock against anyone waiting to acquire exclusive |
| 2406 | + * lock. We don't need to make any state changes in this case. |
| 2407 | + */ |
| 2408 | + if (mode == LockTupleShared && |
| 2409 | + (infomask & HEAP_XMAX_IS_MULTI) && |
| 2410 | + MultiXactIdIsCurrent((MultiXactId) xwait)) |
| 2411 | + { |
| 2412 | + Assert(infomask & HEAP_XMAX_SHARED_LOCK); |
| 2413 | + /* Probably can't hold tuple lock here, but may as well check */ |
| 2414 | + if (have_tuple_lock) |
| 2415 | + UnlockTuple(relation, tid, tuple_lock_type); |
| 2416 | + return HeapTupleMayBeUpdated; |
| 2417 | + } |
| 2418 | + |
2398 | 2419 | /*
|
2399 | 2420 | * Acquire tuple lock to establish our priority for the tuple.
|
2400 | 2421 | * LockTuple will release us when we are next-in-line for the tuple.
|
@@ -2532,26 +2553,50 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, Buffer *buffer,
|
2532 | 2553 | return result;
|
2533 | 2554 | }
|
2534 | 2555 |
|
| 2556 | + /* |
| 2557 | + * We might already hold the desired lock (or stronger), possibly under |
| 2558 | + * a different subtransaction of the current top transaction. If so, |
| 2559 | + * there is no need to change state or issue a WAL record. We already |
| 2560 | + * handled the case where this is true for xmax being a MultiXactId, |
| 2561 | + * so now check for cases where it is a plain TransactionId. |
| 2562 | + * |
| 2563 | + * Note in particular that this covers the case where we already hold |
| 2564 | + * exclusive lock on the tuple and the caller only wants shared lock. |
| 2565 | + * It would certainly not do to give up the exclusive lock. |
| 2566 | + */ |
| 2567 | + xmax = HeapTupleHeaderGetXmax(tuple->t_data); |
| 2568 | + old_infomask = tuple->t_data->t_infomask; |
| 2569 | + |
| 2570 | + if (!(old_infomask & (HEAP_XMAX_INVALID | |
| 2571 | + HEAP_XMAX_COMMITTED | |
| 2572 | + HEAP_XMAX_IS_MULTI)) && |
| 2573 | + (mode == LockTupleShared ? |
| 2574 | + (old_infomask & HEAP_IS_LOCKED) : |
| 2575 | + (old_infomask & HEAP_XMAX_EXCL_LOCK)) && |
| 2576 | + TransactionIdIsCurrentTransactionId(xmax)) |
| 2577 | + { |
| 2578 | + LockBuffer(*buffer, BUFFER_LOCK_UNLOCK); |
| 2579 | + /* Probably can't hold tuple lock here, but may as well check */ |
| 2580 | + if (have_tuple_lock) |
| 2581 | + UnlockTuple(relation, tid, tuple_lock_type); |
| 2582 | + return HeapTupleMayBeUpdated; |
| 2583 | + } |
| 2584 | + |
2535 | 2585 | /*
|
2536 | 2586 | * Compute the new xmax and infomask to store into the tuple. Note we do
|
2537 | 2587 | * not modify the tuple just yet, because that would leave it in the wrong
|
2538 | 2588 | * state if multixact.c elogs.
|
2539 | 2589 | */
|
2540 | 2590 | xid = GetCurrentTransactionId();
|
2541 | 2591 |
|
2542 |
| - new_infomask = tuple->t_data->t_infomask; |
2543 |
| - |
2544 |
| - new_infomask &= ~(HEAP_XMAX_COMMITTED | |
2545 |
| - HEAP_XMAX_INVALID | |
2546 |
| - HEAP_XMAX_IS_MULTI | |
2547 |
| - HEAP_IS_LOCKED | |
2548 |
| - HEAP_MOVED); |
| 2592 | + new_infomask = old_infomask & ~(HEAP_XMAX_COMMITTED | |
| 2593 | + HEAP_XMAX_INVALID | |
| 2594 | + HEAP_XMAX_IS_MULTI | |
| 2595 | + HEAP_IS_LOCKED | |
| 2596 | + HEAP_MOVED); |
2549 | 2597 |
|
2550 | 2598 | if (mode == LockTupleShared)
|
2551 | 2599 | {
|
2552 |
| - TransactionId xmax = HeapTupleHeaderGetXmax(tuple->t_data); |
2553 |
| - uint16 old_infomask = tuple->t_data->t_infomask; |
2554 |
| - |
2555 | 2600 | /*
|
2556 | 2601 | * If this is the first acquisition of a shared lock in the current
|
2557 | 2602 | * transaction, set my per-backend OldestMemberMXactId setting. We can
|
@@ -2592,32 +2637,13 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, Buffer *buffer,
|
2592 | 2637 | }
|
2593 | 2638 | else if (TransactionIdIsInProgress(xmax))
|
2594 | 2639 | {
|
2595 |
| - if (TransactionIdEquals(xmax, xid)) |
2596 |
| - { |
2597 |
| - /* |
2598 |
| - * If the old locker is ourselves, we'll just mark the |
2599 |
| - * tuple again with our own TransactionId. However we |
2600 |
| - * have to consider the possibility that we had exclusive |
2601 |
| - * rather than shared lock before --- if so, be careful to |
2602 |
| - * preserve the exclusivity of the lock. |
2603 |
| - */ |
2604 |
| - if (!(old_infomask & HEAP_XMAX_SHARED_LOCK)) |
2605 |
| - { |
2606 |
| - new_infomask &= ~HEAP_XMAX_SHARED_LOCK; |
2607 |
| - new_infomask |= HEAP_XMAX_EXCL_LOCK; |
2608 |
| - mode = LockTupleExclusive; |
2609 |
| - } |
2610 |
| - } |
2611 |
| - else |
2612 |
| - { |
2613 |
| - /* |
2614 |
| - * If the Xmax is a valid TransactionId, then we need to |
2615 |
| - * create a new MultiXactId that includes both the old |
2616 |
| - * locker and our own TransactionId. |
2617 |
| - */ |
2618 |
| - xid = MultiXactIdCreate(xmax, xid); |
2619 |
| - new_infomask |= HEAP_XMAX_IS_MULTI; |
2620 |
| - } |
| 2640 | + /* |
| 2641 | + * If the XMAX is a valid TransactionId, then we need to |
| 2642 | + * create a new MultiXactId that includes both the old |
| 2643 | + * locker and our own TransactionId. |
| 2644 | + */ |
| 2645 | + xid = MultiXactIdCreate(xmax, xid); |
| 2646 | + new_infomask |= HEAP_XMAX_IS_MULTI; |
2621 | 2647 | }
|
2622 | 2648 | else
|
2623 | 2649 | {
|
|
0 commit comments