Line data Source code
1 : /*--------------------------------------------------------------------------
2 : *
3 : * test_dsa.c
4 : * Test dynamic shared memory areas (DSAs)
5 : *
6 : * Copyright (c) 2022-2026, PostgreSQL Global Development Group
7 : *
8 : * IDENTIFICATION
9 : * src/test/modules/test_dsa/test_dsa.c
10 : *
11 : * -------------------------------------------------------------------------
12 : */
13 : #include "postgres.h"
14 :
15 : #include "fmgr.h"
16 : #include "storage/dsm_registry.h"
17 : #include "storage/lwlock.h"
18 : #include "utils/dsa.h"
19 : #include "utils/freepage.h"
20 : #include "utils/resowner.h"
21 :
22 1 : PG_MODULE_MAGIC;
23 :
24 : static void
25 1 : init_tranche(void *ptr, void *arg)
26 : {
27 1 : int *tranche_id = (int *) ptr;
28 :
29 1 : *tranche_id = LWLockNewTrancheId("test_dsa");
30 1 : }
31 :
32 : /* Test basic DSA functionality */
33 2 : PG_FUNCTION_INFO_V1(test_dsa_basic);
34 : Datum
35 1 : test_dsa_basic(PG_FUNCTION_ARGS)
36 : {
37 : int *tranche_id;
38 : bool found;
39 : dsa_area *a;
40 : dsa_pointer p[100];
41 :
42 1 : tranche_id = GetNamedDSMSegment("test_dsa", sizeof(int),
43 : init_tranche, &found, NULL);
44 :
45 1 : a = dsa_create(*tranche_id);
46 101 : for (int i = 0; i < 100; i++)
47 : {
48 100 : p[i] = dsa_allocate(a, 1000);
49 100 : snprintf(dsa_get_address(a, p[i]), 1000, "foobar%d", i);
50 : }
51 :
52 101 : for (int i = 0; i < 100; i++)
53 : {
54 : char buf[100];
55 :
56 100 : snprintf(buf, 100, "foobar%d", i);
57 100 : if (strcmp(dsa_get_address(a, p[i]), buf) != 0)
58 0 : elog(ERROR, "no match");
59 : }
60 :
61 101 : for (int i = 0; i < 100; i++)
62 : {
63 100 : dsa_free(a, p[i]);
64 : }
65 :
66 1 : dsa_detach(a);
67 :
68 1 : PG_RETURN_VOID();
69 : }
70 :
71 : /* Test using DSA across different resource owners */
72 2 : PG_FUNCTION_INFO_V1(test_dsa_resowners);
73 : Datum
74 1 : test_dsa_resowners(PG_FUNCTION_ARGS)
75 : {
76 : int *tranche_id;
77 : bool found;
78 : dsa_area *a;
79 : dsa_pointer p[10000];
80 : ResourceOwner oldowner;
81 : ResourceOwner childowner;
82 :
83 1 : tranche_id = GetNamedDSMSegment("test_dsa", sizeof(int),
84 : init_tranche, &found, NULL);
85 :
86 : /* Create DSA in parent resource owner */
87 1 : a = dsa_create(*tranche_id);
88 :
89 : /*
90 : * Switch to child resource owner, and do a bunch of allocations in the
91 : * DSA
92 : */
93 1 : oldowner = CurrentResourceOwner;
94 1 : childowner = ResourceOwnerCreate(oldowner, "test_dsa temp owner");
95 1 : CurrentResourceOwner = childowner;
96 :
97 10001 : for (int i = 0; i < 10000; i++)
98 : {
99 10000 : p[i] = dsa_allocate(a, 1000);
100 10000 : snprintf(dsa_get_address(a, p[i]), 1000, "foobar%d", i);
101 : }
102 :
103 : /* Also test freeing, by freeing some of the allocations. */
104 501 : for (int i = 0; i < 500; i++)
105 500 : dsa_free(a, p[i]);
106 :
107 : /* Release the child resource owner */
108 1 : CurrentResourceOwner = oldowner;
109 1 : ResourceOwnerRelease(childowner,
110 : RESOURCE_RELEASE_BEFORE_LOCKS,
111 : true, false);
112 1 : ResourceOwnerRelease(childowner,
113 : RESOURCE_RELEASE_LOCKS,
114 : true, false);
115 1 : ResourceOwnerRelease(childowner,
116 : RESOURCE_RELEASE_AFTER_LOCKS,
117 : true, false);
118 1 : ResourceOwnerDelete(childowner);
119 :
120 1 : dsa_detach(a);
121 :
122 1 : PG_RETURN_VOID();
123 : }
124 :
125 : /*
126 : * test_dsa_allocate
127 : *
128 : * Test DSA allocation across a range of sizes to exercise the pagemap
129 : * sizing logic in make_new_segment(). A fresh DSA is created for each
130 : * iteration so that each allocation triggers a new segment creation,
131 : * including the odd-sized segment path.
132 : */
133 2 : PG_FUNCTION_INFO_V1(test_dsa_allocate);
134 : Datum
135 2 : test_dsa_allocate(PG_FUNCTION_ARGS)
136 : {
137 2 : int start_num_pages = PG_GETARG_INT32(0);
138 2 : int end_num_pages = PG_GETARG_INT32(1);
139 2 : int step = PG_GETARG_INT32(2);
140 : size_t usable_pages;
141 : int *tranche_id;
142 : bool found;
143 : dsa_area *a;
144 : dsa_pointer dp;
145 :
146 2 : if (start_num_pages > end_num_pages)
147 0 : elog(ERROR, "incorrect start and end parameters");
148 :
149 2 : tranche_id = GetNamedDSMSegment("test_dsa", sizeof(int),
150 : init_tranche, &found, NULL);
151 :
152 13 : for (usable_pages = start_num_pages; usable_pages < end_num_pages; usable_pages += step)
153 : {
154 11 : a = dsa_create(*tranche_id);
155 11 : dp = dsa_allocate(a, usable_pages * FPM_PAGE_SIZE);
156 :
157 11 : dsa_free(a, dp);
158 11 : dsa_detach(a);
159 : }
160 :
161 2 : PG_RETURN_VOID();
162 : }
|