PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
resowner.c File Reference
#include "postgres.h"
#include "common/hashfn.h"
#include "common/int.h"
#include "storage/ipc.h"
#include "storage/predicate.h"
#include "storage/proc.h"
#include "utils/memutils.h"
#include "utils/resowner.h"
Include dependency graph for resowner.c:

Go to the source code of this file.

Data Structures

struct  ResourceElem
 
struct  ResourceOwnerData
 
struct  ResourceReleaseCallbackItem
 

Macros

#define RESOWNER_ARRAY_SIZE   32
 
#define RESOWNER_HASH_INIT_SIZE   64
 
#define RESOWNER_HASH_MAX_ITEMS(capacity)    Min(capacity - RESOWNER_ARRAY_SIZE, (capacity)/4 * 3)
 
#define MAX_RESOWNER_LOCKS   15
 

Typedefs

typedef struct ResourceElem ResourceElem
 
typedef struct ResourceReleaseCallbackItem ResourceReleaseCallbackItem
 

Functions

 StaticAssertDecl (RESOWNER_HASH_MAX_ITEMS(RESOWNER_HASH_INIT_SIZE) >=RESOWNER_ARRAY_SIZE, "initial hash size too small compared to array size")
 
static uint32 hash_resource_elem (Datum value, const ResourceOwnerDesc *kind)
 
static void ResourceOwnerAddToHash (ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
 
static int resource_priority_cmp (const void *a, const void *b)
 
static void ResourceOwnerSort (ResourceOwner owner)
 
static void ResourceOwnerReleaseAll (ResourceOwner owner, ResourceReleasePhase phase, bool printLeakWarnings)
 
static void ResourceOwnerReleaseInternal (ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
 
static void ReleaseAuxProcessResourcesCallback (int code, Datum arg)
 
ResourceOwner ResourceOwnerCreate (ResourceOwner parent, const char *name)
 
void ResourceOwnerEnlarge (ResourceOwner owner)
 
void ResourceOwnerRemember (ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
 
void ResourceOwnerForget (ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
 
void ResourceOwnerRelease (ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
 
void ResourceOwnerReleaseAllOfKind (ResourceOwner owner, const ResourceOwnerDesc *kind)
 
void ResourceOwnerDelete (ResourceOwner owner)
 
ResourceOwner ResourceOwnerGetParent (ResourceOwner owner)
 
void ResourceOwnerNewParent (ResourceOwner owner, ResourceOwner newparent)
 
void RegisterResourceReleaseCallback (ResourceReleaseCallback callback, void *arg)
 
void UnregisterResourceReleaseCallback (ResourceReleaseCallback callback, void *arg)
 
void CreateAuxProcessResourceOwner (void)
 
void ReleaseAuxProcessResources (bool isCommit)
 
void ResourceOwnerRememberLock (ResourceOwner owner, LOCALLOCK *locallock)
 
void ResourceOwnerForgetLock (ResourceOwner owner, LOCALLOCK *locallock)
 

Variables

ResourceOwner CurrentResourceOwner = NULL
 
ResourceOwner CurTransactionResourceOwner = NULL
 
ResourceOwner TopTransactionResourceOwner = NULL
 
ResourceOwner AuxProcessResourceOwner = NULL
 
static ResourceReleaseCallbackItemResourceRelease_callbacks = NULL
 

Macro Definition Documentation

◆ MAX_RESOWNER_LOCKS

#define MAX_RESOWNER_LOCKS   15

Definition at line 105 of file resowner.c.

◆ RESOWNER_ARRAY_SIZE

#define RESOWNER_ARRAY_SIZE   32

Definition at line 71 of file resowner.c.

◆ RESOWNER_HASH_INIT_SIZE

#define RESOWNER_HASH_INIT_SIZE   64

Definition at line 77 of file resowner.c.

◆ RESOWNER_HASH_MAX_ITEMS

#define RESOWNER_HASH_MAX_ITEMS (   capacity)     Min(capacity - RESOWNER_ARRAY_SIZE, (capacity)/4 * 3)

Definition at line 89 of file resowner.c.

Typedef Documentation

◆ ResourceElem

typedef struct ResourceElem ResourceElem

◆ ResourceReleaseCallbackItem

Function Documentation

◆ CreateAuxProcessResourceOwner()

void CreateAuxProcessResourceOwner ( void  )

Definition at line 982 of file resowner.c.

983 {
985  Assert(CurrentResourceOwner == NULL);
986  AuxProcessResourceOwner = ResourceOwnerCreate(NULL, "AuxiliaryProcess");
988 
989  /*
990  * Register a shmem-exit callback for cleanup of aux-process resource
991  * owner. (This needs to run after, e.g., ShutdownXLOG.)
992  */
994 }
#define Assert(condition)
Definition: c.h:863
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:365
static void ReleaseAuxProcessResourcesCallback(int code, Datum arg)
Definition: resowner.c:1027
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:413
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165
ResourceOwner AuxProcessResourceOwner
Definition: resowner.c:168

References Assert, AuxProcessResourceOwner, CurrentResourceOwner, on_shmem_exit(), ReleaseAuxProcessResourcesCallback(), and ResourceOwnerCreate().

Referenced by AuxiliaryProcessMainCommon(), and InitPostgres().

◆ hash_resource_elem()

static uint32 hash_resource_elem ( Datum  value,
const ResourceOwnerDesc kind 
)
inlinestatic

Definition at line 214 of file resowner.c.

215 {
216  /*
217  * Most resource kinds store a pointer in 'value', and pointers are unique
218  * all on their own. But some resources store plain integers (Files and
219  * Buffers as of this writing), so we want to incorporate the 'kind' in
220  * the hash too, otherwise those resources will collide a lot. But
221  * because there are only a few resource kinds like that - and only a few
222  * resource kinds to begin with - we don't need to work too hard to mix
223  * 'kind' into the hash. Just add it with hash_combine(), it perturbs the
224  * result enough for our purposes.
225  */
226 #if SIZEOF_DATUM == 8
227  return hash_combine64(murmurhash64((uint64) value), (uint64) kind);
228 #else
229  return hash_combine(murmurhash32((uint32) value), (uint32) kind);
230 #endif
231 }
unsigned int uint32
Definition: c.h:518
static uint64 hash_combine64(uint64 a, uint64 b)
Definition: hashfn.h:80
static uint64 murmurhash64(uint64 data)
Definition: hashfn.h:106
static uint32 hash_combine(uint32 a, uint32 b)
Definition: hashfn.h:68
static uint32 murmurhash32(uint32 data)
Definition: hashfn.h:92
static struct @160 value

References hash_combine(), hash_combine64(), murmurhash32(), murmurhash64(), and value.

Referenced by ResourceOwnerAddToHash(), and ResourceOwnerForget().

◆ RegisterResourceReleaseCallback()

void RegisterResourceReleaseCallback ( ResourceReleaseCallback  callback,
void *  arg 
)

Definition at line 944 of file resowner.c.

945 {
947 
948  item = (ResourceReleaseCallbackItem *)
951  item->callback = callback;
952  item->arg = arg;
955 }
MemoryContext TopMemoryContext
Definition: mcxt.c:149
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
void * arg
static ResourceReleaseCallbackItem * ResourceRelease_callbacks
Definition: resowner.c:187
struct ResourceReleaseCallbackItem * next
Definition: resowner.c:182
ResourceReleaseCallback callback
Definition: resowner.c:183
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:46

References ResourceReleaseCallbackItem::arg, arg, ResourceReleaseCallbackItem::callback, callback(), MemoryContextAlloc(), ResourceReleaseCallbackItem::next, ResourceRelease_callbacks, and TopMemoryContext.

◆ ReleaseAuxProcessResources()

void ReleaseAuxProcessResources ( bool  isCommit)

Definition at line 1002 of file resowner.c.

1003 {
1004  /*
1005  * At this writing, the only thing that could actually get released is
1006  * buffer pins; but we may as well do the full release protocol.
1007  */
1010  isCommit, true);
1013  isCommit, true);
1016  isCommit, true);
1017  /* allow it to be reused */
1020 }
void ResourceOwnerRelease(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition: resowner.c:648
@ RESOURCE_RELEASE_LOCKS
Definition: resowner.h:55
@ RESOURCE_RELEASE_BEFORE_LOCKS
Definition: resowner.h:54
@ RESOURCE_RELEASE_AFTER_LOCKS
Definition: resowner.h:56

References AuxProcessResourceOwner, ResourceOwnerData::releasing, RESOURCE_RELEASE_AFTER_LOCKS, RESOURCE_RELEASE_BEFORE_LOCKS, RESOURCE_RELEASE_LOCKS, ResourceOwnerRelease(), and ResourceOwnerData::sorted.

Referenced by BackgroundWriterMain(), CheckpointerMain(), InitPostgres(), perform_base_backup(), pgarch_archiveXlog(), ReleaseAuxProcessResourcesCallback(), UploadManifest(), WalSndErrorCleanup(), WalSummarizerMain(), and WalWriterMain().

◆ ReleaseAuxProcessResourcesCallback()

static void ReleaseAuxProcessResourcesCallback ( int  code,
Datum  arg 
)
static

Definition at line 1027 of file resowner.c.

1028 {
1029  bool isCommit = (code == 0);
1030 
1031  ReleaseAuxProcessResources(isCommit);
1032 }
void ReleaseAuxProcessResources(bool isCommit)
Definition: resowner.c:1002

References ReleaseAuxProcessResources().

Referenced by CreateAuxProcessResourceOwner().

◆ resource_priority_cmp()

static int resource_priority_cmp ( const void *  a,
const void *  b 
)
static

Definition at line 261 of file resowner.c.

262 {
263  const ResourceElem *ra = (const ResourceElem *) a;
264  const ResourceElem *rb = (const ResourceElem *) b;
265 
266  /* Note: reverse order */
267  if (ra->kind->release_phase == rb->kind->release_phase)
269  else if (ra->kind->release_phase > rb->kind->release_phase)
270  return -1;
271  else
272  return 1;
273 }
static int pg_cmp_u32(uint32 a, uint32 b)
Definition: int.h:604
int b
Definition: isn.c:69
int a
Definition: isn.c:68
const ResourceOwnerDesc * kind
Definition: resowner.c:65
ResourceReleasePhase release_phase
Definition: resowner.h:96
ResourceReleasePriority release_priority
Definition: resowner.h:97

References a, b, ResourceElem::kind, pg_cmp_u32(), ResourceOwnerDesc::release_phase, and ResourceOwnerDesc::release_priority.

Referenced by ResourceOwnerSort().

◆ ResourceOwnerAddToHash()

static void ResourceOwnerAddToHash ( ResourceOwner  owner,
Datum  value,
const ResourceOwnerDesc kind 
)
static

Definition at line 237 of file resowner.c.

238 {
239  uint32 mask = owner->capacity - 1;
240  uint32 idx;
241 
242  Assert(kind != NULL);
243 
244  /* Insert into first free slot at or after hash location. */
245  idx = hash_resource_elem(value, kind) & mask;
246  for (;;)
247  {
248  if (owner->hash[idx].kind == NULL)
249  break; /* found a free slot */
250  idx = (idx + 1) & mask;
251  }
252  owner->hash[idx].item = value;
253  owner->hash[idx].kind = kind;
254  owner->nhash++;
255 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
static uint32 hash_resource_elem(Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:214
Datum item
Definition: resowner.c:64
ResourceElem * hash
Definition: resowner.c:152

References Assert, ResourceOwnerData::capacity, ResourceOwnerData::hash, hash_resource_elem(), idx(), ResourceElem::item, ResourceElem::kind, ResourceOwnerData::nhash, and value.

Referenced by ResourceOwnerEnlarge().

◆ ResourceOwnerCreate()

ResourceOwner ResourceOwnerCreate ( ResourceOwner  parent,
const char *  name 
)

Definition at line 413 of file resowner.c.

414 {
415  ResourceOwner owner;
416 
418  sizeof(struct ResourceOwnerData));
419  owner->name = name;
420 
421  if (parent)
422  {
423  owner->parent = parent;
424  owner->nextchild = parent->firstchild;
425  parent->firstchild = owner;
426  }
427 
428  return owner;
429 }
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1215
struct ResourceOwnerData * ResourceOwner
Definition: resowner.h:27
ResourceOwner parent
Definition: resowner.c:112
const char * name
Definition: resowner.c:115
ResourceOwner nextchild
Definition: resowner.c:114
ResourceOwner firstchild
Definition: resowner.c:113
const char * name

References ResourceOwnerData::firstchild, MemoryContextAllocZero(), name, ResourceOwnerData::name, ResourceOwnerData::nextchild, ResourceOwnerData::parent, and TopMemoryContext.

Referenced by AtStart_ResourceOwner(), AtSubStart_ResourceOwner(), CreateAuxProcessResourceOwner(), CreatePortal(), plpgsql_call_handler(), plpgsql_create_econtext(), plpgsql_inline_handler(), test_dsa_resowners(), test_resowner_forget_between_phases(), test_resowner_leak(), test_resowner_many(), test_resowner_priorities(), and test_resowner_remember_between_phases().

◆ ResourceOwnerDelete()

void ResourceOwnerDelete ( ResourceOwner  owner)

Definition at line 854 of file resowner.c.

855 {
856  /* We had better not be deleting CurrentResourceOwner ... */
857  Assert(owner != CurrentResourceOwner);
858 
859  /* And it better not own any resources, either */
860  Assert(owner->narr == 0);
861  Assert(owner->nhash == 0);
862  Assert(owner->nlocks == 0 || owner->nlocks == MAX_RESOWNER_LOCKS + 1);
863 
864  /*
865  * Delete children. The recursive call will delink the child from me, so
866  * just iterate as long as there is a child.
867  */
868  while (owner->firstchild != NULL)
870 
871  /*
872  * We delink the owner from its parent before deleting it, so that if
873  * there's an error we won't have deleted/busted owners still attached to
874  * the owner tree. Better a leak than a crash.
875  */
876  ResourceOwnerNewParent(owner, NULL);
877 
878  /* And free the object. */
879  if (owner->hash)
880  pfree(owner->hash);
881  pfree(owner);
882 }
void pfree(void *pointer)
Definition: mcxt.c:1521
void ResourceOwnerNewParent(ResourceOwner owner, ResourceOwner newparent)
Definition: resowner.c:897
#define MAX_RESOWNER_LOCKS
Definition: resowner.c:105
void ResourceOwnerDelete(ResourceOwner owner)
Definition: resowner.c:854

References Assert, CurrentResourceOwner, ResourceOwnerData::firstchild, ResourceOwnerData::hash, MAX_RESOWNER_LOCKS, ResourceOwnerData::narr, ResourceOwnerData::nhash, ResourceOwnerData::nlocks, pfree(), and ResourceOwnerNewParent().

Referenced by CleanupSubTransaction(), CleanupTransaction(), CommitSubTransaction(), CommitTransaction(), plpgsql_call_handler(), plpgsql_inline_handler(), PortalDrop(), PrepareTransaction(), test_dsa_resowners(), test_resowner_leak(), test_resowner_many(), and test_resowner_priorities().

◆ ResourceOwnerEnlarge()

void ResourceOwnerEnlarge ( ResourceOwner  owner)

Definition at line 442 of file resowner.c.

443 {
444  /*
445  * Mustn't try to remember more resources after we have already started
446  * releasing
447  */
448  if (owner->releasing)
449  elog(ERROR, "ResourceOwnerEnlarge called after release started");
450 
451  if (owner->narr < RESOWNER_ARRAY_SIZE)
452  return; /* no work needed */
453 
454  /*
455  * Is there space in the hash? If not, enlarge it.
456  */
457  if (owner->narr + owner->nhash >= owner->grow_at)
458  {
459  uint32 i,
460  oldcap,
461  newcap;
462  ResourceElem *oldhash;
463  ResourceElem *newhash;
464 
465  oldhash = owner->hash;
466  oldcap = owner->capacity;
467 
468  /* Double the capacity (it must stay a power of 2!) */
469  newcap = (oldcap > 0) ? oldcap * 2 : RESOWNER_HASH_INIT_SIZE;
471  newcap * sizeof(ResourceElem));
472 
473  /*
474  * We assume we can't fail below this point, so OK to scribble on the
475  * owner
476  */
477  owner->hash = newhash;
478  owner->capacity = newcap;
479  owner->grow_at = RESOWNER_HASH_MAX_ITEMS(newcap);
480  owner->nhash = 0;
481 
482  if (oldhash != NULL)
483  {
484  /*
485  * Transfer any pre-existing entries into the new hash table; they
486  * don't necessarily go where they were before, so this simple
487  * logic is the best way.
488  */
489  for (i = 0; i < oldcap; i++)
490  {
491  if (oldhash[i].kind != NULL)
492  ResourceOwnerAddToHash(owner, oldhash[i].item, oldhash[i].kind);
493  }
494 
495  /* And release old hash table. */
496  pfree(oldhash);
497  }
498  }
499 
500  /* Move items from the array to the hash */
501  for (int i = 0; i < owner->narr; i++)
502  ResourceOwnerAddToHash(owner, owner->arr[i].item, owner->arr[i].kind);
503  owner->narr = 0;
504 
505  Assert(owner->nhash <= owner->grow_at);
506 }
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
int i
Definition: isn.c:72
#define RESOWNER_HASH_INIT_SIZE
Definition: resowner.c:77
#define RESOWNER_HASH_MAX_ITEMS(capacity)
Definition: resowner.c:89
static void ResourceOwnerAddToHash(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:237
#define RESOWNER_ARRAY_SIZE
Definition: resowner.c:71
ResourceElem arr[RESOWNER_ARRAY_SIZE]
Definition: resowner.c:140

References ResourceOwnerData::arr, Assert, ResourceOwnerData::capacity, elog, ERROR, ResourceOwnerData::grow_at, ResourceOwnerData::hash, i, ResourceElem::item, ResourceElem::kind, MemoryContextAllocZero(), ResourceOwnerData::narr, ResourceOwnerData::nhash, pfree(), ResourceOwnerData::releasing, ResourceOwnerAddToHash(), RESOWNER_ARRAY_SIZE, RESOWNER_HASH_INIT_SIZE, RESOWNER_HASH_MAX_ITEMS, and TopMemoryContext.

Referenced by BufferAlloc(), CachedPlanAllowsSimpleValidityCheck(), CachedPlanIsSimplyValid(), CreateWaitEventSet(), dsm_create_descriptor(), dsm_unpin_mapping(), EvictUnpinnedBuffer(), ExtendBufferedRelLocal(), ExtendBufferedRelShared(), FlushDatabaseBuffers(), FlushRelationBuffers(), FlushRelationsAllBuffers(), GetCachedPlan(), GetLocalVictimBuffer(), GetVictimBuffer(), IncrBufferRefCount(), IncrTupleDescRefCount(), llvm_create_context(), LocalBufferAlloc(), OpenTemporaryFile(), PathNameCreateTemporaryFile(), PathNameOpenTemporaryFile(), pg_cryptohash_create(), pg_hmac_create(), px_find_cipher(), px_find_digest(), ReadRecentBuffer(), RegisterSnapshotOnOwner(), RelationIncrementReferenceCount(), RememberManyTestResources(), SearchCatCacheInternal(), SearchCatCacheList(), SearchCatCacheMiss(), StartBufferIO(), SyncOneBuffer(), test_resowner_forget_between_phases(), test_resowner_leak(), test_resowner_priorities(), and test_resowner_remember_between_phases().

◆ ResourceOwnerForget()

void ResourceOwnerForget ( ResourceOwner  owner,
Datum  value,
const ResourceOwnerDesc kind 
)

Definition at line 554 of file resowner.c.

555 {
556  /*
557  * Mustn't call this after we have already started releasing resources.
558  * (Release callback functions are not allowed to release additional
559  * resources.)
560  */
561  if (owner->releasing)
562  elog(ERROR, "ResourceOwnerForget called for %s after release started", kind->name);
563  Assert(!owner->sorted);
564 
565  /* Search through all items in the array first. */
566  for (int i = owner->narr - 1; i >= 0; i--)
567  {
568  if (owner->arr[i].item == value &&
569  owner->arr[i].kind == kind)
570  {
571  owner->arr[i] = owner->arr[owner->narr - 1];
572  owner->narr--;
573 
574 #ifdef RESOWNER_STATS
575  narray_lookups++;
576 #endif
577  return;
578  }
579  }
580 
581  /* Search hash */
582  if (owner->nhash > 0)
583  {
584  uint32 mask = owner->capacity - 1;
585  uint32 idx;
586 
587  idx = hash_resource_elem(value, kind) & mask;
588  for (uint32 i = 0; i < owner->capacity; i++)
589  {
590  if (owner->hash[idx].item == value &&
591  owner->hash[idx].kind == kind)
592  {
593  owner->hash[idx].item = (Datum) 0;
594  owner->hash[idx].kind = NULL;
595  owner->nhash--;
596 
597 #ifdef RESOWNER_STATS
598  nhash_lookups++;
599 #endif
600  return;
601  }
602  idx = (idx + 1) & mask;
603  }
604  }
605 
606  /*
607  * Use %p to print the reference, since most objects tracked by a resource
608  * owner are pointers. It's a bit misleading if it's not a pointer, but
609  * this is a programmer error, anyway.
610  */
611  elog(ERROR, "%s %p is not owned by resource owner %s",
612  kind->name, DatumGetPointer(value), owner->name);
613 }
uintptr_t Datum
Definition: postgres.h:64
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
const char * name
Definition: resowner.h:93

References ResourceOwnerData::arr, Assert, ResourceOwnerData::capacity, DatumGetPointer(), elog, ERROR, ResourceOwnerData::hash, hash_resource_elem(), i, idx(), ResourceElem::item, ResourceElem::kind, ResourceOwnerData::name, ResourceOwnerDesc::name, ResourceOwnerData::narr, ResourceOwnerData::nhash, ResourceOwnerData::releasing, ResourceOwnerData::sorted, and value.

Referenced by ForgetManyTestResources(), ResourceOwnerForgetBuffer(), ResourceOwnerForgetBufferIO(), ResourceOwnerForgetCatCacheListRef(), ResourceOwnerForgetCatCacheRef(), ResourceOwnerForgetCryptoHash(), ResourceOwnerForgetDSM(), ResourceOwnerForgetFile(), ResourceOwnerForgetHMAC(), ResourceOwnerForgetJIT(), ResourceOwnerForgetOSSLCipher(), ResourceOwnerForgetOSSLDigest(), ResourceOwnerForgetPlanCacheRef(), ResourceOwnerForgetRelationRef(), ResourceOwnerForgetSnapshot(), ResourceOwnerForgetTupleDesc(), ResourceOwnerForgetWaitEventSet(), and test_resowner_forget_between_phases().

◆ ResourceOwnerForgetLock()

void ResourceOwnerForgetLock ( ResourceOwner  owner,
LOCALLOCK locallock 
)

Definition at line 1065 of file resowner.c.

1066 {
1067  int i;
1068 
1069  if (owner->nlocks > MAX_RESOWNER_LOCKS)
1070  return; /* we have overflowed */
1071 
1072  Assert(owner->nlocks > 0);
1073  for (i = owner->nlocks - 1; i >= 0; i--)
1074  {
1075  if (locallock == owner->locks[i])
1076  {
1077  owner->locks[i] = owner->locks[owner->nlocks - 1];
1078  owner->nlocks--;
1079  return;
1080  }
1081  }
1082  elog(ERROR, "lock reference %p is not owned by resource owner %s",
1083  locallock, owner->name);
1084 }
LOCALLOCK * locks[MAX_RESOWNER_LOCKS]
Definition: resowner.c:157

References Assert, elog, ERROR, i, ResourceOwnerData::locks, MAX_RESOWNER_LOCKS, ResourceOwnerData::name, and ResourceOwnerData::nlocks.

Referenced by LockReassignOwner(), LockRelease(), LockReleaseAll(), ReleaseLockIfHeld(), and RemoveLocalLock().

◆ ResourceOwnerGetParent()

ResourceOwner ResourceOwnerGetParent ( ResourceOwner  owner)

Definition at line 888 of file resowner.c.

889 {
890  return owner->parent;
891 }

References ResourceOwnerData::parent.

Referenced by LockReassignCurrentOwner().

◆ ResourceOwnerNewParent()

void ResourceOwnerNewParent ( ResourceOwner  owner,
ResourceOwner  newparent 
)

Definition at line 897 of file resowner.c.

899 {
900  ResourceOwner oldparent = owner->parent;
901 
902  if (oldparent)
903  {
904  if (owner == oldparent->firstchild)
905  oldparent->firstchild = owner->nextchild;
906  else
907  {
908  ResourceOwner child;
909 
910  for (child = oldparent->firstchild; child; child = child->nextchild)
911  {
912  if (owner == child->nextchild)
913  {
914  child->nextchild = owner->nextchild;
915  break;
916  }
917  }
918  }
919  }
920 
921  if (newparent)
922  {
923  Assert(owner != newparent);
924  owner->parent = newparent;
925  owner->nextchild = newparent->firstchild;
926  newparent->firstchild = owner;
927  }
928  else
929  {
930  owner->parent = NULL;
931  owner->nextchild = NULL;
932  }
933 }

References Assert, ResourceOwnerData::firstchild, ResourceOwnerData::nextchild, and ResourceOwnerData::parent.

Referenced by AtSubAbort_Portals(), AtSubCommit_Portals(), and ResourceOwnerDelete().

◆ ResourceOwnerRelease()

void ResourceOwnerRelease ( ResourceOwner  owner,
ResourceReleasePhase  phase,
bool  isCommit,
bool  isTopLevel 
)

Definition at line 648 of file resowner.c.

652 {
653  /* There's not currently any setup needed before recursing */
654  ResourceOwnerReleaseInternal(owner, phase, isCommit, isTopLevel);
655 
656 #ifdef RESOWNER_STATS
657  if (isTopLevel)
658  {
659  elog(LOG, "RESOWNER STATS: lookups: array %d, hash %d",
660  narray_lookups, nhash_lookups);
661  narray_lookups = 0;
662  nhash_lookups = 0;
663  }
664 #endif
665 }
#define LOG
Definition: elog.h:31
static void ResourceOwnerReleaseInternal(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition: resowner.c:668

References elog, LOG, and ResourceOwnerReleaseInternal().

Referenced by AbortSubTransaction(), AbortTransaction(), CommitSubTransaction(), CommitTransaction(), PortalDrop(), PrepareTransaction(), ReleaseAuxProcessResources(), test_dsa_resowners(), test_resowner_forget_between_phases(), test_resowner_leak(), test_resowner_many(), test_resowner_priorities(), and test_resowner_remember_between_phases().

◆ ResourceOwnerReleaseAll()

static void ResourceOwnerReleaseAll ( ResourceOwner  owner,
ResourceReleasePhase  phase,
bool  printLeakWarnings 
)
static

Definition at line 340 of file resowner.c.

342 {
344  uint32 nitems;
345 
346  /*
347  * ResourceOwnerSort must've been called already. All the resources are
348  * either in the array or the hash.
349  */
350  Assert(owner->releasing);
351  Assert(owner->sorted);
352  if (owner->nhash == 0)
353  {
354  items = owner->arr;
355  nitems = owner->narr;
356  }
357  else
358  {
359  Assert(owner->narr == 0);
360  items = owner->hash;
361  nitems = owner->nhash;
362  }
363 
364  /*
365  * The resources are sorted in reverse priority order. Release them
366  * starting from the end, until we hit the end of the phase that we are
367  * releasing now. We will continue from there when called again for the
368  * next phase.
369  */
370  while (nitems > 0)
371  {
372  uint32 idx = nitems - 1;
373  Datum value = items[idx].item;
374  const ResourceOwnerDesc *kind = items[idx].kind;
375 
376  if (kind->release_phase > phase)
377  break;
378  Assert(kind->release_phase == phase);
379 
380  if (printLeakWarnings)
381  {
382  char *res_str;
383 
384  res_str = kind->DebugPrint ?
385  kind->DebugPrint(value)
386  : psprintf("%s %p", kind->name, DatumGetPointer(value));
387  elog(WARNING, "resource was not closed: %s", res_str);
388  pfree(res_str);
389  }
390  kind->ReleaseResource(value);
391  nitems--;
392  }
393  if (owner->nhash == 0)
394  owner->narr = nitems;
395  else
396  owner->nhash = nitems;
397 }
#define WARNING
Definition: elog.h:36
#define nitems(x)
Definition: indent.h:31
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
char *(* DebugPrint)(Datum res)
Definition: resowner.h:118
void(* ReleaseResource)(Datum res)
Definition: resowner.h:108
static ItemArray items
Definition: test_tidstore.c:48

References ResourceOwnerData::arr, Assert, DatumGetPointer(), ResourceOwnerDesc::DebugPrint, elog, ResourceOwnerData::hash, idx(), items, ResourceOwnerDesc::name, ResourceOwnerData::narr, ResourceOwnerData::nhash, nitems, pfree(), psprintf(), ResourceOwnerDesc::release_phase, ResourceOwnerDesc::ReleaseResource, ResourceOwnerData::releasing, ResourceOwnerData::sorted, value, and WARNING.

Referenced by ResourceOwnerReleaseInternal().

◆ ResourceOwnerReleaseAllOfKind()

void ResourceOwnerReleaseAllOfKind ( ResourceOwner  owner,
const ResourceOwnerDesc kind 
)

Definition at line 801 of file resowner.c.

802 {
803  /* Mustn't call this after we have already started releasing resources. */
804  if (owner->releasing)
805  elog(ERROR, "ResourceOwnerForget called for %s after release started", kind->name);
806  Assert(!owner->sorted);
807 
808  /*
809  * Temporarily set 'releasing', to prevent calls to ResourceOwnerRemember
810  * while we're scanning the owner. Enlarging the hash would cause us to
811  * lose track of the point we're scanning.
812  */
813  owner->releasing = true;
814 
815  /* Array first */
816  for (int i = 0; i < owner->narr; i++)
817  {
818  if (owner->arr[i].kind == kind)
819  {
820  Datum value = owner->arr[i].item;
821 
822  owner->arr[i] = owner->arr[owner->narr - 1];
823  owner->narr--;
824  i--;
825 
826  kind->ReleaseResource(value);
827  }
828  }
829 
830  /* Then hash */
831  for (int i = 0; i < owner->capacity; i++)
832  {
833  if (owner->hash[i].kind == kind)
834  {
835  Datum value = owner->hash[i].item;
836 
837  owner->hash[i].item = (Datum) 0;
838  owner->hash[i].kind = NULL;
839  owner->nhash--;
840 
841  kind->ReleaseResource(value);
842  }
843  }
844  owner->releasing = false;
845 }

References ResourceOwnerData::arr, Assert, ResourceOwnerData::capacity, elog, ERROR, ResourceOwnerData::hash, i, ResourceElem::item, ResourceElem::kind, ResourceOwnerDesc::name, ResourceOwnerData::narr, ResourceOwnerData::nhash, ResourceOwnerDesc::ReleaseResource, ResourceOwnerData::releasing, ResourceOwnerData::sorted, and value.

Referenced by ReleaseAllPlanCacheRefsInOwner().

◆ ResourceOwnerReleaseInternal()

static void ResourceOwnerReleaseInternal ( ResourceOwner  owner,
ResourceReleasePhase  phase,
bool  isCommit,
bool  isTopLevel 
)
static

Definition at line 668 of file resowner.c.

672 {
673  ResourceOwner child;
674  ResourceOwner save;
677 
678  /* Recurse to handle descendants */
679  for (child = owner->firstchild; child != NULL; child = child->nextchild)
680  ResourceOwnerReleaseInternal(child, phase, isCommit, isTopLevel);
681 
682  /*
683  * To release the resources in the right order, sort them by phase and
684  * priority.
685  *
686  * The ReleaseResource callback functions are not allowed to remember or
687  * forget any other resources after this. Otherwise we lose track of where
688  * we are in processing the hash/array.
689  */
690  if (!owner->releasing)
691  {
693  Assert(!owner->sorted);
694  owner->releasing = true;
695  }
696  else
697  {
698  /*
699  * Phase is normally > RESOURCE_RELEASE_BEFORE_LOCKS, if this is not
700  * the first call to ResourceOwnerRelease. But if an error happens
701  * between the release phases, we might get called again for the same
702  * ResourceOwner from AbortTransaction.
703  */
704  }
705  if (!owner->sorted)
706  {
707  ResourceOwnerSort(owner);
708  owner->sorted = true;
709  }
710 
711  /*
712  * Make CurrentResourceOwner point to me, so that the release callback
713  * functions know which resource owner is been released.
714  */
715  save = CurrentResourceOwner;
716  CurrentResourceOwner = owner;
717 
718  if (phase == RESOURCE_RELEASE_BEFORE_LOCKS)
719  {
720  /*
721  * Release all resources that need to be released before the locks.
722  *
723  * During a commit, there shouldn't be any remaining resources ---
724  * that would indicate failure to clean up the executor correctly ---
725  * so issue warnings. In the abort case, just clean up quietly.
726  */
727  ResourceOwnerReleaseAll(owner, phase, isCommit);
728  }
729  else if (phase == RESOURCE_RELEASE_LOCKS)
730  {
731  if (isTopLevel)
732  {
733  /*
734  * For a top-level xact we are going to release all locks (or at
735  * least all non-session locks), so just do a single lmgr call at
736  * the top of the recursion.
737  */
738  if (owner == TopTransactionResourceOwner)
739  {
740  ProcReleaseLocks(isCommit);
741  ReleasePredicateLocks(isCommit, false);
742  }
743  }
744  else
745  {
746  /*
747  * Release locks retail. Note that if we are committing a
748  * subtransaction, we do NOT release its locks yet, but transfer
749  * them to the parent.
750  */
751  LOCALLOCK **locks;
752  int nlocks;
753 
754  Assert(owner->parent != NULL);
755 
756  /*
757  * Pass the list of locks owned by this resource owner to the lock
758  * manager, unless it has overflowed.
759  */
760  if (owner->nlocks > MAX_RESOWNER_LOCKS)
761  {
762  locks = NULL;
763  nlocks = 0;
764  }
765  else
766  {
767  locks = owner->locks;
768  nlocks = owner->nlocks;
769  }
770 
771  if (isCommit)
772  LockReassignCurrentOwner(locks, nlocks);
773  else
774  LockReleaseCurrentOwner(locks, nlocks);
775  }
776  }
777  else if (phase == RESOURCE_RELEASE_AFTER_LOCKS)
778  {
779  /*
780  * Release all resources that need to be released after the locks.
781  */
782  ResourceOwnerReleaseAll(owner, phase, isCommit);
783  }
784 
785  /* Let add-on modules get a chance too */
786  for (item = ResourceRelease_callbacks; item; item = next)
787  {
788  /* allow callbacks to unregister themselves when called */
789  next = item->next;
790  item->callback(phase, isCommit, isTopLevel, item->arg);
791  }
792 
793  CurrentResourceOwner = save;
794 }
static int32 next
Definition: blutils.c:219
void LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks)
Definition: lock.c:2615
void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks)
Definition: lock.c:2520
void ReleasePredicateLocks(bool isCommit, bool isReadOnlySafe)
Definition: predicate.c:3302
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:167
static void ResourceOwnerReleaseAll(ResourceOwner owner, ResourceReleasePhase phase, bool printLeakWarnings)
Definition: resowner.c:340
static void ResourceOwnerSort(ResourceOwner owner)
Definition: resowner.c:284
void ProcReleaseLocks(bool isCommit)
Definition: proc.c:835

References ResourceReleaseCallbackItem::arg, Assert, ResourceReleaseCallbackItem::callback, CurrentResourceOwner, ResourceOwnerData::firstchild, LockReassignCurrentOwner(), LockReleaseCurrentOwner(), ResourceOwnerData::locks, MAX_RESOWNER_LOCKS, next, ResourceReleaseCallbackItem::next, ResourceOwnerData::nextchild, ResourceOwnerData::nlocks, ResourceOwnerData::parent, ProcReleaseLocks(), ReleasePredicateLocks(), ResourceOwnerData::releasing, RESOURCE_RELEASE_AFTER_LOCKS, RESOURCE_RELEASE_BEFORE_LOCKS, RESOURCE_RELEASE_LOCKS, ResourceOwnerReleaseAll(), ResourceOwnerSort(), ResourceRelease_callbacks, ResourceOwnerData::sorted, and TopTransactionResourceOwner.

Referenced by ResourceOwnerRelease().

◆ ResourceOwnerRemember()

void ResourceOwnerRemember ( ResourceOwner  owner,
Datum  value,
const ResourceOwnerDesc kind 
)

Definition at line 514 of file resowner.c.

515 {
516  uint32 idx;
517 
518  /* sanity check the ResourceOwnerDesc */
519  Assert(kind->release_phase != 0);
520  Assert(kind->release_priority != 0);
521 
522  /*
523  * Mustn't try to remember more resources after we have already started
524  * releasing. We already checked this in ResourceOwnerEnlarge.
525  */
526  Assert(!owner->releasing);
527  Assert(!owner->sorted);
528 
529  if (owner->narr >= RESOWNER_ARRAY_SIZE)
530  {
531  /* forgot to call ResourceOwnerEnlarge? */
532  elog(ERROR, "ResourceOwnerRemember called but array was full");
533  }
534 
535  /* Append to the array. */
536  idx = owner->narr;
537  owner->arr[idx].item = value;
538  owner->arr[idx].kind = kind;
539  owner->narr++;
540 }

References ResourceOwnerData::arr, Assert, elog, ERROR, idx(), ResourceElem::item, ResourceElem::kind, ResourceOwnerData::narr, ResourceOwnerDesc::release_phase, ResourceOwnerDesc::release_priority, ResourceOwnerData::releasing, RESOWNER_ARRAY_SIZE, ResourceOwnerData::sorted, and value.

Referenced by RememberManyTestResources(), ResourceOwnerRememberBuffer(), ResourceOwnerRememberBufferIO(), ResourceOwnerRememberCatCacheListRef(), ResourceOwnerRememberCatCacheRef(), ResourceOwnerRememberCryptoHash(), ResourceOwnerRememberDSM(), ResourceOwnerRememberFile(), ResourceOwnerRememberHMAC(), ResourceOwnerRememberJIT(), ResourceOwnerRememberOSSLCipher(), ResourceOwnerRememberOSSLDigest(), ResourceOwnerRememberPlanCacheRef(), ResourceOwnerRememberRelationRef(), ResourceOwnerRememberSnapshot(), ResourceOwnerRememberTupleDesc(), ResourceOwnerRememberWaitEventSet(), test_resowner_forget_between_phases(), test_resowner_leak(), test_resowner_priorities(), and test_resowner_remember_between_phases().

◆ ResourceOwnerRememberLock()

void ResourceOwnerRememberLock ( ResourceOwner  owner,
LOCALLOCK locallock 
)

Definition at line 1045 of file resowner.c.

1046 {
1047  Assert(locallock != NULL);
1048 
1049  if (owner->nlocks > MAX_RESOWNER_LOCKS)
1050  return; /* we have already overflowed */
1051 
1052  if (owner->nlocks < MAX_RESOWNER_LOCKS)
1053  owner->locks[owner->nlocks] = locallock;
1054  else
1055  {
1056  /* overflowed */
1057  }
1058  owner->nlocks++;
1059 }

References Assert, ResourceOwnerData::locks, MAX_RESOWNER_LOCKS, and ResourceOwnerData::nlocks.

Referenced by GrantLockLocal(), and LockReassignOwner().

◆ ResourceOwnerSort()

static void ResourceOwnerSort ( ResourceOwner  owner)
static

Definition at line 284 of file resowner.c.

285 {
287  uint32 nitems;
288 
289  if (owner->nhash == 0)
290  {
291  items = owner->arr;
292  nitems = owner->narr;
293  }
294  else
295  {
296  /*
297  * Compact the hash table, so that all the elements are in the
298  * beginning of the 'hash' array, with no empty elements.
299  */
300  uint32 dst = 0;
301 
302  for (int idx = 0; idx < owner->capacity; idx++)
303  {
304  if (owner->hash[idx].kind != NULL)
305  {
306  if (dst != idx)
307  owner->hash[dst] = owner->hash[idx];
308  dst++;
309  }
310  }
311 
312  /*
313  * Move all entries from the fixed-size array to 'hash'.
314  *
315  * RESOWNER_HASH_MAX_ITEMS is defined so that there is always enough
316  * free space to move all the elements from the fixed-size array to
317  * the hash.
318  */
319  Assert(dst + owner->narr <= owner->capacity);
320  for (int idx = 0; idx < owner->narr; idx++)
321  {
322  owner->hash[dst] = owner->arr[idx];
323  dst++;
324  }
325  Assert(dst == owner->nhash + owner->narr);
326  owner->narr = 0;
327  owner->nhash = dst;
328 
329  items = owner->hash;
330  nitems = owner->nhash;
331  }
332 
334 }
#define qsort(a, b, c, d)
Definition: port.h:447
static int resource_priority_cmp(const void *a, const void *b)
Definition: resowner.c:261

References ResourceOwnerData::arr, Assert, ResourceOwnerData::capacity, ResourceOwnerData::hash, idx(), items, ResourceElem::kind, ResourceOwnerData::narr, ResourceOwnerData::nhash, nitems, qsort, and resource_priority_cmp().

Referenced by ResourceOwnerReleaseInternal().

◆ StaticAssertDecl()

StaticAssertDecl ( RESOWNER_HASH_MAX_ITEMS(RESOWNER_HASH_INIT_SIZE) >=  RESOWNER_ARRAY_SIZE,
"initial hash size too small compared to array size  
)

◆ UnregisterResourceReleaseCallback()

void UnregisterResourceReleaseCallback ( ResourceReleaseCallback  callback,
void *  arg 
)

Definition at line 958 of file resowner.c.

959 {
962 
963  prev = NULL;
964  for (item = ResourceRelease_callbacks; item; prev = item, item = item->next)
965  {
966  if (item->callback == callback && item->arg == arg)
967  {
968  if (prev)
969  prev->next = item->next;
970  else
972  pfree(item);
973  break;
974  }
975  }
976 }

References ResourceReleaseCallbackItem::arg, arg, ResourceReleaseCallbackItem::callback, callback(), ResourceReleaseCallbackItem::next, pfree(), and ResourceRelease_callbacks.

Variable Documentation

◆ AuxProcessResourceOwner

◆ CurrentResourceOwner

ResourceOwner CurrentResourceOwner = NULL

Definition at line 165 of file resowner.c.

Referenced by _SPI_execute_plan(), apply_spooled_messages(), AssignTransactionId(), AtAbort_ResourceOwner(), AtStart_ResourceOwner(), AtSubAbort_ResourceOwner(), AtSubStart_ResourceOwner(), attach_internal(), BufferAlloc(), CleanupSubTransaction(), CleanupTransaction(), close_lo_relation(), CommitSubTransaction(), CommitTransaction(), create_internal(), CreateAuxProcessResourceOwner(), DecrTupleDescRefCount(), dsm_create_descriptor(), dsm_unpin_mapping(), EvictUnpinnedBuffer(), exec_eval_simple_expr(), exec_init_tuple_store(), exec_simple_check_plan(), exec_stmt_block(), ExecAppendAsyncEventWait(), ExplainExecuteQuery(), ExtendBufferedRelLocal(), ExtendBufferedRelShared(), extendBufFile(), FlushDatabaseBuffers(), FlushRelationBuffers(), FlushRelationsAllBuffers(), get_segment_by_index(), GetCurrentFDWTuplestore(), GetLocalVictimBuffer(), GetVictimBuffer(), IncrBufferRefCount(), IncrTupleDescRefCount(), InitPostgres(), llvm_create_context(), LocalBufferAlloc(), lock_and_open_sequence(), LockAcquireExtended(), LockReassignCurrentOwner(), LockReassignOwner(), LockRelease(), LogicalSlotAdvanceAndCheckSnapState(), make_callstmt_target(), make_new_segment(), makeBufFileCommon(), MakeTransitionCaptureState(), open_lo_relation(), OpenTemporaryFile(), PathNameCreateTemporaryFile(), PathNameOpenTemporaryFile(), perform_base_backup(), PersistHoldablePortal(), pg_cryptohash_create(), pg_hmac_create(), pg_logical_slot_get_changes_guts(), PinBuffer(), PinBuffer_Locked(), PinLocalBuffer(), plperl_spi_exec(), plperl_spi_exec_prepared(), plperl_spi_fetchrow(), plperl_spi_prepare(), plperl_spi_query(), plperl_spi_query_prepared(), plpgsql_estate_setup(), pltcl_func_handler(), pltcl_init_tuple_store(), pltcl_returnnext(), pltcl_SPI_execute(), pltcl_SPI_execute_plan(), pltcl_SPI_prepare(), pltcl_subtrans_abort(), pltcl_subtrans_commit(), pltcl_subtransaction(), PLy_abort_open_subtransactions(), PLy_cursor_fetch(), PLy_cursor_iternext(), PLy_cursor_plan(), PLy_cursor_query(), PLy_spi_execute_plan(), PLy_spi_execute_query(), PLy_spi_prepare(), PLy_spi_subtransaction_abort(), PLy_spi_subtransaction_commit(), PLy_subtransaction_enter(), PLy_subtransaction_exit(), PopTransaction(), PortalCleanup(), PortalRun(), PortalRunFetch(), PortalStart(), PrepareTransaction(), px_find_cipher(), px_find_digest(), ReadRecentBuffer(), RegisterSnapshot(), RegisterTemporaryFile(), RelationDecrementReferenceCount(), RelationIncrementReferenceCount(), ReleaseCatCache(), ReleaseCatCacheList(), ReleaseCatCacheListWithOwner(), ReleaseCatCacheWithOwner(), ReleaseLockIfHeld(), ResourceOwnerDelete(), ResourceOwnerReleaseInternal(), SearchCatCacheInternal(), SearchCatCacheList(), SearchCatCacheMiss(), ShutdownXLOG(), SnapBuildClearExportedSnapshot(), SnapBuildExportSnapshot(), SPI_plan_get_cached_plan(), StartBufferIO(), StartupXLOG(), SyncOneBuffer(), TerminateBufferIO(), test_dsa_resowners(), test_resowner_forget_between_phases(), test_resowner_leak(), test_resowner_many(), test_resowner_priorities(), test_resowner_remember_between_phases(), tuplestore_begin_common(), tuplestore_puttuple_common(), UnpinBuffer(), UnpinLocalBuffer(), UnregisterSnapshot(), UploadManifest(), and WaitLatchOrSocket().

◆ CurTransactionResourceOwner

◆ ResourceRelease_callbacks

ResourceReleaseCallbackItem* ResourceRelease_callbacks = NULL
static

◆ TopTransactionResourceOwner