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