Age Owner Branch data TLA 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 : :
851 heikki.linnakangas@i 22 :CBC 1 : PG_MODULE_MAGIC;
23 : :
24 : : static void
90 nathan@postgresql.or 25 :GNC 1 : init_tranche(void *ptr, void *arg)
26 : : {
123 27 : 1 : int *tranche_id = (int *) ptr;
28 : :
29 : 1 : *tranche_id = LWLockNewTrancheId("test_dsa");
30 : 1 : }
31 : :
32 : : /* Test basic DSA functionality */
851 heikki.linnakangas@i 33 :CBC 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 : :
123 nathan@postgresql.or 42 :GNC 1 : tranche_id = GetNamedDSMSegment("test_dsa", sizeof(int),
43 : : init_tranche, &found, NULL);
44 : :
45 : 1 : a = dsa_create(*tranche_id);
851 heikki.linnakangas@i 46 [ + + ]:CBC 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)
851 heikki.linnakangas@i 58 [ # # ]:UBC 0 : elog(ERROR, "no match");
59 : : }
60 : :
851 heikki.linnakangas@i 61 [ + + ]:CBC 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 : :
123 nathan@postgresql.or 83 :GNC 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 : : */
851 heikki.linnakangas@i 93 :CBC 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 : : */
6 michael@paquier.xyz 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)
6 michael@paquier.xyz 147 [ # # ]:UBC 0 : elog(ERROR, "incorrect start and end parameters");
148 : :
6 michael@paquier.xyz 149 :GNC 2 : tranche_id = GetNamedDSMSegment("test_dsa", sizeof(int),
150 : : init_tranche, &found, NULL);
151 : :
6 michael@paquier.xyz 152 [ + + ]:CBC 13 : for (usable_pages = start_num_pages; usable_pages < end_num_pages; usable_pages += step)
153 : : {
6 michael@paquier.xyz 154 :GNC 11 : a = dsa_create(*tranche_id);
6 michael@paquier.xyz 155 :CBC 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 : : }
|