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-2025, 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 "utils/resowner.h"
17
19
20static void ReleaseString(Datum res);
21static char *PrintString(Datum res);
22
23/*
24 * A resource that tracks strings and prints the string when it's released.
25 * This makes the order that the resources are released visible.
26 */
28 .name = "test resource",
29 .release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
30 .release_priority = RELEASE_PRIO_FIRST,
31 .ReleaseResource = ReleaseString,
32 .DebugPrint = PrintString
33};
34
35static void
37{
38 elog(NOTICE, "releasing string: %s", DatumGetPointer(res));
39}
40
41static char *
43{
44 return psprintf("test string \"%s\"", DatumGetPointer(res));
45}
46
47/* demonstrates phases and priorities between a parent and child context */
51{
52 int32 nkinds = PG_GETARG_INT32(0);
53 int32 nresources = PG_GETARG_INT32(1);
54 ResourceOwner parent,
55 child;
56 ResourceOwnerDesc *before_desc;
57 ResourceOwnerDesc *after_desc;
58
59 if (nkinds <= 0)
60 elog(ERROR, "nkinds must be greater than zero");
61 if (nresources <= 0)
62 elog(ERROR, "nresources must be greater than zero");
63
64 parent = ResourceOwnerCreate(CurrentResourceOwner, "test parent");
65 child = ResourceOwnerCreate(parent, "test child");
66
67 before_desc = palloc(nkinds * sizeof(ResourceOwnerDesc));
68 for (int i = 0; i < nkinds; i++)
69 {
70 before_desc[i].name = psprintf("test resource before locks %d", i);
72 before_desc[i].release_priority = RELEASE_PRIO_FIRST + i;
73 before_desc[i].ReleaseResource = ReleaseString;
74 before_desc[i].DebugPrint = PrintString;
75 }
76 after_desc = palloc(nkinds * sizeof(ResourceOwnerDesc));
77 for (int i = 0; i < nkinds; i++)
78 {
79 after_desc[i].name = psprintf("test resource after locks %d", i);
81 after_desc[i].release_priority = RELEASE_PRIO_FIRST + i;
82 after_desc[i].ReleaseResource = ReleaseString;
83 after_desc[i].DebugPrint = PrintString;
84 }
85
86 /* Add a bunch of resources to child, with different priorities */
87 for (int i = 0; i < nresources; i++)
88 {
89 ResourceOwnerDesc *kind = &before_desc[i % nkinds];
90
93 CStringGetDatum(psprintf("child before locks priority %d", kind->release_priority)),
94 kind);
95 }
96 for (int i = 0; i < nresources; i++)
97 {
98 ResourceOwnerDesc *kind = &after_desc[i % nkinds];
99
102 CStringGetDatum(psprintf("child after locks priority %d", kind->release_priority)),
103 kind);
104 }
105
106 /* And also to the parent */
107 for (int i = 0; i < nresources; i++)
108 {
109 ResourceOwnerDesc *kind = &after_desc[i % nkinds];
110
111 ResourceOwnerEnlarge(parent);
113 CStringGetDatum(psprintf("parent after locks priority %d", kind->release_priority)),
114 kind);
115 }
116 for (int i = 0; i < nresources; i++)
117 {
118 ResourceOwnerDesc *kind = &before_desc[i % nkinds];
119
120 ResourceOwnerEnlarge(parent);
122 CStringGetDatum(psprintf("parent before locks priority %d", kind->release_priority)),
123 kind);
124 }
125
126 elog(NOTICE, "releasing resources before locks");
128 elog(NOTICE, "releasing locks");
129 ResourceOwnerRelease(parent, RESOURCE_RELEASE_LOCKS, false, false);
130 elog(NOTICE, "releasing resources after locks");
132
133 ResourceOwnerDelete(parent);
134
136}
137
139Datum
141{
142 ResourceOwner resowner;
143
144 resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");
145
146 ResourceOwnerEnlarge(resowner);
147
148 ResourceOwnerRemember(resowner, CStringGetDatum("my string"), &string_desc);
149
150 /* don't call ResourceOwnerForget, so that it is leaked */
151
153 ResourceOwnerRelease(resowner, RESOURCE_RELEASE_LOCKS, true, false);
155
156 ResourceOwnerDelete(resowner);
157
159}
160
162Datum
164{
165 ResourceOwner resowner;
166
167 resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");
168
170
171 /*
172 * Try to remember a new resource. Fails because we already called
173 * ResourceOwnerRelease.
174 */
175 ResourceOwnerEnlarge(resowner);
176 ResourceOwnerRemember(resowner, CStringGetDatum("my string"), &string_desc);
177
178 /* unreachable */
179 elog(ERROR, "ResourceOwnerEnlarge should have errored out");
180
182}
183
185Datum
187{
188 ResourceOwner resowner;
189 Datum str_resource;
190
191 resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");
192
193 ResourceOwnerEnlarge(resowner);
194 str_resource = CStringGetDatum("my string");
195 ResourceOwnerRemember(resowner, str_resource, &string_desc);
196
198
199 /*
200 * Try to forget the resource that was remembered earlier. Fails because
201 * we already called ResourceOwnerRelease.
202 */
203 ResourceOwnerForget(resowner, str_resource, &string_desc);
204
205 /* unreachable */
206 elog(ERROR, "ResourceOwnerForget should have errored out");
207
209}
int32_t int32
Definition: c.h:498
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#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:74
void * palloc(Size size)
Definition: mcxt.c:1317
uintptr_t Datum
Definition: postgres.h:69
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:355
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:421
ResourceOwner CurrentResourceOwner
Definition: resowner.c:173
void ResourceOwnerRelease(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition: resowner.c:658
void ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:564
void ResourceOwnerDelete(ResourceOwner owner)
Definition: resowner.c:871
void ResourceOwnerRemember(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:524
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition: resowner.c:452
@ 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)