Add a small cache of locks owned by a resource owner in ResourceOwner.
Back-patch 9.3-era commit eeb6f37d89fc60c6449ca12ef9e91491069369cb, to improve the older branches' ability to cope with pg_dump dumping a large number of tables. I back-patched into 9.2 and 9.1, but not 9.0 as it would have required a significant amount of refactoring, thus negating the argument that this is by-now-well-tested code. Jeff Janes, reviewed by Amit Kapila and Heikki Linnakangas.
This commit is contained in:
parent
31934dd3dd
commit
9b1b9446f5
@ -257,6 +257,7 @@ static void RemoveLocalLock(LOCALLOCK *locallock);
|
|||||||
static void GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner);
|
static void GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner);
|
||||||
static void WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner);
|
static void WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner);
|
||||||
static void ReleaseLockIfHeld(LOCALLOCK *locallock, bool sessionLock);
|
static void ReleaseLockIfHeld(LOCALLOCK *locallock, bool sessionLock);
|
||||||
|
static void LockReassignOwner(LOCALLOCK *locallock, ResourceOwner parent);
|
||||||
static bool UnGrantLock(LOCK *lock, LOCKMODE lockmode,
|
static bool UnGrantLock(LOCK *lock, LOCKMODE lockmode,
|
||||||
PROCLOCK *proclock, LockMethod lockMethodTable);
|
PROCLOCK *proclock, LockMethod lockMethodTable);
|
||||||
static void CleanUpLock(LOCK *lock, PROCLOCK *proclock,
|
static void CleanUpLock(LOCK *lock, PROCLOCK *proclock,
|
||||||
@ -996,6 +997,13 @@ LockAcquireExtended(const LOCKTAG *locktag,
|
|||||||
static void
|
static void
|
||||||
RemoveLocalLock(LOCALLOCK *locallock)
|
RemoveLocalLock(LOCALLOCK *locallock)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = locallock->numLockOwners - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (locallock->lockOwners[i].owner != NULL)
|
||||||
|
ResourceOwnerForgetLock(locallock->lockOwners[i].owner, locallock);
|
||||||
|
}
|
||||||
pfree(locallock->lockOwners);
|
pfree(locallock->lockOwners);
|
||||||
locallock->lockOwners = NULL;
|
locallock->lockOwners = NULL;
|
||||||
if (!hash_search(LockMethodLocalHash,
|
if (!hash_search(LockMethodLocalHash,
|
||||||
@ -1241,6 +1249,8 @@ GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner)
|
|||||||
lockOwners[i].owner = owner;
|
lockOwners[i].owner = owner;
|
||||||
lockOwners[i].nLocks = 1;
|
lockOwners[i].nLocks = 1;
|
||||||
locallock->numLockOwners++;
|
locallock->numLockOwners++;
|
||||||
|
if (owner != NULL)
|
||||||
|
ResourceOwnerRememberLock(owner, locallock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1498,6 +1508,8 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
|
|||||||
Assert(lockOwners[i].nLocks > 0);
|
Assert(lockOwners[i].nLocks > 0);
|
||||||
if (--lockOwners[i].nLocks == 0)
|
if (--lockOwners[i].nLocks == 0)
|
||||||
{
|
{
|
||||||
|
if (owner != NULL)
|
||||||
|
ResourceOwnerForgetLock(owner, locallock);
|
||||||
/* compact out unused slot */
|
/* compact out unused slot */
|
||||||
locallock->numLockOwners--;
|
locallock->numLockOwners--;
|
||||||
if (i < locallock->numLockOwners)
|
if (i < locallock->numLockOwners)
|
||||||
@ -1636,14 +1648,13 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
|
|||||||
{
|
{
|
||||||
LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
|
LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
|
||||||
|
|
||||||
/* If it's above array position 0, move it down to 0 */
|
/* If session lock is above array position 0, move it down to 0 */
|
||||||
for (i = locallock->numLockOwners - 1; i > 0; i--)
|
for (i = 0; i < locallock->numLockOwners; i++)
|
||||||
{
|
{
|
||||||
if (lockOwners[i].owner == NULL)
|
if (lockOwners[i].owner == NULL)
|
||||||
{
|
|
||||||
lockOwners[0] = lockOwners[i];
|
lockOwners[0] = lockOwners[i];
|
||||||
break;
|
else
|
||||||
}
|
ResourceOwnerForgetLock(lockOwners[i].owner, locallock);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locallock->numLockOwners > 0 &&
|
if (locallock->numLockOwners > 0 &&
|
||||||
@ -1656,6 +1667,8 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
|
|||||||
/* We aren't deleting this locallock, so done */
|
/* We aren't deleting this locallock, so done */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
locallock->numLockOwners = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark the proclock to show we need to release this lockmode */
|
/* Mark the proclock to show we need to release this lockmode */
|
||||||
@ -1785,18 +1798,31 @@ LockReleaseSession(LOCKMETHODID lockmethodid)
|
|||||||
/*
|
/*
|
||||||
* LockReleaseCurrentOwner
|
* LockReleaseCurrentOwner
|
||||||
* Release all locks belonging to CurrentResourceOwner
|
* Release all locks belonging to CurrentResourceOwner
|
||||||
|
*
|
||||||
|
* If the caller knows what those locks are, it can pass them as an array.
|
||||||
|
* That speeds up the call significantly, when a lot of locks are held.
|
||||||
|
* Otherwise, pass NULL for locallocks, and we'll traverse through our hash
|
||||||
|
* table to find them.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
LockReleaseCurrentOwner(void)
|
LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks)
|
||||||
{
|
{
|
||||||
HASH_SEQ_STATUS status;
|
if (locallocks == NULL)
|
||||||
LOCALLOCK *locallock;
|
|
||||||
|
|
||||||
hash_seq_init(&status, LockMethodLocalHash);
|
|
||||||
|
|
||||||
while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
|
|
||||||
{
|
{
|
||||||
ReleaseLockIfHeld(locallock, false);
|
HASH_SEQ_STATUS status;
|
||||||
|
LOCALLOCK *locallock;
|
||||||
|
|
||||||
|
hash_seq_init(&status, LockMethodLocalHash);
|
||||||
|
|
||||||
|
while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
|
||||||
|
ReleaseLockIfHeld(locallock, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = nlocks - 1; i >= 0; i--)
|
||||||
|
ReleaseLockIfHeld(locallocks[i], false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1842,6 +1868,8 @@ ReleaseLockIfHeld(LOCALLOCK *locallock, bool sessionLock)
|
|||||||
locallock->nLocks -= lockOwners[i].nLocks;
|
locallock->nLocks -= lockOwners[i].nLocks;
|
||||||
/* compact out unused slot */
|
/* compact out unused slot */
|
||||||
locallock->numLockOwners--;
|
locallock->numLockOwners--;
|
||||||
|
if (owner != NULL)
|
||||||
|
ResourceOwnerForgetLock(owner, locallock);
|
||||||
if (i < locallock->numLockOwners)
|
if (i < locallock->numLockOwners)
|
||||||
lockOwners[i] = lockOwners[locallock->numLockOwners];
|
lockOwners[i] = lockOwners[locallock->numLockOwners];
|
||||||
}
|
}
|
||||||
@ -1864,59 +1892,85 @@ ReleaseLockIfHeld(LOCALLOCK *locallock, bool sessionLock)
|
|||||||
/*
|
/*
|
||||||
* LockReassignCurrentOwner
|
* LockReassignCurrentOwner
|
||||||
* Reassign all locks belonging to CurrentResourceOwner to belong
|
* Reassign all locks belonging to CurrentResourceOwner to belong
|
||||||
* to its parent resource owner
|
* to its parent resource owner.
|
||||||
|
*
|
||||||
|
* If the caller knows what those locks are, it can pass them as an array.
|
||||||
|
* That speeds up the call significantly, when a lot of locks are held
|
||||||
|
* (e.g pg_dump with a large schema). Otherwise, pass NULL for locallocks,
|
||||||
|
* and we'll traverse through our hash table to find them.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
LockReassignCurrentOwner(void)
|
LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks)
|
||||||
{
|
{
|
||||||
ResourceOwner parent = ResourceOwnerGetParent(CurrentResourceOwner);
|
ResourceOwner parent = ResourceOwnerGetParent(CurrentResourceOwner);
|
||||||
HASH_SEQ_STATUS status;
|
|
||||||
LOCALLOCK *locallock;
|
|
||||||
LOCALLOCKOWNER *lockOwners;
|
|
||||||
|
|
||||||
Assert(parent != NULL);
|
Assert(parent != NULL);
|
||||||
|
|
||||||
hash_seq_init(&status, LockMethodLocalHash);
|
if (locallocks == NULL)
|
||||||
|
{
|
||||||
|
HASH_SEQ_STATUS status;
|
||||||
|
LOCALLOCK *locallock;
|
||||||
|
|
||||||
while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
|
hash_seq_init(&status, LockMethodLocalHash);
|
||||||
|
|
||||||
|
while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
|
||||||
|
LockReassignOwner(locallock, parent);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int ic = -1;
|
|
||||||
int ip = -1;
|
|
||||||
|
|
||||||
/*
|
for (i = nlocks - 1; i >= 0; i--)
|
||||||
* Scan to see if there are any locks belonging to current owner or
|
LockReassignOwner(locallocks[i], parent);
|
||||||
* its parent
|
|
||||||
*/
|
|
||||||
lockOwners = locallock->lockOwners;
|
|
||||||
for (i = locallock->numLockOwners - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if (lockOwners[i].owner == CurrentResourceOwner)
|
|
||||||
ic = i;
|
|
||||||
else if (lockOwners[i].owner == parent)
|
|
||||||
ip = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ic < 0)
|
|
||||||
continue; /* no current locks */
|
|
||||||
|
|
||||||
if (ip < 0)
|
|
||||||
{
|
|
||||||
/* Parent has no slot, so just give it child's slot */
|
|
||||||
lockOwners[ic].owner = parent;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Merge child's count with parent's */
|
|
||||||
lockOwners[ip].nLocks += lockOwners[ic].nLocks;
|
|
||||||
/* compact out unused slot */
|
|
||||||
locallock->numLockOwners--;
|
|
||||||
if (ic < locallock->numLockOwners)
|
|
||||||
lockOwners[ic] = lockOwners[locallock->numLockOwners];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Subroutine of LockReassignCurrentOwner. Reassigns a given lock belonging to
|
||||||
|
* CurrentResourceOwner to its parent.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
LockReassignOwner(LOCALLOCK *locallock, ResourceOwner parent)
|
||||||
|
{
|
||||||
|
LOCALLOCKOWNER *lockOwners;
|
||||||
|
int i;
|
||||||
|
int ic = -1;
|
||||||
|
int ip = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scan to see if there are any locks belonging to current owner or its
|
||||||
|
* parent
|
||||||
|
*/
|
||||||
|
lockOwners = locallock->lockOwners;
|
||||||
|
for (i = locallock->numLockOwners - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (lockOwners[i].owner == CurrentResourceOwner)
|
||||||
|
ic = i;
|
||||||
|
else if (lockOwners[i].owner == parent)
|
||||||
|
ip = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ic < 0)
|
||||||
|
return; /* no current locks */
|
||||||
|
|
||||||
|
if (ip < 0)
|
||||||
|
{
|
||||||
|
/* Parent has no slot, so just give it the child's slot */
|
||||||
|
lockOwners[ic].owner = parent;
|
||||||
|
ResourceOwnerRememberLock(parent, locallock);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Merge child's count with parent's */
|
||||||
|
lockOwners[ip].nLocks += lockOwners[ic].nLocks;
|
||||||
|
/* compact out unused slot */
|
||||||
|
locallock->numLockOwners--;
|
||||||
|
if (ic < locallock->numLockOwners)
|
||||||
|
lockOwners[ic] = lockOwners[locallock->numLockOwners];
|
||||||
|
}
|
||||||
|
ResourceOwnerForgetLock(CurrentResourceOwner, locallock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GetLockConflicts
|
* GetLockConflicts
|
||||||
|
@ -29,6 +29,23 @@
|
|||||||
#include "utils/resowner.h"
|
#include "utils/resowner.h"
|
||||||
#include "utils/snapmgr.h"
|
#include "utils/snapmgr.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To speed up bulk releasing or reassigning locks from a resource owner to
|
||||||
|
* its parent, each resource owner has a small cache of locks it owns. The
|
||||||
|
* lock manager has the same information in its local lock hash table, and
|
||||||
|
* we fall back on that if cache overflows, but traversing the hash table
|
||||||
|
* is slower when there are a lot of locks belonging to other resource owners.
|
||||||
|
*
|
||||||
|
* MAX_RESOWNER_LOCKS is the size of the per-resource owner cache. It's
|
||||||
|
* chosen based on some testing with pg_dump with a large schema. When the
|
||||||
|
* tests were done (on 9.2), resource owners in a pg_dump run contained up
|
||||||
|
* to 9 locks, regardless of the schema size, except for the top resource
|
||||||
|
* owner which contained much more (overflowing the cache). 15 seems like a
|
||||||
|
* nice round number that's somewhat higher than what pg_dump needs. Note that
|
||||||
|
* making this number larger is not free - the bigger the cache, the slower
|
||||||
|
* it is to release locks (in retail), when a resource owner holds many locks.
|
||||||
|
*/
|
||||||
|
#define MAX_RESOWNER_LOCKS 15
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ResourceOwner objects look like this
|
* ResourceOwner objects look like this
|
||||||
@ -45,6 +62,10 @@ typedef struct ResourceOwnerData
|
|||||||
Buffer *buffers; /* dynamically allocated array */
|
Buffer *buffers; /* dynamically allocated array */
|
||||||
int maxbuffers; /* currently allocated array size */
|
int maxbuffers; /* currently allocated array size */
|
||||||
|
|
||||||
|
/* We can remember up to MAX_RESOWNER_LOCKS references to local locks. */
|
||||||
|
int nlocks; /* number of owned locks */
|
||||||
|
LOCALLOCK *locks[MAX_RESOWNER_LOCKS]; /* list of owned locks */
|
||||||
|
|
||||||
/* We have built-in support for remembering catcache references */
|
/* We have built-in support for remembering catcache references */
|
||||||
int ncatrefs; /* number of owned catcache pins */
|
int ncatrefs; /* number of owned catcache pins */
|
||||||
HeapTuple *catrefs; /* dynamically allocated array */
|
HeapTuple *catrefs; /* dynamically allocated array */
|
||||||
@ -274,11 +295,30 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
|
|||||||
* subtransaction, we do NOT release its locks yet, but transfer
|
* subtransaction, we do NOT release its locks yet, but transfer
|
||||||
* them to the parent.
|
* them to the parent.
|
||||||
*/
|
*/
|
||||||
|
LOCALLOCK **locks;
|
||||||
|
int nlocks;
|
||||||
|
|
||||||
Assert(owner->parent != NULL);
|
Assert(owner->parent != NULL);
|
||||||
if (isCommit)
|
|
||||||
LockReassignCurrentOwner();
|
/*
|
||||||
|
* Pass the list of locks owned by this resource owner to the lock
|
||||||
|
* manager, unless it has overflowed.
|
||||||
|
*/
|
||||||
|
if (owner->nlocks > MAX_RESOWNER_LOCKS)
|
||||||
|
{
|
||||||
|
locks = NULL;
|
||||||
|
nlocks = 0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
LockReleaseCurrentOwner();
|
{
|
||||||
|
locks = owner->locks;
|
||||||
|
nlocks = owner->nlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isCommit)
|
||||||
|
LockReassignCurrentOwner(locks, nlocks);
|
||||||
|
else
|
||||||
|
LockReleaseCurrentOwner(locks, nlocks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (phase == RESOURCE_RELEASE_AFTER_LOCKS)
|
else if (phase == RESOURCE_RELEASE_AFTER_LOCKS)
|
||||||
@ -359,6 +399,7 @@ ResourceOwnerDelete(ResourceOwner owner)
|
|||||||
|
|
||||||
/* And it better not own any resources, either */
|
/* And it better not own any resources, either */
|
||||||
Assert(owner->nbuffers == 0);
|
Assert(owner->nbuffers == 0);
|
||||||
|
Assert(owner->nlocks == 0 || owner->nlocks == MAX_RESOWNER_LOCKS + 1);
|
||||||
Assert(owner->ncatrefs == 0);
|
Assert(owner->ncatrefs == 0);
|
||||||
Assert(owner->ncatlistrefs == 0);
|
Assert(owner->ncatlistrefs == 0);
|
||||||
Assert(owner->nrelrefs == 0);
|
Assert(owner->nrelrefs == 0);
|
||||||
@ -590,6 +631,56 @@ ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remember that a Local Lock is owned by a ResourceOwner
|
||||||
|
*
|
||||||
|
* This is different from the other Remember functions in that the list of
|
||||||
|
* locks is only a lossy cache. It can hold up to MAX_RESOWNER_LOCKS entries,
|
||||||
|
* and when it overflows, we stop tracking locks. The point of only remembering
|
||||||
|
* only up to MAX_RESOWNER_LOCKS entries is that if a lot of locks are held,
|
||||||
|
* ResourceOwnerForgetLock doesn't need to scan through a large array to find
|
||||||
|
* the entry.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ResourceOwnerRememberLock(ResourceOwner owner, LOCALLOCK *locallock)
|
||||||
|
{
|
||||||
|
if (owner->nlocks > MAX_RESOWNER_LOCKS)
|
||||||
|
return; /* we have already overflowed */
|
||||||
|
|
||||||
|
if (owner->nlocks < MAX_RESOWNER_LOCKS)
|
||||||
|
owner->locks[owner->nlocks] = locallock;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* overflowed */
|
||||||
|
}
|
||||||
|
owner->nlocks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Forget that a Local Lock is owned by a ResourceOwner
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ResourceOwnerForgetLock(ResourceOwner owner, LOCALLOCK *locallock)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (owner->nlocks > MAX_RESOWNER_LOCKS)
|
||||||
|
return; /* we have overflowed */
|
||||||
|
|
||||||
|
Assert(owner->nlocks > 0);
|
||||||
|
for (i = owner->nlocks - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (locallock == owner->locks[i])
|
||||||
|
{
|
||||||
|
owner->locks[i] = owner->locks[owner->nlocks - 1];
|
||||||
|
owner->nlocks--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elog(ERROR, "lock reference %p is not owned by resource owner %s",
|
||||||
|
locallock, owner->name);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure there is room for at least one more entry in a ResourceOwner's
|
* Make sure there is room for at least one more entry in a ResourceOwner's
|
||||||
* catcache reference array.
|
* catcache reference array.
|
||||||
|
@ -488,8 +488,8 @@ extern bool LockRelease(const LOCKTAG *locktag,
|
|||||||
LOCKMODE lockmode, bool sessionLock);
|
LOCKMODE lockmode, bool sessionLock);
|
||||||
extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks);
|
extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks);
|
||||||
extern void LockReleaseSession(LOCKMETHODID lockmethodid);
|
extern void LockReleaseSession(LOCKMETHODID lockmethodid);
|
||||||
extern void LockReleaseCurrentOwner(void);
|
extern void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks);
|
||||||
extern void LockReassignCurrentOwner(void);
|
extern void LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks);
|
||||||
extern bool LockHasWaiters(const LOCKTAG *locktag,
|
extern bool LockHasWaiters(const LOCKTAG *locktag,
|
||||||
LOCKMODE lockmode, bool sessionLock);
|
LOCKMODE lockmode, bool sessionLock);
|
||||||
extern VirtualTransactionId *GetLockConflicts(const LOCKTAG *locktag,
|
extern VirtualTransactionId *GetLockConflicts(const LOCKTAG *locktag,
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "storage/buf.h"
|
#include "storage/buf.h"
|
||||||
#include "storage/fd.h"
|
#include "storage/fd.h"
|
||||||
|
#include "storage/lock.h"
|
||||||
#include "utils/catcache.h"
|
#include "utils/catcache.h"
|
||||||
#include "utils/plancache.h"
|
#include "utils/plancache.h"
|
||||||
#include "utils/snapshot.h"
|
#include "utils/snapshot.h"
|
||||||
@ -90,6 +91,10 @@ extern void ResourceOwnerEnlargeBuffers(ResourceOwner owner);
|
|||||||
extern void ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer);
|
extern void ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer);
|
||||||
extern void ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer);
|
extern void ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer);
|
||||||
|
|
||||||
|
/* support for local lock management */
|
||||||
|
extern void ResourceOwnerRememberLock(ResourceOwner owner, LOCALLOCK *locallock);
|
||||||
|
extern void ResourceOwnerForgetLock(ResourceOwner owner, LOCALLOCK *locallock);
|
||||||
|
|
||||||
/* support for catcache refcount management */
|
/* support for catcache refcount management */
|
||||||
extern void ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner);
|
extern void ResourceOwnerEnlargeCatCacheRefs(ResourceOwner owner);
|
||||||
extern void ResourceOwnerRememberCatCacheRef(ResourceOwner owner,
|
extern void ResourceOwnerRememberCatCacheRef(ResourceOwner owner,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user