~ubuntu-branches/ubuntu/hardy/postgresql-8.4/hardy-backports

« back to all changes in this revision

Viewing changes to src/backend/storage/lmgr/lock.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-03-20 12:00:13 UTC
  • Revision ID: james.westby@ubuntu.com-20090320120013-hogj7egc5mjncc5g
Tags: upstream-8.4~0cvs20090328
ImportĀ upstreamĀ versionĀ 8.4~0cvs20090328

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * lock.c
 
4
 *        POSTGRES primary lock mechanism
 
5
 *
 
6
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        $PostgreSQL$
 
12
 *
 
13
 * NOTES
 
14
 *        A lock table is a shared memory hash table.  When
 
15
 *        a process tries to acquire a lock of a type that conflicts
 
16
 *        with existing locks, it is put to sleep using the routines
 
17
 *        in storage/lmgr/proc.c.
 
18
 *
 
19
 *        For the most part, this code should be invoked via lmgr.c
 
20
 *        or another lock-management module, not directly.
 
21
 *
 
22
 *      Interface:
 
23
 *
 
24
 *      InitLocks(), GetLocksMethodTable(),
 
25
 *      LockAcquire(), LockRelease(), LockReleaseAll(),
 
26
 *      LockCheckConflicts(), GrantLock()
 
27
 *
 
28
 *-------------------------------------------------------------------------
 
29
 */
 
30
#include "postgres.h"
 
31
 
 
32
#include <signal.h>
 
33
#include <unistd.h>
 
34
 
 
35
#include "access/transam.h"
 
36
#include "access/twophase.h"
 
37
#include "access/twophase_rmgr.h"
 
38
#include "miscadmin.h"
 
39
#include "pg_trace.h"
 
40
#include "pgstat.h"
 
41
#include "utils/memutils.h"
 
42
#include "utils/ps_status.h"
 
43
#include "utils/resowner.h"
 
44
 
 
45
 
 
46
/* This configuration variable is used to set the lock table size */
 
47
int                     max_locks_per_xact; /* set by guc.c */
 
48
 
 
49
#define NLOCKENTS() \
 
50
        mul_size(max_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
 
51
 
 
52
 
 
53
/*
 
54
 * Data structures defining the semantics of the standard lock methods.
 
55
 *
 
56
 * The conflict table defines the semantics of the various lock modes.
 
57
 */
 
58
static const LOCKMASK LockConflicts[] = {
 
59
        0,
 
60
 
 
61
        /* AccessShareLock */
 
62
        (1 << AccessExclusiveLock),
 
63
 
 
64
        /* RowShareLock */
 
65
        (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
 
66
 
 
67
        /* RowExclusiveLock */
 
68
        (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
 
69
        (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
 
70
 
 
71
        /* ShareUpdateExclusiveLock */
 
72
        (1 << ShareUpdateExclusiveLock) |
 
73
        (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
 
74
        (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
 
75
 
 
76
        /* ShareLock */
 
77
        (1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
 
78
        (1 << ShareRowExclusiveLock) |
 
79
        (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
 
80
 
 
81
        /* ShareRowExclusiveLock */
 
82
        (1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
 
83
        (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
 
84
        (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
 
85
 
 
86
        /* ExclusiveLock */
 
87
        (1 << RowShareLock) |
 
88
        (1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
 
89
        (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
 
90
        (1 << ExclusiveLock) | (1 << AccessExclusiveLock),
 
91
 
 
92
        /* AccessExclusiveLock */
 
93
        (1 << AccessShareLock) | (1 << RowShareLock) |
 
94
        (1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
 
95
        (1 << ShareLock) | (1 << ShareRowExclusiveLock) |
 
96
        (1 << ExclusiveLock) | (1 << AccessExclusiveLock)
 
97
 
 
98
};
 
99
 
 
100
/* Names of lock modes, for debug printouts */
 
101
static const char *const lock_mode_names[] =
 
102
{
 
103
        "INVALID",
 
104
        "AccessShareLock",
 
105
        "RowShareLock",
 
106
        "RowExclusiveLock",
 
107
        "ShareUpdateExclusiveLock",
 
108
        "ShareLock",
 
109
        "ShareRowExclusiveLock",
 
110
        "ExclusiveLock",
 
111
        "AccessExclusiveLock"
 
112
};
 
113
 
 
114
#ifndef LOCK_DEBUG
 
115
static bool Dummy_trace = false;
 
116
#endif
 
117
 
 
118
static const LockMethodData default_lockmethod = {
 
119
        AccessExclusiveLock,            /* highest valid lock mode number */
 
120
        true,
 
121
        LockConflicts,
 
122
        lock_mode_names,
 
123
#ifdef LOCK_DEBUG
 
124
        &Trace_locks
 
125
#else
 
126
        &Dummy_trace
 
127
#endif
 
128
};
 
129
 
 
130
static const LockMethodData user_lockmethod = {
 
131
        AccessExclusiveLock,            /* highest valid lock mode number */
 
132
        false,
 
133
        LockConflicts,
 
134
        lock_mode_names,
 
135
#ifdef LOCK_DEBUG
 
136
        &Trace_userlocks
 
137
#else
 
138
        &Dummy_trace
 
139
#endif
 
140
};
 
141
 
 
142
/*
 
143
 * map from lock method id to the lock table data structures
 
144
 */
 
145
static const LockMethod LockMethods[] = {
 
146
        NULL,
 
147
        &default_lockmethod,
 
148
        &user_lockmethod
 
149
};
 
150
 
 
151
 
 
152
/* Record that's written to 2PC state file when a lock is persisted */
 
153
typedef struct TwoPhaseLockRecord
 
154
{
 
155
        LOCKTAG         locktag;
 
156
        LOCKMODE        lockmode;
 
157
} TwoPhaseLockRecord;
 
158
 
 
159
 
 
160
/*
 
161
 * Pointers to hash tables containing lock state
 
162
 *
 
163
 * The LockMethodLockHash and LockMethodProcLockHash hash tables are in
 
164
 * shared memory; LockMethodLocalHash is local to each backend.
 
165
 */
 
166
static HTAB *LockMethodLockHash;
 
167
static HTAB *LockMethodProcLockHash;
 
168
static HTAB *LockMethodLocalHash;
 
169
 
 
170
 
 
171
/* private state for GrantAwaitedLock */
 
172
static LOCALLOCK *awaitedLock;
 
173
static ResourceOwner awaitedOwner;
 
174
 
 
175
 
 
176
#ifdef LOCK_DEBUG
 
177
 
 
178
/*------
 
179
 * The following configuration options are available for lock debugging:
 
180
 *
 
181
 *         TRACE_LOCKS          -- give a bunch of output what's going on in this file
 
182
 *         TRACE_USERLOCKS      -- same but for user locks
 
183
 *         TRACE_LOCK_OIDMIN-- do not trace locks for tables below this oid
 
184
 *                                                 (use to avoid output on system tables)
 
185
 *         TRACE_LOCK_TABLE -- trace locks on this table (oid) unconditionally
 
186
 *         DEBUG_DEADLOCKS      -- currently dumps locks at untimely occasions ;)
 
187
 *
 
188
 * Furthermore, but in storage/lmgr/lwlock.c:
 
189
 *         TRACE_LWLOCKS        -- trace lightweight locks (pretty useless)
 
190
 *
 
191
 * Define LOCK_DEBUG at compile time to get all these enabled.
 
192
 * --------
 
193
 */
 
194
 
 
195
int                     Trace_lock_oidmin = FirstNormalObjectId;
 
196
bool            Trace_locks = false;
 
197
bool            Trace_userlocks = false;
 
198
int                     Trace_lock_table = 0;
 
199
bool            Debug_deadlocks = false;
 
200
 
 
201
 
 
202
inline static bool
 
203
LOCK_DEBUG_ENABLED(const LOCKTAG *tag)
 
204
{
 
205
        return
 
206
                (*(LockMethods[tag->locktag_lockmethodid]->trace_flag) &&
 
207
                 ((Oid) tag->locktag_field2 >= (Oid) Trace_lock_oidmin))
 
208
                || (Trace_lock_table &&
 
209
                        (tag->locktag_field2 == Trace_lock_table));
 
210
}
 
211
 
 
212
 
 
213
inline static void
 
214
LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type)
 
215
{
 
216
        if (LOCK_DEBUG_ENABLED(&lock->tag))
 
217
                elog(LOG,
 
218
                         "%s: lock(%p) id(%u,%u,%u,%u,%u,%u) grantMask(%x) "
 
219
                         "req(%d,%d,%d,%d,%d,%d,%d)=%d "
 
220
                         "grant(%d,%d,%d,%d,%d,%d,%d)=%d wait(%d) type(%s)",
 
221
                         where, lock,
 
222
                         lock->tag.locktag_field1, lock->tag.locktag_field2,
 
223
                         lock->tag.locktag_field3, lock->tag.locktag_field4,
 
224
                         lock->tag.locktag_type, lock->tag.locktag_lockmethodid,
 
225
                         lock->grantMask,
 
226
                         lock->requested[1], lock->requested[2], lock->requested[3],
 
227
                         lock->requested[4], lock->requested[5], lock->requested[6],
 
228
                         lock->requested[7], lock->nRequested,
 
229
                         lock->granted[1], lock->granted[2], lock->granted[3],
 
230
                         lock->granted[4], lock->granted[5], lock->granted[6],
 
231
                         lock->granted[7], lock->nGranted,
 
232
                         lock->waitProcs.size,
 
233
                         LockMethods[LOCK_LOCKMETHOD(*lock)]->lockModeNames[type]);
 
234
}
 
235
 
 
236
 
 
237
inline static void
 
238
PROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP)
 
239
{
 
240
        if (LOCK_DEBUG_ENABLED(&proclockP->tag.myLock->tag))
 
241
                elog(LOG,
 
242
                         "%s: proclock(%p) lock(%p) method(%u) proc(%p) hold(%x)",
 
243
                         where, proclockP, proclockP->tag.myLock,
 
244
                         PROCLOCK_LOCKMETHOD(*(proclockP)),
 
245
                         proclockP->tag.myProc, (int) proclockP->holdMask);
 
246
}
 
247
#else                                                   /* not LOCK_DEBUG */
 
248
 
 
249
#define LOCK_PRINT(where, lock, type)
 
250
#define PROCLOCK_PRINT(where, proclockP)
 
251
#endif   /* not LOCK_DEBUG */
 
252
 
 
253
 
 
254
static uint32 proclock_hash(const void *key, Size keysize);
 
255
static void RemoveLocalLock(LOCALLOCK *locallock);
 
256
static void GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner);
 
257
static void WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner);
 
258
static bool UnGrantLock(LOCK *lock, LOCKMODE lockmode,
 
259
                        PROCLOCK *proclock, LockMethod lockMethodTable);
 
260
static void CleanUpLock(LOCK *lock, PROCLOCK *proclock,
 
261
                        LockMethod lockMethodTable, uint32 hashcode,
 
262
                        bool wakeupNeeded);
 
263
 
 
264
 
 
265
/*
 
266
 * InitLocks -- Initialize the lock manager's data structures.
 
267
 *
 
268
 * This is called from CreateSharedMemoryAndSemaphores(), which see for
 
269
 * more comments.  In the normal postmaster case, the shared hash tables
 
270
 * are created here, as well as a locallock hash table that will remain
 
271
 * unused and empty in the postmaster itself.  Backends inherit the pointers
 
272
 * to the shared tables via fork(), and also inherit an image of the locallock
 
273
 * hash table, which they proceed to use.  In the EXEC_BACKEND case, each
 
274
 * backend re-executes this code to obtain pointers to the already existing
 
275
 * shared hash tables and to create its locallock hash table.
 
276
 */
 
277
void
 
278
InitLocks(void)
 
279
{
 
280
        HASHCTL         info;
 
281
        int                     hash_flags;
 
282
        long            init_table_size,
 
283
                                max_table_size;
 
284
 
 
285
        /*
 
286
         * Compute init/max size to request for lock hashtables.  Note these
 
287
         * calculations must agree with LockShmemSize!
 
288
         */
 
289
        max_table_size = NLOCKENTS();
 
290
        init_table_size = max_table_size / 2;
 
291
 
 
292
        /*
 
293
         * Allocate hash table for LOCK structs.  This stores per-locked-object
 
294
         * information.
 
295
         */
 
296
        MemSet(&info, 0, sizeof(info));
 
297
        info.keysize = sizeof(LOCKTAG);
 
298
        info.entrysize = sizeof(LOCK);
 
299
        info.hash = tag_hash;
 
300
        info.num_partitions = NUM_LOCK_PARTITIONS;
 
301
        hash_flags = (HASH_ELEM | HASH_FUNCTION | HASH_PARTITION);
 
302
 
 
303
        LockMethodLockHash = ShmemInitHash("LOCK hash",
 
304
                                                                           init_table_size,
 
305
                                                                           max_table_size,
 
306
                                                                           &info,
 
307
                                                                           hash_flags);
 
308
        if (!LockMethodLockHash)
 
309
                elog(FATAL, "could not initialize lock hash table");
 
310
 
 
311
        /* Assume an average of 2 holders per lock */
 
312
        max_table_size *= 2;
 
313
        init_table_size *= 2;
 
314
 
 
315
        /*
 
316
         * Allocate hash table for PROCLOCK structs.  This stores
 
317
         * per-lock-per-holder information.
 
318
         */
 
319
        info.keysize = sizeof(PROCLOCKTAG);
 
320
        info.entrysize = sizeof(PROCLOCK);
 
321
        info.hash = proclock_hash;
 
322
        info.num_partitions = NUM_LOCK_PARTITIONS;
 
323
        hash_flags = (HASH_ELEM | HASH_FUNCTION | HASH_PARTITION);
 
324
 
 
325
        LockMethodProcLockHash = ShmemInitHash("PROCLOCK hash",
 
326
                                                                                   init_table_size,
 
327
                                                                                   max_table_size,
 
328
                                                                                   &info,
 
329
                                                                                   hash_flags);
 
330
        if (!LockMethodProcLockHash)
 
331
                elog(FATAL, "could not initialize proclock hash table");
 
332
 
 
333
        /*
 
334
         * Allocate non-shared hash table for LOCALLOCK structs.  This stores lock
 
335
         * counts and resource owner information.
 
336
         *
 
337
         * The non-shared table could already exist in this process (this occurs
 
338
         * when the postmaster is recreating shared memory after a backend crash).
 
339
         * If so, delete and recreate it.  (We could simply leave it, since it
 
340
         * ought to be empty in the postmaster, but for safety let's zap it.)
 
341
         */
 
342
        if (LockMethodLocalHash)
 
343
                hash_destroy(LockMethodLocalHash);
 
344
 
 
345
        info.keysize = sizeof(LOCALLOCKTAG);
 
346
        info.entrysize = sizeof(LOCALLOCK);
 
347
        info.hash = tag_hash;
 
348
        hash_flags = (HASH_ELEM | HASH_FUNCTION);
 
349
 
 
350
        LockMethodLocalHash = hash_create("LOCALLOCK hash",
 
351
                                                                          128,
 
352
                                                                          &info,
 
353
                                                                          hash_flags);
 
354
}
 
355
 
 
356
 
 
357
/*
 
358
 * Fetch the lock method table associated with a given lock
 
359
 */
 
360
LockMethod
 
361
GetLocksMethodTable(const LOCK *lock)
 
362
{
 
363
        LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*lock);
 
364
 
 
365
        Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));
 
366
        return LockMethods[lockmethodid];
 
367
}
 
368
 
 
369
 
 
370
/*
 
371
 * Compute the hash code associated with a LOCKTAG.
 
372
 *
 
373
 * To avoid unnecessary recomputations of the hash code, we try to do this
 
374
 * just once per function, and then pass it around as needed.  Aside from
 
375
 * passing the hashcode to hash_search_with_hash_value(), we can extract
 
376
 * the lock partition number from the hashcode.
 
377
 */
 
378
uint32
 
379
LockTagHashCode(const LOCKTAG *locktag)
 
380
{
 
381
        return get_hash_value(LockMethodLockHash, (const void *) locktag);
 
382
}
 
383
 
 
384
/*
 
385
 * Compute the hash code associated with a PROCLOCKTAG.
 
386
 *
 
387
 * Because we want to use just one set of partition locks for both the
 
388
 * LOCK and PROCLOCK hash tables, we have to make sure that PROCLOCKs
 
389
 * fall into the same partition number as their associated LOCKs.
 
390
 * dynahash.c expects the partition number to be the low-order bits of
 
391
 * the hash code, and therefore a PROCLOCKTAG's hash code must have the
 
392
 * same low-order bits as the associated LOCKTAG's hash code.  We achieve
 
393
 * this with this specialized hash function.
 
394
 */
 
395
static uint32
 
396
proclock_hash(const void *key, Size keysize)
 
397
{
 
398
        const PROCLOCKTAG *proclocktag = (const PROCLOCKTAG *) key;
 
399
        uint32          lockhash;
 
400
        Datum           procptr;
 
401
 
 
402
        Assert(keysize == sizeof(PROCLOCKTAG));
 
403
 
 
404
        /* Look into the associated LOCK object, and compute its hash code */
 
405
        lockhash = LockTagHashCode(&proclocktag->myLock->tag);
 
406
 
 
407
        /*
 
408
         * To make the hash code also depend on the PGPROC, we xor the proc
 
409
         * struct's address into the hash code, left-shifted so that the
 
410
         * partition-number bits don't change.  Since this is only a hash, we
 
411
         * don't care if we lose high-order bits of the address; use an
 
412
         * intermediate variable to suppress cast-pointer-to-int warnings.
 
413
         */
 
414
        procptr = PointerGetDatum(proclocktag->myProc);
 
415
        lockhash ^= ((uint32) procptr) << LOG2_NUM_LOCK_PARTITIONS;
 
416
 
 
417
        return lockhash;
 
418
}
 
419
 
 
420
/*
 
421
 * Compute the hash code associated with a PROCLOCKTAG, given the hashcode
 
422
 * for its underlying LOCK.
 
423
 *
 
424
 * We use this just to avoid redundant calls of LockTagHashCode().
 
425
 */
 
426
static inline uint32
 
427
ProcLockHashCode(const PROCLOCKTAG *proclocktag, uint32 hashcode)
 
428
{
 
429
        uint32          lockhash = hashcode;
 
430
        Datum           procptr;
 
431
 
 
432
        /*
 
433
         * This must match proclock_hash()!
 
434
         */
 
435
        procptr = PointerGetDatum(proclocktag->myProc);
 
436
        lockhash ^= ((uint32) procptr) << LOG2_NUM_LOCK_PARTITIONS;
 
437
 
 
438
        return lockhash;
 
439
}
 
440
 
 
441
 
 
442
/*
 
443
 * LockAcquire -- Check for lock conflicts, sleep if conflict found,
 
444
 *              set lock if/when no conflicts.
 
445
 *
 
446
 * Inputs:
 
447
 *      locktag: unique identifier for the lockable object
 
448
 *      lockmode: lock mode to acquire
 
449
 *      sessionLock: if true, acquire lock for session not current transaction
 
450
 *      dontWait: if true, don't wait to acquire lock
 
451
 *
 
452
 * Returns one of:
 
453
 *              LOCKACQUIRE_NOT_AVAIL           lock not available, and dontWait=true
 
454
 *              LOCKACQUIRE_OK                          lock successfully acquired
 
455
 *              LOCKACQUIRE_ALREADY_HELD        incremented count for lock already held
 
456
 *
 
457
 * In the normal case where dontWait=false and the caller doesn't need to
 
458
 * distinguish a freshly acquired lock from one already taken earlier in
 
459
 * this same transaction, there is no need to examine the return value.
 
460
 *
 
461
 * Side Effects: The lock is acquired and recorded in lock tables.
 
462
 *
 
463
 * NOTE: if we wait for the lock, there is no way to abort the wait
 
464
 * short of aborting the transaction.
 
465
 */
 
466
LockAcquireResult
 
467
LockAcquire(const LOCKTAG *locktag,
 
468
                        LOCKMODE lockmode,
 
469
                        bool sessionLock,
 
470
                        bool dontWait)
 
471
{
 
472
        LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
 
473
        LockMethod      lockMethodTable;
 
474
        LOCALLOCKTAG localtag;
 
475
        LOCALLOCK  *locallock;
 
476
        LOCK       *lock;
 
477
        PROCLOCK   *proclock;
 
478
        PROCLOCKTAG proclocktag;
 
479
        bool            found;
 
480
        ResourceOwner owner;
 
481
        uint32          hashcode;
 
482
        uint32          proclock_hashcode;
 
483
        int                     partition;
 
484
        LWLockId        partitionLock;
 
485
        int                     status;
 
486
 
 
487
        if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
 
488
                elog(ERROR, "unrecognized lock method: %d", lockmethodid);
 
489
        lockMethodTable = LockMethods[lockmethodid];
 
490
        if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
 
491
                elog(ERROR, "unrecognized lock mode: %d", lockmode);
 
492
 
 
493
#ifdef LOCK_DEBUG
 
494
        if (LOCK_DEBUG_ENABLED(locktag))
 
495
                elog(LOG, "LockAcquire: lock [%u,%u] %s",
 
496
                         locktag->locktag_field1, locktag->locktag_field2,
 
497
                         lockMethodTable->lockModeNames[lockmode]);
 
498
#endif
 
499
 
 
500
        /* Session locks are never transactional, else check table */
 
501
        if (!sessionLock && lockMethodTable->transactional)
 
502
                owner = CurrentResourceOwner;
 
503
        else
 
504
                owner = NULL;
 
505
 
 
506
        /*
 
507
         * Find or create a LOCALLOCK entry for this lock and lockmode
 
508
         */
 
509
        MemSet(&localtag, 0, sizeof(localtag));         /* must clear padding */
 
510
        localtag.lock = *locktag;
 
511
        localtag.mode = lockmode;
 
512
 
 
513
        locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
 
514
                                                                                  (void *) &localtag,
 
515
                                                                                  HASH_ENTER, &found);
 
516
 
 
517
        /*
 
518
         * if it's a new locallock object, initialize it
 
519
         */
 
520
        if (!found)
 
521
        {
 
522
                locallock->lock = NULL;
 
523
                locallock->proclock = NULL;
 
524
                locallock->hashcode = LockTagHashCode(&(localtag.lock));
 
525
                locallock->nLocks = 0;
 
526
                locallock->numLockOwners = 0;
 
527
                locallock->maxLockOwners = 8;
 
528
                locallock->lockOwners = NULL;
 
529
                locallock->lockOwners = (LOCALLOCKOWNER *)
 
530
                        MemoryContextAlloc(TopMemoryContext,
 
531
                                                  locallock->maxLockOwners * sizeof(LOCALLOCKOWNER));
 
532
        }
 
533
        else
 
534
        {
 
535
                /* Make sure there will be room to remember the lock */
 
536
                if (locallock->numLockOwners >= locallock->maxLockOwners)
 
537
                {
 
538
                        int                     newsize = locallock->maxLockOwners * 2;
 
539
 
 
540
                        locallock->lockOwners = (LOCALLOCKOWNER *)
 
541
                                repalloc(locallock->lockOwners,
 
542
                                                 newsize * sizeof(LOCALLOCKOWNER));
 
543
                        locallock->maxLockOwners = newsize;
 
544
                }
 
545
        }
 
546
 
 
547
        /*
 
548
         * If we already hold the lock, we can just increase the count locally.
 
549
         */
 
550
        if (locallock->nLocks > 0)
 
551
        {
 
552
                GrantLockLocal(locallock, owner);
 
553
                return LOCKACQUIRE_ALREADY_HELD;
 
554
        }
 
555
 
 
556
        /*
 
557
         * Otherwise we've got to mess with the shared lock table.
 
558
         */
 
559
        hashcode = locallock->hashcode;
 
560
        partition = LockHashPartition(hashcode);
 
561
        partitionLock = LockHashPartitionLock(hashcode);
 
562
 
 
563
        LWLockAcquire(partitionLock, LW_EXCLUSIVE);
 
564
 
 
565
        /*
 
566
         * Find or create a lock with this tag.
 
567
         *
 
568
         * Note: if the locallock object already existed, it might have a pointer
 
569
         * to the lock already ... but we probably should not assume that that
 
570
         * pointer is valid, since a lock object with no locks can go away
 
571
         * anytime.
 
572
         */
 
573
        lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
 
574
                                                                                                (void *) locktag,
 
575
                                                                                                hashcode,
 
576
                                                                                                HASH_ENTER_NULL,
 
577
                                                                                                &found);
 
578
        if (!lock)
 
579
        {
 
580
                LWLockRelease(partitionLock);
 
581
                ereport(ERROR,
 
582
                                (errcode(ERRCODE_OUT_OF_MEMORY),
 
583
                                 errmsg("out of shared memory"),
 
584
                  errhint("You might need to increase max_locks_per_transaction.")));
 
585
        }
 
586
        locallock->lock = lock;
 
587
 
 
588
        /*
 
589
         * if it's a new lock object, initialize it
 
590
         */
 
591
        if (!found)
 
592
        {
 
593
                lock->grantMask = 0;
 
594
                lock->waitMask = 0;
 
595
                SHMQueueInit(&(lock->procLocks));
 
596
                ProcQueueInit(&(lock->waitProcs));
 
597
                lock->nRequested = 0;
 
598
                lock->nGranted = 0;
 
599
                MemSet(lock->requested, 0, sizeof(int) * MAX_LOCKMODES);
 
600
                MemSet(lock->granted, 0, sizeof(int) * MAX_LOCKMODES);
 
601
                LOCK_PRINT("LockAcquire: new", lock, lockmode);
 
602
        }
 
603
        else
 
604
        {
 
605
                LOCK_PRINT("LockAcquire: found", lock, lockmode);
 
606
                Assert((lock->nRequested >= 0) && (lock->requested[lockmode] >= 0));
 
607
                Assert((lock->nGranted >= 0) && (lock->granted[lockmode] >= 0));
 
608
                Assert(lock->nGranted <= lock->nRequested);
 
609
        }
 
610
 
 
611
        /*
 
612
         * Create the hash key for the proclock table.
 
613
         */
 
614
        proclocktag.myLock = lock;
 
615
        proclocktag.myProc = MyProc;
 
616
 
 
617
        proclock_hashcode = ProcLockHashCode(&proclocktag, hashcode);
 
618
 
 
619
        /*
 
620
         * Find or create a proclock entry with this tag
 
621
         */
 
622
        proclock = (PROCLOCK *) hash_search_with_hash_value(LockMethodProcLockHash,
 
623
                                                                                                                (void *) &proclocktag,
 
624
                                                                                                                proclock_hashcode,
 
625
                                                                                                                HASH_ENTER_NULL,
 
626
                                                                                                                &found);
 
627
        if (!proclock)
 
628
        {
 
629
                /* Ooops, not enough shmem for the proclock */
 
630
                if (lock->nRequested == 0)
 
631
                {
 
632
                        /*
 
633
                         * There are no other requestors of this lock, so garbage-collect
 
634
                         * the lock object.  We *must* do this to avoid a permanent leak
 
635
                         * of shared memory, because there won't be anything to cause
 
636
                         * anyone to release the lock object later.
 
637
                         */
 
638
                        Assert(SHMQueueEmpty(&(lock->procLocks)));
 
639
                        if (!hash_search_with_hash_value(LockMethodLockHash,
 
640
                                                                                         (void *) &(lock->tag),
 
641
                                                                                         hashcode,
 
642
                                                                                         HASH_REMOVE,
 
643
                                                                                         NULL))
 
644
                                elog(PANIC, "lock table corrupted");
 
645
                }
 
646
                LWLockRelease(partitionLock);
 
647
                ereport(ERROR,
 
648
                                (errcode(ERRCODE_OUT_OF_MEMORY),
 
649
                                 errmsg("out of shared memory"),
 
650
                  errhint("You might need to increase max_locks_per_transaction.")));
 
651
        }
 
652
        locallock->proclock = proclock;
 
653
 
 
654
        /*
 
655
         * If new, initialize the new entry
 
656
         */
 
657
        if (!found)
 
658
        {
 
659
                proclock->holdMask = 0;
 
660
                proclock->releaseMask = 0;
 
661
                /* Add proclock to appropriate lists */
 
662
                SHMQueueInsertBefore(&lock->procLocks, &proclock->lockLink);
 
663
                SHMQueueInsertBefore(&(MyProc->myProcLocks[partition]),
 
664
                                                         &proclock->procLink);
 
665
                PROCLOCK_PRINT("LockAcquire: new", proclock);
 
666
        }
 
667
        else
 
668
        {
 
669
                PROCLOCK_PRINT("LockAcquire: found", proclock);
 
670
                Assert((proclock->holdMask & ~lock->grantMask) == 0);
 
671
 
 
672
#ifdef CHECK_DEADLOCK_RISK
 
673
 
 
674
                /*
 
675
                 * Issue warning if we already hold a lower-level lock on this object
 
676
                 * and do not hold a lock of the requested level or higher. This
 
677
                 * indicates a deadlock-prone coding practice (eg, we'd have a
 
678
                 * deadlock if another backend were following the same code path at
 
679
                 * about the same time).
 
680
                 *
 
681
                 * This is not enabled by default, because it may generate log entries
 
682
                 * about user-level coding practices that are in fact safe in context.
 
683
                 * It can be enabled to help find system-level problems.
 
684
                 *
 
685
                 * XXX Doing numeric comparison on the lockmodes is a hack; it'd be
 
686
                 * better to use a table.  For now, though, this works.
 
687
                 */
 
688
                {
 
689
                        int                     i;
 
690
 
 
691
                        for (i = lockMethodTable->numLockModes; i > 0; i--)
 
692
                        {
 
693
                                if (proclock->holdMask & LOCKBIT_ON(i))
 
694
                                {
 
695
                                        if (i >= (int) lockmode)
 
696
                                                break;  /* safe: we have a lock >= req level */
 
697
                                        elog(LOG, "deadlock risk: raising lock level"
 
698
                                                 " from %s to %s on object %u/%u/%u",
 
699
                                                 lockMethodTable->lockModeNames[i],
 
700
                                                 lockMethodTable->lockModeNames[lockmode],
 
701
                                                 lock->tag.locktag_field1, lock->tag.locktag_field2,
 
702
                                                 lock->tag.locktag_field3);
 
703
                                        break;
 
704
                                }
 
705
                        }
 
706
                }
 
707
#endif   /* CHECK_DEADLOCK_RISK */
 
708
        }
 
709
 
 
710
        /*
 
711
         * lock->nRequested and lock->requested[] count the total number of
 
712
         * requests, whether granted or waiting, so increment those immediately.
 
713
         * The other counts don't increment till we get the lock.
 
714
         */
 
715
        lock->nRequested++;
 
716
        lock->requested[lockmode]++;
 
717
        Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0));
 
718
 
 
719
        /*
 
720
         * We shouldn't already hold the desired lock; else locallock table is
 
721
         * broken.
 
722
         */
 
723
        if (proclock->holdMask & LOCKBIT_ON(lockmode))
 
724
                elog(ERROR, "lock %s on object %u/%u/%u is already held",
 
725
                         lockMethodTable->lockModeNames[lockmode],
 
726
                         lock->tag.locktag_field1, lock->tag.locktag_field2,
 
727
                         lock->tag.locktag_field3);
 
728
 
 
729
        /*
 
730
         * If lock requested conflicts with locks requested by waiters, must join
 
731
         * wait queue.  Otherwise, check for conflict with already-held locks.
 
732
         * (That's last because most complex check.)
 
733
         */
 
734
        if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
 
735
                status = STATUS_FOUND;
 
736
        else
 
737
                status = LockCheckConflicts(lockMethodTable, lockmode,
 
738
                                                                        lock, proclock, MyProc);
 
739
 
 
740
        if (status == STATUS_OK)
 
741
        {
 
742
                /* No conflict with held or previously requested locks */
 
743
                GrantLock(lock, proclock, lockmode);
 
744
                GrantLockLocal(locallock, owner);
 
745
        }
 
746
        else
 
747
        {
 
748
                Assert(status == STATUS_FOUND);
 
749
 
 
750
                /*
 
751
                 * We can't acquire the lock immediately.  If caller specified no
 
752
                 * blocking, remove useless table entries and return NOT_AVAIL without
 
753
                 * waiting.
 
754
                 */
 
755
                if (dontWait)
 
756
                {
 
757
                        if (proclock->holdMask == 0)
 
758
                        {
 
759
                                SHMQueueDelete(&proclock->lockLink);
 
760
                                SHMQueueDelete(&proclock->procLink);
 
761
                                if (!hash_search_with_hash_value(LockMethodProcLockHash,
 
762
                                                                                                 (void *) &(proclock->tag),
 
763
                                                                                                 proclock_hashcode,
 
764
                                                                                                 HASH_REMOVE,
 
765
                                                                                                 NULL))
 
766
                                        elog(PANIC, "proclock table corrupted");
 
767
                        }
 
768
                        else
 
769
                                PROCLOCK_PRINT("LockAcquire: NOWAIT", proclock);
 
770
                        lock->nRequested--;
 
771
                        lock->requested[lockmode]--;
 
772
                        LOCK_PRINT("LockAcquire: conditional lock failed", lock, lockmode);
 
773
                        Assert((lock->nRequested > 0) && (lock->requested[lockmode] >= 0));
 
774
                        Assert(lock->nGranted <= lock->nRequested);
 
775
                        LWLockRelease(partitionLock);
 
776
                        if (locallock->nLocks == 0)
 
777
                                RemoveLocalLock(locallock);
 
778
                        return LOCKACQUIRE_NOT_AVAIL;
 
779
                }
 
780
 
 
781
                /*
 
782
                 * Set bitmask of locks this process already holds on this object.
 
783
                 */
 
784
                MyProc->heldLocks = proclock->holdMask;
 
785
 
 
786
                /*
 
787
                 * Sleep till someone wakes me up.
 
788
                 */
 
789
 
 
790
                TRACE_POSTGRESQL_LOCK_WAIT_START(locktag->locktag_field1,
 
791
                                                                                 locktag->locktag_field2,
 
792
                                                                                 locktag->locktag_field3,
 
793
                                                                                 locktag->locktag_field4,
 
794
                                                                                 locktag->locktag_type,
 
795
                                                                                 lockmode);
 
796
 
 
797
                WaitOnLock(locallock, owner);
 
798
 
 
799
                TRACE_POSTGRESQL_LOCK_WAIT_DONE(locktag->locktag_field1,
 
800
                                                                                locktag->locktag_field2,
 
801
                                                                                locktag->locktag_field3,
 
802
                                                                                locktag->locktag_field4,
 
803
                                                                                locktag->locktag_type,
 
804
                                                                                lockmode);
 
805
 
 
806
                /*
 
807
                 * NOTE: do not do any material change of state between here and
 
808
                 * return.      All required changes in locktable state must have been
 
809
                 * done when the lock was granted to us --- see notes in WaitOnLock.
 
810
                 */
 
811
 
 
812
                /*
 
813
                 * Check the proclock entry status, in case something in the ipc
 
814
                 * communication doesn't work correctly.
 
815
                 */
 
816
                if (!(proclock->holdMask & LOCKBIT_ON(lockmode)))
 
817
                {
 
818
                        PROCLOCK_PRINT("LockAcquire: INCONSISTENT", proclock);
 
819
                        LOCK_PRINT("LockAcquire: INCONSISTENT", lock, lockmode);
 
820
                        /* Should we retry ? */
 
821
                        LWLockRelease(partitionLock);
 
822
                        elog(ERROR, "LockAcquire failed");
 
823
                }
 
824
                PROCLOCK_PRINT("LockAcquire: granted", proclock);
 
825
                LOCK_PRINT("LockAcquire: granted", lock, lockmode);
 
826
        }
 
827
 
 
828
        LWLockRelease(partitionLock);
 
829
 
 
830
        return LOCKACQUIRE_OK;
 
831
}
 
832
 
 
833
/*
 
834
 * Subroutine to free a locallock entry
 
835
 */
 
836
static void
 
837
RemoveLocalLock(LOCALLOCK *locallock)
 
838
{
 
839
        pfree(locallock->lockOwners);
 
840
        locallock->lockOwners = NULL;
 
841
        if (!hash_search(LockMethodLocalHash,
 
842
                                         (void *) &(locallock->tag),
 
843
                                         HASH_REMOVE, NULL))
 
844
                elog(WARNING, "locallock table corrupted");
 
845
}
 
846
 
 
847
/*
 
848
 * LockCheckConflicts -- test whether requested lock conflicts
 
849
 *              with those already granted
 
850
 *
 
851
 * Returns STATUS_FOUND if conflict, STATUS_OK if no conflict.
 
852
 *
 
853
 * NOTES:
 
854
 *              Here's what makes this complicated: one process's locks don't
 
855
 * conflict with one another, no matter what purpose they are held for
 
856
 * (eg, session and transaction locks do not conflict).
 
857
 * So, we must subtract off our own locks when determining whether the
 
858
 * requested new lock conflicts with those already held.
 
859
 */
 
860
int
 
861
LockCheckConflicts(LockMethod lockMethodTable,
 
862
                                   LOCKMODE lockmode,
 
863
                                   LOCK *lock,
 
864
                                   PROCLOCK *proclock,
 
865
                                   PGPROC *proc)
 
866
{
 
867
        int                     numLockModes = lockMethodTable->numLockModes;
 
868
        LOCKMASK        myLocks;
 
869
        LOCKMASK        otherLocks;
 
870
        int                     i;
 
871
 
 
872
        /*
 
873
         * first check for global conflicts: If no locks conflict with my request,
 
874
         * then I get the lock.
 
875
         *
 
876
         * Checking for conflict: lock->grantMask represents the types of
 
877
         * currently held locks.  conflictTable[lockmode] has a bit set for each
 
878
         * type of lock that conflicts with request.   Bitwise compare tells if
 
879
         * there is a conflict.
 
880
         */
 
881
        if (!(lockMethodTable->conflictTab[lockmode] & lock->grantMask))
 
882
        {
 
883
                PROCLOCK_PRINT("LockCheckConflicts: no conflict", proclock);
 
884
                return STATUS_OK;
 
885
        }
 
886
 
 
887
        /*
 
888
         * Rats.  Something conflicts.  But it could still be my own lock. We have
 
889
         * to construct a conflict mask that does not reflect our own locks, but
 
890
         * only lock types held by other processes.
 
891
         */
 
892
        myLocks = proclock->holdMask;
 
893
        otherLocks = 0;
 
894
        for (i = 1; i <= numLockModes; i++)
 
895
        {
 
896
                int                     myHolding = (myLocks & LOCKBIT_ON(i)) ? 1 : 0;
 
897
 
 
898
                if (lock->granted[i] > myHolding)
 
899
                        otherLocks |= LOCKBIT_ON(i);
 
900
        }
 
901
 
 
902
        /*
 
903
         * now check again for conflicts.  'otherLocks' describes the types of
 
904
         * locks held by other processes.  If one of these conflicts with the kind
 
905
         * of lock that I want, there is a conflict and I have to sleep.
 
906
         */
 
907
        if (!(lockMethodTable->conflictTab[lockmode] & otherLocks))
 
908
        {
 
909
                /* no conflict. OK to get the lock */
 
910
                PROCLOCK_PRINT("LockCheckConflicts: resolved", proclock);
 
911
                return STATUS_OK;
 
912
        }
 
913
 
 
914
        PROCLOCK_PRINT("LockCheckConflicts: conflicting", proclock);
 
915
        return STATUS_FOUND;
 
916
}
 
917
 
 
918
/*
 
919
 * GrantLock -- update the lock and proclock data structures to show
 
920
 *              the lock request has been granted.
 
921
 *
 
922
 * NOTE: if proc was blocked, it also needs to be removed from the wait list
 
923
 * and have its waitLock/waitProcLock fields cleared.  That's not done here.
 
924
 *
 
925
 * NOTE: the lock grant also has to be recorded in the associated LOCALLOCK
 
926
 * table entry; but since we may be awaking some other process, we can't do
 
927
 * that here; it's done by GrantLockLocal, instead.
 
928
 */
 
929
void
 
930
GrantLock(LOCK *lock, PROCLOCK *proclock, LOCKMODE lockmode)
 
931
{
 
932
        lock->nGranted++;
 
933
        lock->granted[lockmode]++;
 
934
        lock->grantMask |= LOCKBIT_ON(lockmode);
 
935
        if (lock->granted[lockmode] == lock->requested[lockmode])
 
936
                lock->waitMask &= LOCKBIT_OFF(lockmode);
 
937
        proclock->holdMask |= LOCKBIT_ON(lockmode);
 
938
        LOCK_PRINT("GrantLock", lock, lockmode);
 
939
        Assert((lock->nGranted > 0) && (lock->granted[lockmode] > 0));
 
940
        Assert(lock->nGranted <= lock->nRequested);
 
941
}
 
942
 
 
943
/*
 
944
 * UnGrantLock -- opposite of GrantLock.
 
945
 *
 
946
 * Updates the lock and proclock data structures to show that the lock
 
947
 * is no longer held nor requested by the current holder.
 
948
 *
 
949
 * Returns true if there were any waiters waiting on the lock that
 
950
 * should now be woken up with ProcLockWakeup.
 
951
 */
 
952
static bool
 
953
UnGrantLock(LOCK *lock, LOCKMODE lockmode,
 
954
                        PROCLOCK *proclock, LockMethod lockMethodTable)
 
955
{
 
956
        bool            wakeupNeeded = false;
 
957
 
 
958
        Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0));
 
959
        Assert((lock->nGranted > 0) && (lock->granted[lockmode] > 0));
 
960
        Assert(lock->nGranted <= lock->nRequested);
 
961
 
 
962
        /*
 
963
         * fix the general lock stats
 
964
         */
 
965
        lock->nRequested--;
 
966
        lock->requested[lockmode]--;
 
967
        lock->nGranted--;
 
968
        lock->granted[lockmode]--;
 
969
 
 
970
        if (lock->granted[lockmode] == 0)
 
971
        {
 
972
                /* change the conflict mask.  No more of this lock type. */
 
973
                lock->grantMask &= LOCKBIT_OFF(lockmode);
 
974
        }
 
975
 
 
976
        LOCK_PRINT("UnGrantLock: updated", lock, lockmode);
 
977
 
 
978
        /*
 
979
         * We need only run ProcLockWakeup if the released lock conflicts with at
 
980
         * least one of the lock types requested by waiter(s).  Otherwise whatever
 
981
         * conflict made them wait must still exist.  NOTE: before MVCC, we could
 
982
         * skip wakeup if lock->granted[lockmode] was still positive. But that's
 
983
         * not true anymore, because the remaining granted locks might belong to
 
984
         * some waiter, who could now be awakened because he doesn't conflict with
 
985
         * his own locks.
 
986
         */
 
987
        if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
 
988
                wakeupNeeded = true;
 
989
 
 
990
        /*
 
991
         * Now fix the per-proclock state.
 
992
         */
 
993
        proclock->holdMask &= LOCKBIT_OFF(lockmode);
 
994
        PROCLOCK_PRINT("UnGrantLock: updated", proclock);
 
995
 
 
996
        return wakeupNeeded;
 
997
}
 
998
 
 
999
/*
 
1000
 * CleanUpLock -- clean up after releasing a lock.      We garbage-collect the
 
1001
 * proclock and lock objects if possible, and call ProcLockWakeup if there
 
1002
 * are remaining requests and the caller says it's OK.  (Normally, this
 
1003
 * should be called after UnGrantLock, and wakeupNeeded is the result from
 
1004
 * UnGrantLock.)
 
1005
 *
 
1006
 * The appropriate partition lock must be held at entry, and will be
 
1007
 * held at exit.
 
1008
 */
 
1009
static void
 
1010
CleanUpLock(LOCK *lock, PROCLOCK *proclock,
 
1011
                        LockMethod lockMethodTable, uint32 hashcode,
 
1012
                        bool wakeupNeeded)
 
1013
{
 
1014
        /*
 
1015
         * If this was my last hold on this lock, delete my entry in the proclock
 
1016
         * table.
 
1017
         */
 
1018
        if (proclock->holdMask == 0)
 
1019
        {
 
1020
                uint32          proclock_hashcode;
 
1021
 
 
1022
                PROCLOCK_PRINT("CleanUpLock: deleting", proclock);
 
1023
                SHMQueueDelete(&proclock->lockLink);
 
1024
                SHMQueueDelete(&proclock->procLink);
 
1025
                proclock_hashcode = ProcLockHashCode(&proclock->tag, hashcode);
 
1026
                if (!hash_search_with_hash_value(LockMethodProcLockHash,
 
1027
                                                                                 (void *) &(proclock->tag),
 
1028
                                                                                 proclock_hashcode,
 
1029
                                                                                 HASH_REMOVE,
 
1030
                                                                                 NULL))
 
1031
                        elog(PANIC, "proclock table corrupted");
 
1032
        }
 
1033
 
 
1034
        if (lock->nRequested == 0)
 
1035
        {
 
1036
                /*
 
1037
                 * The caller just released the last lock, so garbage-collect the lock
 
1038
                 * object.
 
1039
                 */
 
1040
                LOCK_PRINT("CleanUpLock: deleting", lock, 0);
 
1041
                Assert(SHMQueueEmpty(&(lock->procLocks)));
 
1042
                if (!hash_search_with_hash_value(LockMethodLockHash,
 
1043
                                                                                 (void *) &(lock->tag),
 
1044
                                                                                 hashcode,
 
1045
                                                                                 HASH_REMOVE,
 
1046
                                                                                 NULL))
 
1047
                        elog(PANIC, "lock table corrupted");
 
1048
        }
 
1049
        else if (wakeupNeeded)
 
1050
        {
 
1051
                /* There are waiters on this lock, so wake them up. */
 
1052
                ProcLockWakeup(lockMethodTable, lock);
 
1053
        }
 
1054
}
 
1055
 
 
1056
/*
 
1057
 * GrantLockLocal -- update the locallock data structures to show
 
1058
 *              the lock request has been granted.
 
1059
 *
 
1060
 * We expect that LockAcquire made sure there is room to add a new
 
1061
 * ResourceOwner entry.
 
1062
 */
 
1063
static void
 
1064
GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner)
 
1065
{
 
1066
        LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
 
1067
        int                     i;
 
1068
 
 
1069
        Assert(locallock->numLockOwners < locallock->maxLockOwners);
 
1070
        /* Count the total */
 
1071
        locallock->nLocks++;
 
1072
        /* Count the per-owner lock */
 
1073
        for (i = 0; i < locallock->numLockOwners; i++)
 
1074
        {
 
1075
                if (lockOwners[i].owner == owner)
 
1076
                {
 
1077
                        lockOwners[i].nLocks++;
 
1078
                        return;
 
1079
                }
 
1080
        }
 
1081
        lockOwners[i].owner = owner;
 
1082
        lockOwners[i].nLocks = 1;
 
1083
        locallock->numLockOwners++;
 
1084
}
 
1085
 
 
1086
/*
 
1087
 * GrantAwaitedLock -- call GrantLockLocal for the lock we are doing
 
1088
 *              WaitOnLock on.
 
1089
 *
 
1090
 * proc.c needs this for the case where we are booted off the lock by
 
1091
 * timeout, but discover that someone granted us the lock anyway.
 
1092
 *
 
1093
 * We could just export GrantLockLocal, but that would require including
 
1094
 * resowner.h in lock.h, which creates circularity.
 
1095
 */
 
1096
void
 
1097
GrantAwaitedLock(void)
 
1098
{
 
1099
        GrantLockLocal(awaitedLock, awaitedOwner);
 
1100
}
 
1101
 
 
1102
/*
 
1103
 * WaitOnLock -- wait to acquire a lock
 
1104
 *
 
1105
 * Caller must have set MyProc->heldLocks to reflect locks already held
 
1106
 * on the lockable object by this process.
 
1107
 *
 
1108
 * The appropriate partition lock must be held at entry.
 
1109
 */
 
1110
static void
 
1111
WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
 
1112
{
 
1113
        LOCKMETHODID lockmethodid = LOCALLOCK_LOCKMETHOD(*locallock);
 
1114
        LockMethod      lockMethodTable = LockMethods[lockmethodid];
 
1115
        char       * volatile new_status = NULL;
 
1116
 
 
1117
        LOCK_PRINT("WaitOnLock: sleeping on lock",
 
1118
                           locallock->lock, locallock->tag.mode);
 
1119
 
 
1120
        /* Report change to waiting status */
 
1121
        if (update_process_title)
 
1122
        {
 
1123
                const char *old_status;
 
1124
                int                     len;
 
1125
 
 
1126
                old_status = get_ps_display(&len);
 
1127
                new_status = (char *) palloc(len + 8 + 1);
 
1128
                memcpy(new_status, old_status, len);
 
1129
                strcpy(new_status + len, " waiting");
 
1130
                set_ps_display(new_status, false);
 
1131
                new_status[len] = '\0'; /* truncate off " waiting" */
 
1132
        }
 
1133
        pgstat_report_waiting(true);
 
1134
 
 
1135
        awaitedLock = locallock;
 
1136
        awaitedOwner = owner;
 
1137
 
 
1138
        /*
 
1139
         * NOTE: Think not to put any shared-state cleanup after the call to
 
1140
         * ProcSleep, in either the normal or failure path.  The lock state must
 
1141
         * be fully set by the lock grantor, or by CheckDeadLock if we give up
 
1142
         * waiting for the lock.  This is necessary because of the possibility
 
1143
         * that a cancel/die interrupt will interrupt ProcSleep after someone else
 
1144
         * grants us the lock, but before we've noticed it. Hence, after granting,
 
1145
         * the locktable state must fully reflect the fact that we own the lock;
 
1146
         * we can't do additional work on return.
 
1147
         *
 
1148
         * We can and do use a PG_TRY block to try to clean up after failure,
 
1149
         * but this still has a major limitation: elog(FATAL) can occur while
 
1150
         * waiting (eg, a "die" interrupt), and then control won't come back here.
 
1151
         * So all cleanup of essential state should happen in LockWaitCancel,
 
1152
         * not here.  We can use PG_TRY to clear the "waiting" status flags,
 
1153
         * since doing that is unimportant if the process exits.
 
1154
         */
 
1155
        PG_TRY();
 
1156
        {
 
1157
                if (ProcSleep(locallock, lockMethodTable) != STATUS_OK)
 
1158
                {
 
1159
                        /*
 
1160
                         * We failed as a result of a deadlock, see CheckDeadLock().
 
1161
                         * Quit now.
 
1162
                         */
 
1163
                        awaitedLock = NULL;
 
1164
                        LOCK_PRINT("WaitOnLock: aborting on lock",
 
1165
                                           locallock->lock, locallock->tag.mode);
 
1166
                        LWLockRelease(LockHashPartitionLock(locallock->hashcode));
 
1167
 
 
1168
                        /*
 
1169
                         * Now that we aren't holding the partition lock, we can give an
 
1170
                         * error report including details about the detected deadlock.
 
1171
                         */
 
1172
                        DeadLockReport();
 
1173
                        /* not reached */
 
1174
                }
 
1175
        }
 
1176
        PG_CATCH();
 
1177
        {
 
1178
                /* In this path, awaitedLock remains set until LockWaitCancel */
 
1179
 
 
1180
                /* Report change to non-waiting status */
 
1181
                pgstat_report_waiting(false);
 
1182
                if (update_process_title)
 
1183
                {
 
1184
                        set_ps_display(new_status, false);
 
1185
                        pfree(new_status);
 
1186
                }
 
1187
 
 
1188
                /* and propagate the error */
 
1189
                PG_RE_THROW();
 
1190
        }
 
1191
        PG_END_TRY();
 
1192
 
 
1193
        awaitedLock = NULL;
 
1194
 
 
1195
        /* Report change to non-waiting status */
 
1196
        pgstat_report_waiting(false);
 
1197
        if (update_process_title)
 
1198
        {
 
1199
                set_ps_display(new_status, false);
 
1200
                pfree(new_status);
 
1201
        }
 
1202
 
 
1203
        LOCK_PRINT("WaitOnLock: wakeup on lock",
 
1204
                           locallock->lock, locallock->tag.mode);
 
1205
}
 
1206
 
 
1207
/*
 
1208
 * Remove a proc from the wait-queue it is on (caller must know it is on one).
 
1209
 * This is only used when the proc has failed to get the lock, so we set its
 
1210
 * waitStatus to STATUS_ERROR.
 
1211
 *
 
1212
 * Appropriate partition lock must be held by caller.  Also, caller is
 
1213
 * responsible for signaling the proc if needed.
 
1214
 *
 
1215
 * NB: this does not clean up any locallock object that may exist for the lock.
 
1216
 */
 
1217
void
 
1218
RemoveFromWaitQueue(PGPROC *proc, uint32 hashcode)
 
1219
{
 
1220
        LOCK       *waitLock = proc->waitLock;
 
1221
        PROCLOCK   *proclock = proc->waitProcLock;
 
1222
        LOCKMODE        lockmode = proc->waitLockMode;
 
1223
        LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*waitLock);
 
1224
 
 
1225
        /* Make sure proc is waiting */
 
1226
        Assert(proc->waitStatus == STATUS_WAITING);
 
1227
        Assert(proc->links.next != NULL);
 
1228
        Assert(waitLock);
 
1229
        Assert(waitLock->waitProcs.size > 0);
 
1230
        Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));
 
1231
 
 
1232
        /* Remove proc from lock's wait queue */
 
1233
        SHMQueueDelete(&(proc->links));
 
1234
        waitLock->waitProcs.size--;
 
1235
 
 
1236
        /* Undo increments of request counts by waiting process */
 
1237
        Assert(waitLock->nRequested > 0);
 
1238
        Assert(waitLock->nRequested > proc->waitLock->nGranted);
 
1239
        waitLock->nRequested--;
 
1240
        Assert(waitLock->requested[lockmode] > 0);
 
1241
        waitLock->requested[lockmode]--;
 
1242
        /* don't forget to clear waitMask bit if appropriate */
 
1243
        if (waitLock->granted[lockmode] == waitLock->requested[lockmode])
 
1244
                waitLock->waitMask &= LOCKBIT_OFF(lockmode);
 
1245
 
 
1246
        /* Clean up the proc's own state, and pass it the ok/fail signal */
 
1247
        proc->waitLock = NULL;
 
1248
        proc->waitProcLock = NULL;
 
1249
        proc->waitStatus = STATUS_ERROR;
 
1250
 
 
1251
        /*
 
1252
         * Delete the proclock immediately if it represents no already-held locks.
 
1253
         * (This must happen now because if the owner of the lock decides to
 
1254
         * release it, and the requested/granted counts then go to zero,
 
1255
         * LockRelease expects there to be no remaining proclocks.) Then see if
 
1256
         * any other waiters for the lock can be woken up now.
 
1257
         */
 
1258
        CleanUpLock(waitLock, proclock,
 
1259
                                LockMethods[lockmethodid], hashcode,
 
1260
                                true);
 
1261
}
 
1262
 
 
1263
/*
 
1264
 * LockRelease -- look up 'locktag' and release one 'lockmode' lock on it.
 
1265
 *              Release a session lock if 'sessionLock' is true, else release a
 
1266
 *              regular transaction lock.
 
1267
 *
 
1268
 * Side Effects: find any waiting processes that are now wakable,
 
1269
 *              grant them their requested locks and awaken them.
 
1270
 *              (We have to grant the lock here to avoid a race between
 
1271
 *              the waking process and any new process to
 
1272
 *              come along and request the lock.)
 
1273
 */
 
1274
bool
 
1275
LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
 
1276
{
 
1277
        LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
 
1278
        LockMethod      lockMethodTable;
 
1279
        LOCALLOCKTAG localtag;
 
1280
        LOCALLOCK  *locallock;
 
1281
        LOCK       *lock;
 
1282
        PROCLOCK   *proclock;
 
1283
        LWLockId        partitionLock;
 
1284
        bool            wakeupNeeded;
 
1285
 
 
1286
        if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
 
1287
                elog(ERROR, "unrecognized lock method: %d", lockmethodid);
 
1288
        lockMethodTable = LockMethods[lockmethodid];
 
1289
        if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
 
1290
                elog(ERROR, "unrecognized lock mode: %d", lockmode);
 
1291
 
 
1292
#ifdef LOCK_DEBUG
 
1293
        if (LOCK_DEBUG_ENABLED(locktag))
 
1294
                elog(LOG, "LockRelease: lock [%u,%u] %s",
 
1295
                         locktag->locktag_field1, locktag->locktag_field2,
 
1296
                         lockMethodTable->lockModeNames[lockmode]);
 
1297
#endif
 
1298
 
 
1299
        /*
 
1300
         * Find the LOCALLOCK entry for this lock and lockmode
 
1301
         */
 
1302
        MemSet(&localtag, 0, sizeof(localtag));         /* must clear padding */
 
1303
        localtag.lock = *locktag;
 
1304
        localtag.mode = lockmode;
 
1305
 
 
1306
        locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
 
1307
                                                                                  (void *) &localtag,
 
1308
                                                                                  HASH_FIND, NULL);
 
1309
 
 
1310
        /*
 
1311
         * let the caller print its own error message, too. Do not ereport(ERROR).
 
1312
         */
 
1313
        if (!locallock || locallock->nLocks <= 0)
 
1314
        {
 
1315
                elog(WARNING, "you don't own a lock of type %s",
 
1316
                         lockMethodTable->lockModeNames[lockmode]);
 
1317
                return FALSE;
 
1318
        }
 
1319
 
 
1320
        /*
 
1321
         * Decrease the count for the resource owner.
 
1322
         */
 
1323
        {
 
1324
                LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
 
1325
                ResourceOwner owner;
 
1326
                int                     i;
 
1327
 
 
1328
                /* Session locks are never transactional, else check table */
 
1329
                if (!sessionLock && lockMethodTable->transactional)
 
1330
                        owner = CurrentResourceOwner;
 
1331
                else
 
1332
                        owner = NULL;
 
1333
 
 
1334
                for (i = locallock->numLockOwners - 1; i >= 0; i--)
 
1335
                {
 
1336
                        if (lockOwners[i].owner == owner)
 
1337
                        {
 
1338
                                Assert(lockOwners[i].nLocks > 0);
 
1339
                                if (--lockOwners[i].nLocks == 0)
 
1340
                                {
 
1341
                                        /* compact out unused slot */
 
1342
                                        locallock->numLockOwners--;
 
1343
                                        if (i < locallock->numLockOwners)
 
1344
                                                lockOwners[i] = lockOwners[locallock->numLockOwners];
 
1345
                                }
 
1346
                                break;
 
1347
                        }
 
1348
                }
 
1349
                if (i < 0)
 
1350
                {
 
1351
                        /* don't release a lock belonging to another owner */
 
1352
                        elog(WARNING, "you don't own a lock of type %s",
 
1353
                                 lockMethodTable->lockModeNames[lockmode]);
 
1354
                        return FALSE;
 
1355
                }
 
1356
        }
 
1357
 
 
1358
        /*
 
1359
         * Decrease the total local count.      If we're still holding the lock, we're
 
1360
         * done.
 
1361
         */
 
1362
        locallock->nLocks--;
 
1363
 
 
1364
        if (locallock->nLocks > 0)
 
1365
                return TRUE;
 
1366
 
 
1367
        /*
 
1368
         * Otherwise we've got to mess with the shared lock table.
 
1369
         */
 
1370
        partitionLock = LockHashPartitionLock(locallock->hashcode);
 
1371
 
 
1372
        LWLockAcquire(partitionLock, LW_EXCLUSIVE);
 
1373
 
 
1374
        /*
 
1375
         * We don't need to re-find the lock or proclock, since we kept their
 
1376
         * addresses in the locallock table, and they couldn't have been removed
 
1377
         * while we were holding a lock on them.
 
1378
         */
 
1379
        lock = locallock->lock;
 
1380
        LOCK_PRINT("LockRelease: found", lock, lockmode);
 
1381
        proclock = locallock->proclock;
 
1382
        PROCLOCK_PRINT("LockRelease: found", proclock);
 
1383
 
 
1384
        /*
 
1385
         * Double-check that we are actually holding a lock of the type we want to
 
1386
         * release.
 
1387
         */
 
1388
        if (!(proclock->holdMask & LOCKBIT_ON(lockmode)))
 
1389
        {
 
1390
                PROCLOCK_PRINT("LockRelease: WRONGTYPE", proclock);
 
1391
                LWLockRelease(partitionLock);
 
1392
                elog(WARNING, "you don't own a lock of type %s",
 
1393
                         lockMethodTable->lockModeNames[lockmode]);
 
1394
                RemoveLocalLock(locallock);
 
1395
                return FALSE;
 
1396
        }
 
1397
 
 
1398
        /*
 
1399
         * Do the releasing.  CleanUpLock will waken any now-wakable waiters.
 
1400
         */
 
1401
        wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable);
 
1402
 
 
1403
        CleanUpLock(lock, proclock,
 
1404
                                lockMethodTable, locallock->hashcode,
 
1405
                                wakeupNeeded);
 
1406
 
 
1407
        LWLockRelease(partitionLock);
 
1408
 
 
1409
        RemoveLocalLock(locallock);
 
1410
        return TRUE;
 
1411
}
 
1412
 
 
1413
/*
 
1414
 * LockReleaseAll -- Release all locks of the specified lock method that
 
1415
 *              are held by the current process.
 
1416
 *
 
1417
 * Well, not necessarily *all* locks.  The available behaviors are:
 
1418
 *              allLocks == true: release all locks including session locks.
 
1419
 *              allLocks == false: release all non-session locks.
 
1420
 */
 
1421
void
 
1422
LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
 
1423
{
 
1424
        HASH_SEQ_STATUS status;
 
1425
        LockMethod      lockMethodTable;
 
1426
        int                     i,
 
1427
                                numLockModes;
 
1428
        LOCALLOCK  *locallock;
 
1429
        LOCK       *lock;
 
1430
        PROCLOCK   *proclock;
 
1431
        int                     partition;
 
1432
 
 
1433
        if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
 
1434
                elog(ERROR, "unrecognized lock method: %d", lockmethodid);
 
1435
        lockMethodTable = LockMethods[lockmethodid];
 
1436
 
 
1437
#ifdef LOCK_DEBUG
 
1438
        if (*(lockMethodTable->trace_flag))
 
1439
                elog(LOG, "LockReleaseAll: lockmethod=%d", lockmethodid);
 
1440
#endif
 
1441
 
 
1442
        numLockModes = lockMethodTable->numLockModes;
 
1443
 
 
1444
        /*
 
1445
         * First we run through the locallock table and get rid of unwanted
 
1446
         * entries, then we scan the process's proclocks and get rid of those. We
 
1447
         * do this separately because we may have multiple locallock entries
 
1448
         * pointing to the same proclock, and we daren't end up with any dangling
 
1449
         * pointers.
 
1450
         */
 
1451
        hash_seq_init(&status, LockMethodLocalHash);
 
1452
 
 
1453
        while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
 
1454
        {
 
1455
                if (locallock->proclock == NULL || locallock->lock == NULL)
 
1456
                {
 
1457
                        /*
 
1458
                         * We must've run out of shared memory while trying to set up this
 
1459
                         * lock.  Just forget the local entry.
 
1460
                         */
 
1461
                        Assert(locallock->nLocks == 0);
 
1462
                        RemoveLocalLock(locallock);
 
1463
                        continue;
 
1464
                }
 
1465
 
 
1466
                /* Ignore items that are not of the lockmethod to be removed */
 
1467
                if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid)
 
1468
                        continue;
 
1469
 
 
1470
                /*
 
1471
                 * If we are asked to release all locks, we can just zap the entry.
 
1472
                 * Otherwise, must scan to see if there are session locks. We assume
 
1473
                 * there is at most one lockOwners entry for session locks.
 
1474
                 */
 
1475
                if (!allLocks)
 
1476
                {
 
1477
                        LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
 
1478
 
 
1479
                        /* If it's above array position 0, move it down to 0 */
 
1480
                        for (i = locallock->numLockOwners - 1; i > 0; i--)
 
1481
                        {
 
1482
                                if (lockOwners[i].owner == NULL)
 
1483
                                {
 
1484
                                        lockOwners[0] = lockOwners[i];
 
1485
                                        break;
 
1486
                                }
 
1487
                        }
 
1488
 
 
1489
                        if (locallock->numLockOwners > 0 &&
 
1490
                                lockOwners[0].owner == NULL &&
 
1491
                                lockOwners[0].nLocks > 0)
 
1492
                        {
 
1493
                                /* Fix the locallock to show just the session locks */
 
1494
                                locallock->nLocks = lockOwners[0].nLocks;
 
1495
                                locallock->numLockOwners = 1;
 
1496
                                /* We aren't deleting this locallock, so done */
 
1497
                                continue;
 
1498
                        }
 
1499
                }
 
1500
 
 
1501
                /* Mark the proclock to show we need to release this lockmode */
 
1502
                if (locallock->nLocks > 0)
 
1503
                        locallock->proclock->releaseMask |= LOCKBIT_ON(locallock->tag.mode);
 
1504
 
 
1505
                /* And remove the locallock hashtable entry */
 
1506
                RemoveLocalLock(locallock);
 
1507
        }
 
1508
 
 
1509
        /*
 
1510
         * Now, scan each lock partition separately.
 
1511
         */
 
1512
        for (partition = 0; partition < NUM_LOCK_PARTITIONS; partition++)
 
1513
        {
 
1514
                LWLockId        partitionLock = FirstLockMgrLock + partition;
 
1515
                SHM_QUEUE  *procLocks = &(MyProc->myProcLocks[partition]);
 
1516
 
 
1517
                proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
 
1518
                                                                                         offsetof(PROCLOCK, procLink));
 
1519
 
 
1520
                if (!proclock)
 
1521
                        continue;                       /* needn't examine this partition */
 
1522
 
 
1523
                LWLockAcquire(partitionLock, LW_EXCLUSIVE);
 
1524
 
 
1525
                while (proclock)
 
1526
                {
 
1527
                        bool            wakeupNeeded = false;
 
1528
                        PROCLOCK   *nextplock;
 
1529
 
 
1530
                        /* Get link first, since we may unlink/delete this proclock */
 
1531
                        nextplock = (PROCLOCK *)
 
1532
                                SHMQueueNext(procLocks, &proclock->procLink,
 
1533
                                                         offsetof(PROCLOCK, procLink));
 
1534
 
 
1535
                        Assert(proclock->tag.myProc == MyProc);
 
1536
 
 
1537
                        lock = proclock->tag.myLock;
 
1538
 
 
1539
                        /* Ignore items that are not of the lockmethod to be removed */
 
1540
                        if (LOCK_LOCKMETHOD(*lock) != lockmethodid)
 
1541
                                goto next_item;
 
1542
 
 
1543
                        /*
 
1544
                         * In allLocks mode, force release of all locks even if locallock
 
1545
                         * table had problems
 
1546
                         */
 
1547
                        if (allLocks)
 
1548
                                proclock->releaseMask = proclock->holdMask;
 
1549
                        else
 
1550
                                Assert((proclock->releaseMask & ~proclock->holdMask) == 0);
 
1551
 
 
1552
                        /*
 
1553
                         * Ignore items that have nothing to be released, unless they have
 
1554
                         * holdMask == 0 and are therefore recyclable
 
1555
                         */
 
1556
                        if (proclock->releaseMask == 0 && proclock->holdMask != 0)
 
1557
                                goto next_item;
 
1558
 
 
1559
                        PROCLOCK_PRINT("LockReleaseAll", proclock);
 
1560
                        LOCK_PRINT("LockReleaseAll", lock, 0);
 
1561
                        Assert(lock->nRequested >= 0);
 
1562
                        Assert(lock->nGranted >= 0);
 
1563
                        Assert(lock->nGranted <= lock->nRequested);
 
1564
                        Assert((proclock->holdMask & ~lock->grantMask) == 0);
 
1565
 
 
1566
                        /*
 
1567
                         * Release the previously-marked lock modes
 
1568
                         */
 
1569
                        for (i = 1; i <= numLockModes; i++)
 
1570
                        {
 
1571
                                if (proclock->releaseMask & LOCKBIT_ON(i))
 
1572
                                        wakeupNeeded |= UnGrantLock(lock, i, proclock,
 
1573
                                                                                                lockMethodTable);
 
1574
                        }
 
1575
                        Assert((lock->nRequested >= 0) && (lock->nGranted >= 0));
 
1576
                        Assert(lock->nGranted <= lock->nRequested);
 
1577
                        LOCK_PRINT("LockReleaseAll: updated", lock, 0);
 
1578
 
 
1579
                        proclock->releaseMask = 0;
 
1580
 
 
1581
                        /* CleanUpLock will wake up waiters if needed. */
 
1582
                        CleanUpLock(lock, proclock,
 
1583
                                                lockMethodTable,
 
1584
                                                LockTagHashCode(&lock->tag),
 
1585
                                                wakeupNeeded);
 
1586
 
 
1587
        next_item:
 
1588
                        proclock = nextplock;
 
1589
                }                                               /* loop over PROCLOCKs within this partition */
 
1590
 
 
1591
                LWLockRelease(partitionLock);
 
1592
        }                                                       /* loop over partitions */
 
1593
 
 
1594
#ifdef LOCK_DEBUG
 
1595
        if (*(lockMethodTable->trace_flag))
 
1596
                elog(LOG, "LockReleaseAll done");
 
1597
#endif
 
1598
}
 
1599
 
 
1600
/*
 
1601
 * LockReleaseCurrentOwner
 
1602
 *              Release all locks belonging to CurrentResourceOwner
 
1603
 */
 
1604
void
 
1605
LockReleaseCurrentOwner(void)
 
1606
{
 
1607
        HASH_SEQ_STATUS status;
 
1608
        LOCALLOCK  *locallock;
 
1609
        LOCALLOCKOWNER *lockOwners;
 
1610
        int                     i;
 
1611
 
 
1612
        hash_seq_init(&status, LockMethodLocalHash);
 
1613
 
 
1614
        while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
 
1615
        {
 
1616
                /* Ignore items that must be nontransactional */
 
1617
                if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
 
1618
                        continue;
 
1619
 
 
1620
                /* Scan to see if there are any locks belonging to current owner */
 
1621
                lockOwners = locallock->lockOwners;
 
1622
                for (i = locallock->numLockOwners - 1; i >= 0; i--)
 
1623
                {
 
1624
                        if (lockOwners[i].owner == CurrentResourceOwner)
 
1625
                        {
 
1626
                                Assert(lockOwners[i].nLocks > 0);
 
1627
                                if (lockOwners[i].nLocks < locallock->nLocks)
 
1628
                                {
 
1629
                                        /*
 
1630
                                         * We will still hold this lock after forgetting this
 
1631
                                         * ResourceOwner.
 
1632
                                         */
 
1633
                                        locallock->nLocks -= lockOwners[i].nLocks;
 
1634
                                        /* compact out unused slot */
 
1635
                                        locallock->numLockOwners--;
 
1636
                                        if (i < locallock->numLockOwners)
 
1637
                                                lockOwners[i] = lockOwners[locallock->numLockOwners];
 
1638
                                }
 
1639
                                else
 
1640
                                {
 
1641
                                        Assert(lockOwners[i].nLocks == locallock->nLocks);
 
1642
                                        /* We want to call LockRelease just once */
 
1643
                                        lockOwners[i].nLocks = 1;
 
1644
                                        locallock->nLocks = 1;
 
1645
                                        if (!LockRelease(&locallock->tag.lock,
 
1646
                                                                         locallock->tag.mode,
 
1647
                                                                         false))
 
1648
                                                elog(WARNING, "LockReleaseCurrentOwner: failed??");
 
1649
                                }
 
1650
                                break;
 
1651
                        }
 
1652
                }
 
1653
        }
 
1654
}
 
1655
 
 
1656
/*
 
1657
 * LockReassignCurrentOwner
 
1658
 *              Reassign all locks belonging to CurrentResourceOwner to belong
 
1659
 *              to its parent resource owner
 
1660
 */
 
1661
void
 
1662
LockReassignCurrentOwner(void)
 
1663
{
 
1664
        ResourceOwner parent = ResourceOwnerGetParent(CurrentResourceOwner);
 
1665
        HASH_SEQ_STATUS status;
 
1666
        LOCALLOCK  *locallock;
 
1667
        LOCALLOCKOWNER *lockOwners;
 
1668
 
 
1669
        Assert(parent != NULL);
 
1670
 
 
1671
        hash_seq_init(&status, LockMethodLocalHash);
 
1672
 
 
1673
        while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
 
1674
        {
 
1675
                int                     i;
 
1676
                int                     ic = -1;
 
1677
                int                     ip = -1;
 
1678
 
 
1679
                /* Ignore items that must be nontransactional */
 
1680
                if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
 
1681
                        continue;
 
1682
 
 
1683
                /*
 
1684
                 * Scan to see if there are any locks belonging to current owner or
 
1685
                 * its parent
 
1686
                 */
 
1687
                lockOwners = locallock->lockOwners;
 
1688
                for (i = locallock->numLockOwners - 1; i >= 0; i--)
 
1689
                {
 
1690
                        if (lockOwners[i].owner == CurrentResourceOwner)
 
1691
                                ic = i;
 
1692
                        else if (lockOwners[i].owner == parent)
 
1693
                                ip = i;
 
1694
                }
 
1695
 
 
1696
                if (ic < 0)
 
1697
                        continue;                       /* no current locks */
 
1698
 
 
1699
                if (ip < 0)
 
1700
                {
 
1701
                        /* Parent has no slot, so just give it child's slot */
 
1702
                        lockOwners[ic].owner = parent;
 
1703
                }
 
1704
                else
 
1705
                {
 
1706
                        /* Merge child's count with parent's */
 
1707
                        lockOwners[ip].nLocks += lockOwners[ic].nLocks;
 
1708
                        /* compact out unused slot */
 
1709
                        locallock->numLockOwners--;
 
1710
                        if (ic < locallock->numLockOwners)
 
1711
                                lockOwners[ic] = lockOwners[locallock->numLockOwners];
 
1712
                }
 
1713
        }
 
1714
}
 
1715
 
 
1716
 
 
1717
/*
 
1718
 * GetLockConflicts
 
1719
 *              Get an array of VirtualTransactionIds of xacts currently holding locks
 
1720
 *              that would conflict with the specified lock/lockmode.
 
1721
 *              xacts merely awaiting such a lock are NOT reported.
 
1722
 *
 
1723
 * The result array is palloc'd and is terminated with an invalid VXID.
 
1724
 *
 
1725
 * Of course, the result could be out of date by the time it's returned,
 
1726
 * so use of this function has to be thought about carefully.
 
1727
 *
 
1728
 * Note we never include the current xact's vxid in the result array,
 
1729
 * since an xact never blocks itself.  Also, prepared transactions are
 
1730
 * ignored, which is a bit more debatable but is appropriate for current
 
1731
 * uses of the result.
 
1732
 */
 
1733
VirtualTransactionId *
 
1734
GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
 
1735
{
 
1736
        VirtualTransactionId *vxids;
 
1737
        LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
 
1738
        LockMethod      lockMethodTable;
 
1739
        LOCK       *lock;
 
1740
        LOCKMASK        conflictMask;
 
1741
        SHM_QUEUE  *procLocks;
 
1742
        PROCLOCK   *proclock;
 
1743
        uint32          hashcode;
 
1744
        LWLockId        partitionLock;
 
1745
        int                     count = 0;
 
1746
 
 
1747
        if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
 
1748
                elog(ERROR, "unrecognized lock method: %d", lockmethodid);
 
1749
        lockMethodTable = LockMethods[lockmethodid];
 
1750
        if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
 
1751
                elog(ERROR, "unrecognized lock mode: %d", lockmode);
 
1752
 
 
1753
        /*
 
1754
         * Allocate memory to store results, and fill with InvalidVXID.  We only
 
1755
         * need enough space for MaxBackends + a terminator, since prepared xacts
 
1756
         * don't count.
 
1757
         */
 
1758
        vxids = (VirtualTransactionId *)
 
1759
                palloc0(sizeof(VirtualTransactionId) * (MaxBackends + 1));
 
1760
 
 
1761
        /*
 
1762
         * Look up the lock object matching the tag.
 
1763
         */
 
1764
        hashcode = LockTagHashCode(locktag);
 
1765
        partitionLock = LockHashPartitionLock(hashcode);
 
1766
 
 
1767
        LWLockAcquire(partitionLock, LW_SHARED);
 
1768
 
 
1769
        lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
 
1770
                                                                                                (void *) locktag,
 
1771
                                                                                                hashcode,
 
1772
                                                                                                HASH_FIND,
 
1773
                                                                                                NULL);
 
1774
        if (!lock)
 
1775
        {
 
1776
                /*
 
1777
                 * If the lock object doesn't exist, there is nothing holding a lock
 
1778
                 * on this lockable object.
 
1779
                 */
 
1780
                LWLockRelease(partitionLock);
 
1781
                return vxids;
 
1782
        }
 
1783
 
 
1784
        /*
 
1785
         * Examine each existing holder (or awaiter) of the lock.
 
1786
         */
 
1787
        conflictMask = lockMethodTable->conflictTab[lockmode];
 
1788
 
 
1789
        procLocks = &(lock->procLocks);
 
1790
 
 
1791
        proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
 
1792
                                                                                 offsetof(PROCLOCK, lockLink));
 
1793
 
 
1794
        while (proclock)
 
1795
        {
 
1796
                if (conflictMask & proclock->holdMask)
 
1797
                {
 
1798
                        PGPROC     *proc = proclock->tag.myProc;
 
1799
 
 
1800
                        /* A backend never blocks itself */
 
1801
                        if (proc != MyProc)
 
1802
                        {
 
1803
                                VirtualTransactionId vxid;
 
1804
 
 
1805
                                GET_VXID_FROM_PGPROC(vxid, *proc);
 
1806
 
 
1807
                                /*
 
1808
                                 * If we see an invalid VXID, then either the xact has already
 
1809
                                 * committed (or aborted), or it's a prepared xact.  In either
 
1810
                                 * case we may ignore it.
 
1811
                                 */
 
1812
                                if (VirtualTransactionIdIsValid(vxid))
 
1813
                                        vxids[count++] = vxid;
 
1814
                        }
 
1815
                }
 
1816
 
 
1817
                proclock = (PROCLOCK *) SHMQueueNext(procLocks, &proclock->lockLink,
 
1818
                                                                                         offsetof(PROCLOCK, lockLink));
 
1819
        }
 
1820
 
 
1821
        LWLockRelease(partitionLock);
 
1822
 
 
1823
        if (count > MaxBackends)        /* should never happen */
 
1824
                elog(PANIC, "too many conflicting locks found");
 
1825
 
 
1826
        return vxids;
 
1827
}
 
1828
 
 
1829
 
 
1830
/*
 
1831
 * AtPrepare_Locks
 
1832
 *              Do the preparatory work for a PREPARE: make 2PC state file records
 
1833
 *              for all locks currently held.
 
1834
 *
 
1835
 * Non-transactional locks are ignored, as are VXID locks.
 
1836
 *
 
1837
 * There are some special cases that we error out on: we can't be holding
 
1838
 * any session locks (should be OK since only VACUUM uses those) and we
 
1839
 * can't be holding any locks on temporary objects (since that would mess
 
1840
 * up the current backend if it tries to exit before the prepared xact is
 
1841
 * committed).
 
1842
 */
 
1843
void
 
1844
AtPrepare_Locks(void)
 
1845
{
 
1846
        HASH_SEQ_STATUS status;
 
1847
        LOCALLOCK  *locallock;
 
1848
 
 
1849
        /*
 
1850
         * We don't need to touch shared memory for this --- all the necessary
 
1851
         * state information is in the locallock table.
 
1852
         */
 
1853
        hash_seq_init(&status, LockMethodLocalHash);
 
1854
 
 
1855
        while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
 
1856
        {
 
1857
                TwoPhaseLockRecord record;
 
1858
                LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
 
1859
                int                     i;
 
1860
 
 
1861
                /* Ignore nontransactional locks */
 
1862
                if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
 
1863
                        continue;
 
1864
 
 
1865
                /*
 
1866
                 * Ignore VXID locks.  We don't want those to be held by prepared
 
1867
                 * transactions, since they aren't meaningful after a restart.
 
1868
                 */
 
1869
                if (locallock->tag.lock.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
 
1870
                        continue;
 
1871
 
 
1872
                /* Ignore it if we don't actually hold the lock */
 
1873
                if (locallock->nLocks <= 0)
 
1874
                        continue;
 
1875
 
 
1876
                /* Scan to verify there are no session locks */
 
1877
                for (i = locallock->numLockOwners - 1; i >= 0; i--)
 
1878
                {
 
1879
                        /* elog not ereport since this should not happen */
 
1880
                        if (lockOwners[i].owner == NULL)
 
1881
                                elog(ERROR, "cannot PREPARE when session locks exist");
 
1882
                }
 
1883
 
 
1884
                /*
 
1885
                 * Create a 2PC record.
 
1886
                 */
 
1887
                memcpy(&(record.locktag), &(locallock->tag.lock), sizeof(LOCKTAG));
 
1888
                record.lockmode = locallock->tag.mode;
 
1889
 
 
1890
                RegisterTwoPhaseRecord(TWOPHASE_RM_LOCK_ID, 0,
 
1891
                                                           &record, sizeof(TwoPhaseLockRecord));
 
1892
        }
 
1893
}
 
1894
 
 
1895
/*
 
1896
 * PostPrepare_Locks
 
1897
 *              Clean up after successful PREPARE
 
1898
 *
 
1899
 * Here, we want to transfer ownership of our locks to a dummy PGPROC
 
1900
 * that's now associated with the prepared transaction, and we want to
 
1901
 * clean out the corresponding entries in the LOCALLOCK table.
 
1902
 *
 
1903
 * Note: by removing the LOCALLOCK entries, we are leaving dangling
 
1904
 * pointers in the transaction's resource owner.  This is OK at the
 
1905
 * moment since resowner.c doesn't try to free locks retail at a toplevel
 
1906
 * transaction commit or abort.  We could alternatively zero out nLocks
 
1907
 * and leave the LOCALLOCK entries to be garbage-collected by LockReleaseAll,
 
1908
 * but that probably costs more cycles.
 
1909
 */
 
1910
void
 
1911
PostPrepare_Locks(TransactionId xid)
 
1912
{
 
1913
        PGPROC     *newproc = TwoPhaseGetDummyProc(xid);
 
1914
        HASH_SEQ_STATUS status;
 
1915
        LOCALLOCK  *locallock;
 
1916
        LOCK       *lock;
 
1917
        PROCLOCK   *proclock;
 
1918
        PROCLOCKTAG proclocktag;
 
1919
        bool            found;
 
1920
        int                     partition;
 
1921
 
 
1922
        /* This is a critical section: any error means big trouble */
 
1923
        START_CRIT_SECTION();
 
1924
 
 
1925
        /*
 
1926
         * First we run through the locallock table and get rid of unwanted
 
1927
         * entries, then we scan the process's proclocks and transfer them to the
 
1928
         * target proc.
 
1929
         *
 
1930
         * We do this separately because we may have multiple locallock entries
 
1931
         * pointing to the same proclock, and we daren't end up with any dangling
 
1932
         * pointers.
 
1933
         */
 
1934
        hash_seq_init(&status, LockMethodLocalHash);
 
1935
 
 
1936
        while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
 
1937
        {
 
1938
                if (locallock->proclock == NULL || locallock->lock == NULL)
 
1939
                {
 
1940
                        /*
 
1941
                         * We must've run out of shared memory while trying to set up this
 
1942
                         * lock.  Just forget the local entry.
 
1943
                         */
 
1944
                        Assert(locallock->nLocks == 0);
 
1945
                        RemoveLocalLock(locallock);
 
1946
                        continue;
 
1947
                }
 
1948
 
 
1949
                /* Ignore nontransactional locks */
 
1950
                if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
 
1951
                        continue;
 
1952
 
 
1953
                /* Ignore VXID locks */
 
1954
                if (locallock->tag.lock.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
 
1955
                        continue;
 
1956
 
 
1957
                /* We already checked there are no session locks */
 
1958
 
 
1959
                /* Mark the proclock to show we need to release this lockmode */
 
1960
                if (locallock->nLocks > 0)
 
1961
                        locallock->proclock->releaseMask |= LOCKBIT_ON(locallock->tag.mode);
 
1962
 
 
1963
                /* And remove the locallock hashtable entry */
 
1964
                RemoveLocalLock(locallock);
 
1965
        }
 
1966
 
 
1967
        /*
 
1968
         * Now, scan each lock partition separately.
 
1969
         */
 
1970
        for (partition = 0; partition < NUM_LOCK_PARTITIONS; partition++)
 
1971
        {
 
1972
                LWLockId        partitionLock = FirstLockMgrLock + partition;
 
1973
                SHM_QUEUE  *procLocks = &(MyProc->myProcLocks[partition]);
 
1974
 
 
1975
                proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
 
1976
                                                                                         offsetof(PROCLOCK, procLink));
 
1977
 
 
1978
                if (!proclock)
 
1979
                        continue;                       /* needn't examine this partition */
 
1980
 
 
1981
                LWLockAcquire(partitionLock, LW_EXCLUSIVE);
 
1982
 
 
1983
                while (proclock)
 
1984
                {
 
1985
                        PROCLOCK   *nextplock;
 
1986
                        LOCKMASK        holdMask;
 
1987
                        PROCLOCK   *newproclock;
 
1988
 
 
1989
                        /* Get link first, since we may unlink/delete this proclock */
 
1990
                        nextplock = (PROCLOCK *)
 
1991
                                SHMQueueNext(procLocks, &proclock->procLink,
 
1992
                                                         offsetof(PROCLOCK, procLink));
 
1993
 
 
1994
                        Assert(proclock->tag.myProc == MyProc);
 
1995
 
 
1996
                        lock = proclock->tag.myLock;
 
1997
 
 
1998
                        /* Ignore nontransactional locks */
 
1999
                        if (!LockMethods[LOCK_LOCKMETHOD(*lock)]->transactional)
 
2000
                                goto next_item;
 
2001
 
 
2002
                        /* Ignore VXID locks */
 
2003
                        if (lock->tag.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
 
2004
                                goto next_item;
 
2005
 
 
2006
                        PROCLOCK_PRINT("PostPrepare_Locks", proclock);
 
2007
                        LOCK_PRINT("PostPrepare_Locks", lock, 0);
 
2008
                        Assert(lock->nRequested >= 0);
 
2009
                        Assert(lock->nGranted >= 0);
 
2010
                        Assert(lock->nGranted <= lock->nRequested);
 
2011
                        Assert((proclock->holdMask & ~lock->grantMask) == 0);
 
2012
 
 
2013
                        /*
 
2014
                         * Since there were no session locks, we should be releasing all
 
2015
                         * locks
 
2016
                         */
 
2017
                        if (proclock->releaseMask != proclock->holdMask)
 
2018
                                elog(PANIC, "we seem to have dropped a bit somewhere");
 
2019
 
 
2020
                        holdMask = proclock->holdMask;
 
2021
 
 
2022
                        /*
 
2023
                         * We cannot simply modify proclock->tag.myProc to reassign
 
2024
                         * ownership of the lock, because that's part of the hash key and
 
2025
                         * the proclock would then be in the wrong hash chain.  So, unlink
 
2026
                         * and delete the old proclock; create a new one with the right
 
2027
                         * contents; and link it into place.  We do it in this order to be
 
2028
                         * certain we won't run out of shared memory (the way dynahash.c
 
2029
                         * works, the deleted object is certain to be available for
 
2030
                         * reallocation).
 
2031
                         */
 
2032
                        SHMQueueDelete(&proclock->lockLink);
 
2033
                        SHMQueueDelete(&proclock->procLink);
 
2034
                        if (!hash_search(LockMethodProcLockHash,
 
2035
                                                         (void *) &(proclock->tag),
 
2036
                                                         HASH_REMOVE, NULL))
 
2037
                                elog(PANIC, "proclock table corrupted");
 
2038
 
 
2039
                        /*
 
2040
                         * Create the hash key for the new proclock table.
 
2041
                         */
 
2042
                        proclocktag.myLock = lock;
 
2043
                        proclocktag.myProc = newproc;
 
2044
 
 
2045
                        newproclock = (PROCLOCK *) hash_search(LockMethodProcLockHash,
 
2046
                                                                                                   (void *) &proclocktag,
 
2047
                                                                                                   HASH_ENTER_NULL, &found);
 
2048
                        if (!newproclock)
 
2049
                                ereport(PANIC,  /* should not happen */
 
2050
                                                (errcode(ERRCODE_OUT_OF_MEMORY),
 
2051
                                                 errmsg("out of shared memory"),
 
2052
                                                 errdetail("Not enough memory for reassigning the prepared transaction's locks.")));
 
2053
 
 
2054
                        /*
 
2055
                         * If new, initialize the new entry
 
2056
                         */
 
2057
                        if (!found)
 
2058
                        {
 
2059
                                newproclock->holdMask = 0;
 
2060
                                newproclock->releaseMask = 0;
 
2061
                                /* Add new proclock to appropriate lists */
 
2062
                                SHMQueueInsertBefore(&lock->procLocks, &newproclock->lockLink);
 
2063
                                SHMQueueInsertBefore(&(newproc->myProcLocks[partition]),
 
2064
                                                                         &newproclock->procLink);
 
2065
                                PROCLOCK_PRINT("PostPrepare_Locks: new", newproclock);
 
2066
                        }
 
2067
                        else
 
2068
                        {
 
2069
                                PROCLOCK_PRINT("PostPrepare_Locks: found", newproclock);
 
2070
                                Assert((newproclock->holdMask & ~lock->grantMask) == 0);
 
2071
                        }
 
2072
 
 
2073
                        /*
 
2074
                         * Pass over the identified lock ownership.
 
2075
                         */
 
2076
                        Assert((newproclock->holdMask & holdMask) == 0);
 
2077
                        newproclock->holdMask |= holdMask;
 
2078
 
 
2079
        next_item:
 
2080
                        proclock = nextplock;
 
2081
                }                                               /* loop over PROCLOCKs within this partition */
 
2082
 
 
2083
                LWLockRelease(partitionLock);
 
2084
        }                                                       /* loop over partitions */
 
2085
 
 
2086
        END_CRIT_SECTION();
 
2087
}
 
2088
 
 
2089
 
 
2090
/*
 
2091
 * Estimate shared-memory space used for lock tables
 
2092
 */
 
2093
Size
 
2094
LockShmemSize(void)
 
2095
{
 
2096
        Size            size = 0;
 
2097
        long            max_table_size;
 
2098
 
 
2099
        /* lock hash table */
 
2100
        max_table_size = NLOCKENTS();
 
2101
        size = add_size(size, hash_estimate_size(max_table_size, sizeof(LOCK)));
 
2102
 
 
2103
        /* proclock hash table */
 
2104
        max_table_size *= 2;
 
2105
        size = add_size(size, hash_estimate_size(max_table_size, sizeof(PROCLOCK)));
 
2106
 
 
2107
        /*
 
2108
         * Since NLOCKENTS is only an estimate, add 10% safety margin.
 
2109
         */
 
2110
        size = add_size(size, size / 10);
 
2111
 
 
2112
        return size;
 
2113
}
 
2114
 
 
2115
/*
 
2116
 * GetLockStatusData - Return a summary of the lock manager's internal
 
2117
 * status, for use in a user-level reporting function.
 
2118
 *
 
2119
 * The return data consists of an array of PROCLOCK objects, with the
 
2120
 * associated PGPROC and LOCK objects for each.  Note that multiple
 
2121
 * copies of the same PGPROC and/or LOCK objects are likely to appear.
 
2122
 * It is the caller's responsibility to match up duplicates if wanted.
 
2123
 *
 
2124
 * The design goal is to hold the LWLocks for as short a time as possible;
 
2125
 * thus, this function simply makes a copy of the necessary data and releases
 
2126
 * the locks, allowing the caller to contemplate and format the data for as
 
2127
 * long as it pleases.
 
2128
 */
 
2129
LockData *
 
2130
GetLockStatusData(void)
 
2131
{
 
2132
        LockData   *data;
 
2133
        PROCLOCK   *proclock;
 
2134
        HASH_SEQ_STATUS seqstat;
 
2135
        int                     els;
 
2136
        int                     el;
 
2137
        int                     i;
 
2138
 
 
2139
        data = (LockData *) palloc(sizeof(LockData));
 
2140
 
 
2141
        /*
 
2142
         * Acquire lock on the entire shared lock data structure.  We can't
 
2143
         * operate one partition at a time if we want to deliver a self-consistent
 
2144
         * view of the state.
 
2145
         *
 
2146
         * Since this is a read-only operation, we take shared instead of
 
2147
         * exclusive lock.      There's not a whole lot of point to this, because all
 
2148
         * the normal operations require exclusive lock, but it doesn't hurt
 
2149
         * anything either. It will at least allow two backends to do
 
2150
         * GetLockStatusData in parallel.
 
2151
         *
 
2152
         * Must grab LWLocks in partition-number order to avoid LWLock deadlock.
 
2153
         */
 
2154
        for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
 
2155
                LWLockAcquire(FirstLockMgrLock + i, LW_SHARED);
 
2156
 
 
2157
        /* Now we can safely count the number of proclocks */
 
2158
        els = hash_get_num_entries(LockMethodProcLockHash);
 
2159
 
 
2160
        data->nelements = els;
 
2161
        data->proclocks = (PROCLOCK *) palloc(sizeof(PROCLOCK) * els);
 
2162
        data->procs = (PGPROC *) palloc(sizeof(PGPROC) * els);
 
2163
        data->locks = (LOCK *) palloc(sizeof(LOCK) * els);
 
2164
 
 
2165
        /* Now scan the tables to copy the data */
 
2166
        hash_seq_init(&seqstat, LockMethodProcLockHash);
 
2167
 
 
2168
        el = 0;
 
2169
        while ((proclock = (PROCLOCK *) hash_seq_search(&seqstat)))
 
2170
        {
 
2171
                PGPROC     *proc = proclock->tag.myProc;
 
2172
                LOCK       *lock = proclock->tag.myLock;
 
2173
 
 
2174
                memcpy(&(data->proclocks[el]), proclock, sizeof(PROCLOCK));
 
2175
                memcpy(&(data->procs[el]), proc, sizeof(PGPROC));
 
2176
                memcpy(&(data->locks[el]), lock, sizeof(LOCK));
 
2177
 
 
2178
                el++;
 
2179
        }
 
2180
 
 
2181
        /*
 
2182
         * And release locks.  We do this in reverse order for two reasons: (1)
 
2183
         * Anyone else who needs more than one of the locks will be trying to lock
 
2184
         * them in increasing order; we don't want to release the other process
 
2185
         * until it can get all the locks it needs. (2) This avoids O(N^2)
 
2186
         * behavior inside LWLockRelease.
 
2187
         */
 
2188
        for (i = NUM_LOCK_PARTITIONS; --i >= 0;)
 
2189
                LWLockRelease(FirstLockMgrLock + i);
 
2190
 
 
2191
        Assert(el == data->nelements);
 
2192
 
 
2193
        return data;
 
2194
}
 
2195
 
 
2196
/* Provide the textual name of any lock mode */
 
2197
const char *
 
2198
GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode)
 
2199
{
 
2200
        Assert(lockmethodid > 0 && lockmethodid < lengthof(LockMethods));
 
2201
        Assert(mode > 0 && mode <= LockMethods[lockmethodid]->numLockModes);
 
2202
        return LockMethods[lockmethodid]->lockModeNames[mode];
 
2203
}
 
2204
 
 
2205
#ifdef LOCK_DEBUG
 
2206
/*
 
2207
 * Dump all locks in the given proc's myProcLocks lists.
 
2208
 *
 
2209
 * Caller is responsible for having acquired appropriate LWLocks.
 
2210
 */
 
2211
void
 
2212
DumpLocks(PGPROC *proc)
 
2213
{
 
2214
        SHM_QUEUE  *procLocks;
 
2215
        PROCLOCK   *proclock;
 
2216
        LOCK       *lock;
 
2217
        int                     i;
 
2218
 
 
2219
        if (proc == NULL)
 
2220
                return;
 
2221
 
 
2222
        if (proc->waitLock)
 
2223
                LOCK_PRINT("DumpLocks: waiting on", proc->waitLock, 0);
 
2224
 
 
2225
        for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
 
2226
        {
 
2227
                procLocks = &(proc->myProcLocks[i]);
 
2228
 
 
2229
                proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
 
2230
                                                                                         offsetof(PROCLOCK, procLink));
 
2231
 
 
2232
                while (proclock)
 
2233
                {
 
2234
                        Assert(proclock->tag.myProc == proc);
 
2235
 
 
2236
                        lock = proclock->tag.myLock;
 
2237
 
 
2238
                        PROCLOCK_PRINT("DumpLocks", proclock);
 
2239
                        LOCK_PRINT("DumpLocks", lock, 0);
 
2240
 
 
2241
                        proclock = (PROCLOCK *)
 
2242
                                SHMQueueNext(procLocks, &proclock->procLink,
 
2243
                                                         offsetof(PROCLOCK, procLink));
 
2244
                }
 
2245
        }
 
2246
}
 
2247
 
 
2248
/*
 
2249
 * Dump all lmgr locks.
 
2250
 *
 
2251
 * Caller is responsible for having acquired appropriate LWLocks.
 
2252
 */
 
2253
void
 
2254
DumpAllLocks(void)
 
2255
{
 
2256
        PGPROC     *proc;
 
2257
        PROCLOCK   *proclock;
 
2258
        LOCK       *lock;
 
2259
        HASH_SEQ_STATUS status;
 
2260
 
 
2261
        proc = MyProc;
 
2262
 
 
2263
        if (proc && proc->waitLock)
 
2264
                LOCK_PRINT("DumpAllLocks: waiting on", proc->waitLock, 0);
 
2265
 
 
2266
        hash_seq_init(&status, LockMethodProcLockHash);
 
2267
 
 
2268
        while ((proclock = (PROCLOCK *) hash_seq_search(&status)) != NULL)
 
2269
        {
 
2270
                PROCLOCK_PRINT("DumpAllLocks", proclock);
 
2271
 
 
2272
                lock = proclock->tag.myLock;
 
2273
                if (lock)
 
2274
                        LOCK_PRINT("DumpAllLocks", lock, 0);
 
2275
                else
 
2276
                        elog(LOG, "DumpAllLocks: proclock->tag.myLock = NULL");
 
2277
        }
 
2278
}
 
2279
#endif   /* LOCK_DEBUG */
 
2280
 
 
2281
/*
 
2282
 * LOCK 2PC resource manager's routines
 
2283
 */
 
2284
 
 
2285
/*
 
2286
 * Re-acquire a lock belonging to a transaction that was prepared.
 
2287
 *
 
2288
 * Because this function is run at db startup, re-acquiring the locks should
 
2289
 * never conflict with running transactions because there are none.  We
 
2290
 * assume that the lock state represented by the stored 2PC files is legal.
 
2291
 */
 
2292
void
 
2293
lock_twophase_recover(TransactionId xid, uint16 info,
 
2294
                                          void *recdata, uint32 len)
 
2295
{
 
2296
        TwoPhaseLockRecord *rec = (TwoPhaseLockRecord *) recdata;
 
2297
        PGPROC     *proc = TwoPhaseGetDummyProc(xid);
 
2298
        LOCKTAG    *locktag;
 
2299
        LOCKMODE        lockmode;
 
2300
        LOCKMETHODID lockmethodid;
 
2301
        LOCK       *lock;
 
2302
        PROCLOCK   *proclock;
 
2303
        PROCLOCKTAG proclocktag;
 
2304
        bool            found;
 
2305
        uint32          hashcode;
 
2306
        uint32          proclock_hashcode;
 
2307
        int                     partition;
 
2308
        LWLockId        partitionLock;
 
2309
        LockMethod      lockMethodTable;
 
2310
 
 
2311
        Assert(len == sizeof(TwoPhaseLockRecord));
 
2312
        locktag = &rec->locktag;
 
2313
        lockmode = rec->lockmode;
 
2314
        lockmethodid = locktag->locktag_lockmethodid;
 
2315
 
 
2316
        if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
 
2317
                elog(ERROR, "unrecognized lock method: %d", lockmethodid);
 
2318
        lockMethodTable = LockMethods[lockmethodid];
 
2319
 
 
2320
        hashcode = LockTagHashCode(locktag);
 
2321
        partition = LockHashPartition(hashcode);
 
2322
        partitionLock = LockHashPartitionLock(hashcode);
 
2323
 
 
2324
        LWLockAcquire(partitionLock, LW_EXCLUSIVE);
 
2325
 
 
2326
        /*
 
2327
         * Find or create a lock with this tag.
 
2328
         */
 
2329
        lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
 
2330
                                                                                                (void *) locktag,
 
2331
                                                                                                hashcode,
 
2332
                                                                                                HASH_ENTER_NULL,
 
2333
                                                                                                &found);
 
2334
        if (!lock)
 
2335
        {
 
2336
                LWLockRelease(partitionLock);
 
2337
                ereport(ERROR,
 
2338
                                (errcode(ERRCODE_OUT_OF_MEMORY),
 
2339
                                 errmsg("out of shared memory"),
 
2340
                  errhint("You might need to increase max_locks_per_transaction.")));
 
2341
        }
 
2342
 
 
2343
        /*
 
2344
         * if it's a new lock object, initialize it
 
2345
         */
 
2346
        if (!found)
 
2347
        {
 
2348
                lock->grantMask = 0;
 
2349
                lock->waitMask = 0;
 
2350
                SHMQueueInit(&(lock->procLocks));
 
2351
                ProcQueueInit(&(lock->waitProcs));
 
2352
                lock->nRequested = 0;
 
2353
                lock->nGranted = 0;
 
2354
                MemSet(lock->requested, 0, sizeof(int) * MAX_LOCKMODES);
 
2355
                MemSet(lock->granted, 0, sizeof(int) * MAX_LOCKMODES);
 
2356
                LOCK_PRINT("lock_twophase_recover: new", lock, lockmode);
 
2357
        }
 
2358
        else
 
2359
        {
 
2360
                LOCK_PRINT("lock_twophase_recover: found", lock, lockmode);
 
2361
                Assert((lock->nRequested >= 0) && (lock->requested[lockmode] >= 0));
 
2362
                Assert((lock->nGranted >= 0) && (lock->granted[lockmode] >= 0));
 
2363
                Assert(lock->nGranted <= lock->nRequested);
 
2364
        }
 
2365
 
 
2366
        /*
 
2367
         * Create the hash key for the proclock table.
 
2368
         */
 
2369
        proclocktag.myLock = lock;
 
2370
        proclocktag.myProc = proc;
 
2371
 
 
2372
        proclock_hashcode = ProcLockHashCode(&proclocktag, hashcode);
 
2373
 
 
2374
        /*
 
2375
         * Find or create a proclock entry with this tag
 
2376
         */
 
2377
        proclock = (PROCLOCK *) hash_search_with_hash_value(LockMethodProcLockHash,
 
2378
                                                                                                                (void *) &proclocktag,
 
2379
                                                                                                                proclock_hashcode,
 
2380
                                                                                                                HASH_ENTER_NULL,
 
2381
                                                                                                                &found);
 
2382
        if (!proclock)
 
2383
        {
 
2384
                /* Ooops, not enough shmem for the proclock */
 
2385
                if (lock->nRequested == 0)
 
2386
                {
 
2387
                        /*
 
2388
                         * There are no other requestors of this lock, so garbage-collect
 
2389
                         * the lock object.  We *must* do this to avoid a permanent leak
 
2390
                         * of shared memory, because there won't be anything to cause
 
2391
                         * anyone to release the lock object later.
 
2392
                         */
 
2393
                        Assert(SHMQueueEmpty(&(lock->procLocks)));
 
2394
                        if (!hash_search_with_hash_value(LockMethodLockHash,
 
2395
                                                                                         (void *) &(lock->tag),
 
2396
                                                                                         hashcode,
 
2397
                                                                                         HASH_REMOVE,
 
2398
                                                                                         NULL))
 
2399
                                elog(PANIC, "lock table corrupted");
 
2400
                }
 
2401
                LWLockRelease(partitionLock);
 
2402
                ereport(ERROR,
 
2403
                                (errcode(ERRCODE_OUT_OF_MEMORY),
 
2404
                                 errmsg("out of shared memory"),
 
2405
                  errhint("You might need to increase max_locks_per_transaction.")));
 
2406
        }
 
2407
 
 
2408
        /*
 
2409
         * If new, initialize the new entry
 
2410
         */
 
2411
        if (!found)
 
2412
        {
 
2413
                proclock->holdMask = 0;
 
2414
                proclock->releaseMask = 0;
 
2415
                /* Add proclock to appropriate lists */
 
2416
                SHMQueueInsertBefore(&lock->procLocks, &proclock->lockLink);
 
2417
                SHMQueueInsertBefore(&(proc->myProcLocks[partition]),
 
2418
                                                         &proclock->procLink);
 
2419
                PROCLOCK_PRINT("lock_twophase_recover: new", proclock);
 
2420
        }
 
2421
        else
 
2422
        {
 
2423
                PROCLOCK_PRINT("lock_twophase_recover: found", proclock);
 
2424
                Assert((proclock->holdMask & ~lock->grantMask) == 0);
 
2425
        }
 
2426
 
 
2427
        /*
 
2428
         * lock->nRequested and lock->requested[] count the total number of
 
2429
         * requests, whether granted or waiting, so increment those immediately.
 
2430
         */
 
2431
        lock->nRequested++;
 
2432
        lock->requested[lockmode]++;
 
2433
        Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0));
 
2434
 
 
2435
        /*
 
2436
         * We shouldn't already hold the desired lock.
 
2437
         */
 
2438
        if (proclock->holdMask & LOCKBIT_ON(lockmode))
 
2439
                elog(ERROR, "lock %s on object %u/%u/%u is already held",
 
2440
                         lockMethodTable->lockModeNames[lockmode],
 
2441
                         lock->tag.locktag_field1, lock->tag.locktag_field2,
 
2442
                         lock->tag.locktag_field3);
 
2443
 
 
2444
        /*
 
2445
         * We ignore any possible conflicts and just grant ourselves the lock.
 
2446
         */
 
2447
        GrantLock(lock, proclock, lockmode);
 
2448
 
 
2449
        LWLockRelease(partitionLock);
 
2450
}
 
2451
 
 
2452
/*
 
2453
 * 2PC processing routine for COMMIT PREPARED case.
 
2454
 *
 
2455
 * Find and release the lock indicated by the 2PC record.
 
2456
 */
 
2457
void
 
2458
lock_twophase_postcommit(TransactionId xid, uint16 info,
 
2459
                                                 void *recdata, uint32 len)
 
2460
{
 
2461
        TwoPhaseLockRecord *rec = (TwoPhaseLockRecord *) recdata;
 
2462
        PGPROC     *proc = TwoPhaseGetDummyProc(xid);
 
2463
        LOCKTAG    *locktag;
 
2464
        LOCKMODE        lockmode;
 
2465
        LOCKMETHODID lockmethodid;
 
2466
        LOCK       *lock;
 
2467
        PROCLOCK   *proclock;
 
2468
        PROCLOCKTAG proclocktag;
 
2469
        uint32          hashcode;
 
2470
        uint32          proclock_hashcode;
 
2471
        LWLockId        partitionLock;
 
2472
        LockMethod      lockMethodTable;
 
2473
        bool            wakeupNeeded;
 
2474
 
 
2475
        Assert(len == sizeof(TwoPhaseLockRecord));
 
2476
        locktag = &rec->locktag;
 
2477
        lockmode = rec->lockmode;
 
2478
        lockmethodid = locktag->locktag_lockmethodid;
 
2479
 
 
2480
        if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
 
2481
                elog(ERROR, "unrecognized lock method: %d", lockmethodid);
 
2482
        lockMethodTable = LockMethods[lockmethodid];
 
2483
 
 
2484
        hashcode = LockTagHashCode(locktag);
 
2485
        partitionLock = LockHashPartitionLock(hashcode);
 
2486
 
 
2487
        LWLockAcquire(partitionLock, LW_EXCLUSIVE);
 
2488
 
 
2489
        /*
 
2490
         * Re-find the lock object (it had better be there).
 
2491
         */
 
2492
        lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
 
2493
                                                                                                (void *) locktag,
 
2494
                                                                                                hashcode,
 
2495
                                                                                                HASH_FIND,
 
2496
                                                                                                NULL);
 
2497
        if (!lock)
 
2498
                elog(PANIC, "failed to re-find shared lock object");
 
2499
 
 
2500
        /*
 
2501
         * Re-find the proclock object (ditto).
 
2502
         */
 
2503
        proclocktag.myLock = lock;
 
2504
        proclocktag.myProc = proc;
 
2505
 
 
2506
        proclock_hashcode = ProcLockHashCode(&proclocktag, hashcode);
 
2507
 
 
2508
        proclock = (PROCLOCK *) hash_search_with_hash_value(LockMethodProcLockHash,
 
2509
                                                                                                                (void *) &proclocktag,
 
2510
                                                                                                                proclock_hashcode,
 
2511
                                                                                                                HASH_FIND,
 
2512
                                                                                                                NULL);
 
2513
        if (!proclock)
 
2514
                elog(PANIC, "failed to re-find shared proclock object");
 
2515
 
 
2516
        /*
 
2517
         * Double-check that we are actually holding a lock of the type we want to
 
2518
         * release.
 
2519
         */
 
2520
        if (!(proclock->holdMask & LOCKBIT_ON(lockmode)))
 
2521
        {
 
2522
                PROCLOCK_PRINT("lock_twophase_postcommit: WRONGTYPE", proclock);
 
2523
                LWLockRelease(partitionLock);
 
2524
                elog(WARNING, "you don't own a lock of type %s",
 
2525
                         lockMethodTable->lockModeNames[lockmode]);
 
2526
                return;
 
2527
        }
 
2528
 
 
2529
        /*
 
2530
         * Do the releasing.  CleanUpLock will waken any now-wakable waiters.
 
2531
         */
 
2532
        wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable);
 
2533
 
 
2534
        CleanUpLock(lock, proclock,
 
2535
                                lockMethodTable, hashcode,
 
2536
                                wakeupNeeded);
 
2537
 
 
2538
        LWLockRelease(partitionLock);
 
2539
}
 
2540
 
 
2541
/*
 
2542
 * 2PC processing routine for ROLLBACK PREPARED case.
 
2543
 *
 
2544
 * This is actually just the same as the COMMIT case.
 
2545
 */
 
2546
void
 
2547
lock_twophase_postabort(TransactionId xid, uint16 info,
 
2548
                                                void *recdata, uint32 len)
 
2549
{
 
2550
        lock_twophase_postcommit(xid, info, recdata, len);
 
2551
}