Age Owner Branch data TLA Line data Source code
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 : :
668 heikki.linnakangas@i 18 :CBC 1 : PG_MODULE_MAGIC;
19 : :
20 : : static void ReleaseString(Datum res);
21 : : static 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 : : */
27 : : static const ResourceOwnerDesc string_desc = {
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 : :
35 : : static void
36 : 142 : ReleaseString(Datum res)
37 : : {
38 [ + + ]: 142 : elog(NOTICE, "releasing string: %s", DatumGetPointer(res));
39 : 142 : }
40 : :
41 : : static char *
42 : 1 : PrintString(Datum res)
43 : : {
44 : 1 : return psprintf("test string \"%s\"", DatumGetPointer(res));
45 : : }
46 : :
47 : : /* demonstrates phases and priorities between a parent and child context */
48 : 2 : PG_FUNCTION_INFO_V1(test_resowner_priorities);
49 : : Datum
50 : 2 : test_resowner_priorities(PG_FUNCTION_ARGS)
51 : : {
52 : 2 : int32 nkinds = PG_GETARG_INT32(0);
53 : 2 : int32 nresources = PG_GETARG_INT32(1);
54 : : ResourceOwner parent,
55 : : child;
56 : : ResourceOwnerDesc *before_desc;
57 : : ResourceOwnerDesc *after_desc;
58 : :
59 [ - + ]: 2 : if (nkinds <= 0)
668 heikki.linnakangas@i 60 [ # # ]:UBC 0 : elog(ERROR, "nkinds must be greater than zero");
668 heikki.linnakangas@i 61 [ - + ]:CBC 2 : if (nresources <= 0)
668 heikki.linnakangas@i 62 [ # # ]:UBC 0 : elog(ERROR, "nresources must be greater than zero");
63 : :
668 heikki.linnakangas@i 64 :CBC 2 : parent = ResourceOwnerCreate(CurrentResourceOwner, "test parent");
65 : 2 : child = ResourceOwnerCreate(parent, "test child");
66 : :
67 : 2 : before_desc = palloc(nkinds * sizeof(ResourceOwnerDesc));
68 [ + + ]: 6 : for (int i = 0; i < nkinds; i++)
69 : : {
70 : 4 : before_desc[i].name = psprintf("test resource before locks %d", i);
71 : 4 : before_desc[i].release_phase = RESOURCE_RELEASE_BEFORE_LOCKS;
72 : 4 : before_desc[i].release_priority = RELEASE_PRIO_FIRST + i;
73 : 4 : before_desc[i].ReleaseResource = ReleaseString;
74 : 4 : before_desc[i].DebugPrint = PrintString;
75 : : }
76 : 2 : after_desc = palloc(nkinds * sizeof(ResourceOwnerDesc));
77 [ + + ]: 6 : for (int i = 0; i < nkinds; i++)
78 : : {
79 : 4 : after_desc[i].name = psprintf("test resource after locks %d", i);
80 : 4 : after_desc[i].release_phase = RESOURCE_RELEASE_AFTER_LOCKS;
81 : 4 : after_desc[i].release_priority = RELEASE_PRIO_FIRST + i;
82 : 4 : after_desc[i].ReleaseResource = ReleaseString;
83 : 4 : after_desc[i].DebugPrint = PrintString;
84 : : }
85 : :
86 : : /* Add a bunch of resources to child, with different priorities */
87 [ + + ]: 37 : for (int i = 0; i < nresources; i++)
88 : : {
89 : 35 : ResourceOwnerDesc *kind = &before_desc[i % nkinds];
90 : :
91 : 35 : ResourceOwnerEnlarge(child);
92 : 35 : ResourceOwnerRemember(child,
93 : 35 : CStringGetDatum(psprintf("child before locks priority %d", kind->release_priority)),
94 : : kind);
95 : : }
96 [ + + ]: 37 : for (int i = 0; i < nresources; i++)
97 : : {
98 : 35 : ResourceOwnerDesc *kind = &after_desc[i % nkinds];
99 : :
100 : 35 : ResourceOwnerEnlarge(child);
101 : 35 : ResourceOwnerRemember(child,
102 : 35 : CStringGetDatum(psprintf("child after locks priority %d", kind->release_priority)),
103 : : kind);
104 : : }
105 : :
106 : : /* And also to the parent */
107 [ + + ]: 37 : for (int i = 0; i < nresources; i++)
108 : : {
109 : 35 : ResourceOwnerDesc *kind = &after_desc[i % nkinds];
110 : :
111 : 35 : ResourceOwnerEnlarge(parent);
112 : 35 : ResourceOwnerRemember(parent,
113 : 35 : CStringGetDatum(psprintf("parent after locks priority %d", kind->release_priority)),
114 : : kind);
115 : : }
116 [ + + ]: 37 : for (int i = 0; i < nresources; i++)
117 : : {
118 : 35 : ResourceOwnerDesc *kind = &before_desc[i % nkinds];
119 : :
120 : 35 : ResourceOwnerEnlarge(parent);
121 : 35 : ResourceOwnerRemember(parent,
122 : 35 : CStringGetDatum(psprintf("parent before locks priority %d", kind->release_priority)),
123 : : kind);
124 : : }
125 : :
126 [ + - ]: 2 : elog(NOTICE, "releasing resources before locks");
127 : 2 : ResourceOwnerRelease(parent, RESOURCE_RELEASE_BEFORE_LOCKS, false, false);
128 [ + - ]: 2 : elog(NOTICE, "releasing locks");
129 : 2 : ResourceOwnerRelease(parent, RESOURCE_RELEASE_LOCKS, false, false);
130 [ + - ]: 2 : elog(NOTICE, "releasing resources after locks");
131 : 2 : ResourceOwnerRelease(parent, RESOURCE_RELEASE_AFTER_LOCKS, false, false);
132 : :
133 : 2 : ResourceOwnerDelete(parent);
134 : :
135 : 2 : PG_RETURN_VOID();
136 : : }
137 : :
138 : 2 : PG_FUNCTION_INFO_V1(test_resowner_leak);
139 : : Datum
140 : 1 : test_resowner_leak(PG_FUNCTION_ARGS)
141 : : {
142 : : ResourceOwner resowner;
143 : :
144 : 1 : resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");
145 : :
146 : 1 : ResourceOwnerEnlarge(resowner);
147 : :
148 : 1 : ResourceOwnerRemember(resowner, CStringGetDatum("my string"), &string_desc);
149 : :
150 : : /* don't call ResourceOwnerForget, so that it is leaked */
151 : :
152 : 1 : ResourceOwnerRelease(resowner, RESOURCE_RELEASE_BEFORE_LOCKS, true, false);
153 : 1 : ResourceOwnerRelease(resowner, RESOURCE_RELEASE_LOCKS, true, false);
154 : 1 : ResourceOwnerRelease(resowner, RESOURCE_RELEASE_AFTER_LOCKS, true, false);
155 : :
156 : 1 : ResourceOwnerDelete(resowner);
157 : :
158 : 1 : PG_RETURN_VOID();
159 : : }
160 : :
161 : 2 : PG_FUNCTION_INFO_V1(test_resowner_remember_between_phases);
162 : : Datum
163 : 1 : test_resowner_remember_between_phases(PG_FUNCTION_ARGS)
164 : : {
165 : : ResourceOwner resowner;
166 : :
167 : 1 : resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");
168 : :
169 : 1 : ResourceOwnerRelease(resowner, RESOURCE_RELEASE_BEFORE_LOCKS, true, false);
170 : :
171 : : /*
172 : : * Try to remember a new resource. Fails because we already called
173 : : * ResourceOwnerRelease.
174 : : */
175 : 1 : ResourceOwnerEnlarge(resowner);
668 heikki.linnakangas@i 176 :UBC 0 : ResourceOwnerRemember(resowner, CStringGetDatum("my string"), &string_desc);
177 : :
178 : : /* unreachable */
179 [ # # ]: 0 : elog(ERROR, "ResourceOwnerEnlarge should have errored out");
180 : :
181 : : PG_RETURN_VOID();
182 : : }
183 : :
668 heikki.linnakangas@i 184 :CBC 2 : PG_FUNCTION_INFO_V1(test_resowner_forget_between_phases);
185 : : Datum
186 : 1 : test_resowner_forget_between_phases(PG_FUNCTION_ARGS)
187 : : {
188 : : ResourceOwner resowner;
189 : : Datum str_resource;
190 : :
191 : 1 : resowner = ResourceOwnerCreate(CurrentResourceOwner, "TestOwner");
192 : :
193 : 1 : ResourceOwnerEnlarge(resowner);
194 : 1 : str_resource = CStringGetDatum("my string");
195 : 1 : ResourceOwnerRemember(resowner, str_resource, &string_desc);
196 : :
197 : 1 : ResourceOwnerRelease(resowner, RESOURCE_RELEASE_BEFORE_LOCKS, true, false);
198 : :
199 : : /*
200 : : * Try to forget the resource that was remembered earlier. Fails because
201 : : * we already called ResourceOwnerRelease.
202 : : */
203 : 1 : ResourceOwnerForget(resowner, str_resource, &string_desc);
204 : :
205 : : /* unreachable */
668 heikki.linnakangas@i 206 [ # # ]:UBC 0 : elog(ERROR, "ResourceOwnerForget should have errored out");
207 : :
208 : : PG_RETURN_VOID();
209 : : }
|