PostgreSQL Source Code  git master
test_resowner_basic.c
Go to the documentation of this file.
1 /*--------------------------------------------------------------------------
2  *
3  * test_resowner_basic.c
4  * Test basic ResourceOwner functionality
5  *
6  * Copyright (c) 2022-2024, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  * src/test/modules/test_resowner/test_resowner_basic.c
10  *
11  * -------------------------------------------------------------------------
12  */
13 #include "postgres.h"
14 
15 #include "fmgr.h"
16 #include "lib/ilist.h"
17 #include "utils/memutils.h"
18 #include "utils/resowner.h"
19 
21 
22 static void ReleaseString(Datum res);
23 static char *PrintString(Datum res);
24 
25 /*
26  * A resource that tracks strings and prints the string when it's released.
27  * This makes the order that the resources are released visible.
28  */
30  .name = "test resource",
31  .release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
32  .release_priority = RELEASE_PRIO_FIRST,
33  .ReleaseResource = ReleaseString,
34  .DebugPrint = PrintString
35 };
36 
37 static void
39 {
40  elog(NOTICE, "releasing string: %s", DatumGetPointer(res));
41 }
42 
43 static char *
45 {
46  return psprintf("test string \"%s\"", DatumGetPointer(res));
47 }
48 
49 /* demonstrates phases and priorities between a parent and child context */
51 Datum
53 {
54  int32 nkinds = PG_GETARG_INT32(0);
55  int32 nresources = PG_GETARG_INT32(1);
56  ResourceOwner parent,
57  child;
58  ResourceOwnerDesc *before_desc;
59  ResourceOwnerDesc *after_desc;
60 
61  if (nkinds <= 0)
62  elog(ERROR, "nkinds must be greater than zero");
63  if (nresources <= 0)
64  elog(ERROR, "nresources must be greater than zero");
65 
66  parent = ResourceOwnerCreate(CurrentResourceOwner, "test parent");
67  child = ResourceOwnerCreate(parent, "test child");
68 
69  before_desc = palloc(nkinds * sizeof(ResourceOwnerDesc));
70  for (int i = 0; i < nkinds; i++)
71  {
72  before_desc[i].name = psprintf("test resource before locks %d", i);
74  before_desc[i].release_priority = RELEASE_PRIO_FIRST + i;
75  before_desc[i].ReleaseResource = ReleaseString;
76  before_desc[i].DebugPrint = PrintString;
77  }
78  after_desc = palloc(nkinds * sizeof(ResourceOwnerDesc));
79  for (int i = 0; i < nkinds; i++)
80  {
81  after_desc[i].name = psprintf("test resource after locks %d", i);
83  after_desc[i].release_priority = RELEASE_PRIO_FIRST + i;
84  after_desc[i].ReleaseResource = ReleaseString;
85  after_desc[i].DebugPrint = PrintString;
86  }
87 
88  /* Add a bunch of resources to child, with different priorities */
89  for (int i = 0; i < nresources; i++)
90  {
91  ResourceOwnerDesc *kind = &before_desc[i % nkinds];
92 
93  ResourceOwnerEnlarge(child);
95  CStringGetDatum(psprintf("child before locks priority %d", kind->release_priority)),
96  kind);
97  }
98  for (int i = 0; i < nresources; i++)
99  {
100  ResourceOwnerDesc *kind = &after_desc[i % nkinds];
101 
102  ResourceOwnerEnlarge(child);
103  ResourceOwnerRemember(child,
104  CStringGetDatum(psprintf("child after locks priority %d", kind->release_priority)),
105  kind);
106  }
107 
108  /* And also to the parent */
109  for (int i = 0; i < nresources; i++)
110  {
111  ResourceOwnerDesc *kind = &after_desc[i % nkinds];
112 
113  ResourceOwnerEnlarge(parent);
114  ResourceOwnerRemember(parent,
115  CStringGetDatum(psprintf("parent after locks priority %d", kind->release_priority)),
116  kind);
117  }
118  for (int i = 0; i < nresources; i++)
119  {
120  ResourceOwnerDesc *kind = &before_desc[i % nkinds];
121 
122  ResourceOwnerEnlarge(parent);
123  ResourceOwnerRemember(parent,
124  CStringGetDatum(psprintf("parent before locks priority %d", kind->release_priority)),
125  kind);
126  }
127 
128  elog(NOTICE, "releasing resources before locks");
130  elog(NOTICE, "releasing locks");
131  ResourceOwnerRelease(parent, RESOURCE_RELEASE_LOCKS, false, false);
132  elog(NOTICE, "releasing resources after locks");
133  ResourceOwnerRelease(parent, RESOURCE_RELEASE_AFTER_LOCKS, false, false);
134 
135  ResourceOwnerDelete(parent);
136 
137  PG_RETURN_VOID();
138 }
139 
141 Datum
143 {
144  ResourceOwner resowner;
145 
146  resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");
147 
148  ResourceOwnerEnlarge(resowner);
149 
150  ResourceOwnerRemember(resowner, CStringGetDatum("my string"), &string_desc);
151 
152  /* don't call ResourceOwnerForget, so that it is leaked */
153 
154  ResourceOwnerRelease(resowner, RESOURCE_RELEASE_BEFORE_LOCKS, true, false);
155  ResourceOwnerRelease(resowner, RESOURCE_RELEASE_LOCKS, true, false);
156  ResourceOwnerRelease(resowner, RESOURCE_RELEASE_AFTER_LOCKS, true, false);
157 
158  ResourceOwnerDelete(resowner);
159 
160  PG_RETURN_VOID();
161 }
162 
164 Datum
166 {
167  ResourceOwner resowner;
168 
169  resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");
170 
171  ResourceOwnerRelease(resowner, RESOURCE_RELEASE_BEFORE_LOCKS, true, false);
172 
173  /*
174  * Try to remember a new resource. Fails because we already called
175  * ResourceOwnerRelease.
176  */
177  ResourceOwnerEnlarge(resowner);
178  ResourceOwnerRemember(resowner, CStringGetDatum("my string"), &string_desc);
179 
180  /* unreachable */
181  elog(ERROR, "ResourceOwnerEnlarge should have errored out");
182 
183  PG_RETURN_VOID();
184 }
185 
187 Datum
189 {
190  ResourceOwner resowner;
191  Datum str_resource;
192 
193  resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");
194 
195  ResourceOwnerEnlarge(resowner);
196  str_resource = CStringGetDatum("my string");
197  ResourceOwnerRemember(resowner, str_resource, &string_desc);
198 
199  ResourceOwnerRelease(resowner, RESOURCE_RELEASE_BEFORE_LOCKS, true, false);
200 
201  /*
202  * Try to forget the resource that was remembered earlier. Fails because
203  * we already called ResourceOwnerRelease.
204  */
205  ResourceOwnerForget(resowner, str_resource, &string_desc);
206 
207  /* unreachable */
208  elog(ERROR, "ResourceOwnerForget should have errored out");
209 
210  PG_RETURN_VOID();
211 }
signed int int32
Definition: c.h:494
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define NOTICE
Definition: elog.h:35
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
int i
Definition: isn.c:73
void * palloc(Size size)
Definition: mcxt.c:1316
uintptr_t Datum
Definition: postgres.h:64
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:413
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165
void ResourceOwnerRelease(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition: resowner.c:648
void ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:554
void ResourceOwnerDelete(ResourceOwner owner)
Definition: resowner.c:854
void ResourceOwnerRemember(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:514
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition: resowner.c:442
@ RESOURCE_RELEASE_LOCKS
Definition: resowner.h:55
@ RESOURCE_RELEASE_BEFORE_LOCKS
Definition: resowner.h:54
@ RESOURCE_RELEASE_AFTER_LOCKS
Definition: resowner.h:56
#define RELEASE_PRIO_FIRST
Definition: resowner.h:80
char *(* DebugPrint)(Datum res)
Definition: resowner.h:118
ResourceReleasePhase release_phase
Definition: resowner.h:96
void(* ReleaseResource)(Datum res)
Definition: resowner.h:108
ResourceReleasePriority release_priority
Definition: resowner.h:97
const char * name
Definition: resowner.h:93
static void ReleaseString(Datum res)
Datum test_resowner_forget_between_phases(PG_FUNCTION_ARGS)
PG_MODULE_MAGIC
static const ResourceOwnerDesc string_desc
Datum test_resowner_remember_between_phases(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(test_resowner_priorities)
Datum test_resowner_leak(PG_FUNCTION_ARGS)
static char * PrintString(Datum res)
Datum test_resowner_priorities(PG_FUNCTION_ARGS)