summaryrefslogtreecommitdiffstats
path: root/src/test/modules/test_slru/test_slru.c
blob: ae21444c47637103b3dc73fadc60a23d271ef7c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*--------------------------------------------------------------------------
 *
 * test_slru.c
 *		Test correctness of SLRU functions.
 *
 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *		src/test/modules/test_slru/test_slru.c
 *
 * -------------------------------------------------------------------------
 */

#include "postgres.h"

#include "access/slru.h"
#include "access/transam.h"
#include "miscadmin.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/shmem.h"
#include "utils/builtins.h"

PG_MODULE_MAGIC;

/*
 * SQL-callable entry points
 */
PG_FUNCTION_INFO_V1(test_slru_page_write);
PG_FUNCTION_INFO_V1(test_slru_page_writeall);
PG_FUNCTION_INFO_V1(test_slru_page_read);
PG_FUNCTION_INFO_V1(test_slru_page_readonly);
PG_FUNCTION_INFO_V1(test_slru_page_exists);
PG_FUNCTION_INFO_V1(test_slru_page_sync);
PG_FUNCTION_INFO_V1(test_slru_page_delete);
PG_FUNCTION_INFO_V1(test_slru_page_truncate);
PG_FUNCTION_INFO_V1(test_slru_delete_all);

/* Number of SLRU page slots */
#define NUM_TEST_BUFFERS		16

/* SLRU control lock */
LWLock		TestSLRULock;
#define TestSLRULock (&TestSLRULock)

static SlruCtlData TestSlruCtlData;
#define TestSlruCtl			(&TestSlruCtlData)

static shmem_request_hook_type prev_shmem_request_hook = NULL;
static shmem_startup_hook_type prev_shmem_startup_hook = NULL;

static bool
test_slru_scan_cb(SlruCtl ctl, char *filename, int segpage, void *data)
{
	elog(NOTICE, "Calling test_slru_scan_cb()");
	return SlruScanDirCbDeleteAll(ctl, filename, segpage, data);
}

Datum
test_slru_page_write(PG_FUNCTION_ARGS)
{
	int			pageno = PG_GETARG_INT32(0);
	char	   *data = text_to_cstring(PG_GETARG_TEXT_PP(1));
	int			slotno;

	LWLockAcquire(TestSLRULock, LW_EXCLUSIVE);

	slotno = SimpleLruZeroPage(TestSlruCtl, pageno);

	/* these should match */
	Assert(TestSlruCtl->shared->page_number[slotno] == pageno);

	/* mark the page as dirty so as it would get written */
	TestSlruCtl->shared->page_dirty[slotno] = true;
	TestSlruCtl->shared->page_status[slotno] = SLRU_PAGE_VALID;

	/* write given data to the page, up to the limit of the page */
	strncpy(TestSlruCtl->shared->page_buffer[slotno], data,
			BLCKSZ - 1);

	SimpleLruWritePage(TestSlruCtl, slotno);
	LWLockRelease(TestSLRULock);

	PG_RETURN_VOID();
}

Datum
test_slru_page_writeall(PG_FUNCTION_ARGS)
{
	SimpleLruWriteAll(TestSlruCtl, true);
	PG_RETURN_VOID();
}

Datum
test_slru_page_read(PG_FUNCTION_ARGS)
{
	int			pageno = PG_GETARG_INT32(0);
	bool		write_ok = PG_GETARG_BOOL(1);
	char	   *data = NULL;
	int			slotno;

	/* find page in buffers, reading it if necessary */
	LWLockAcquire(TestSLRULock, LW_EXCLUSIVE);
	slotno = SimpleLruReadPage(TestSlruCtl, pageno,
							   write_ok, InvalidTransactionId);
	data = (char *) TestSlruCtl->shared->page_buffer[slotno];
	LWLockRelease(TestSLRULock);

	PG_RETURN_TEXT_P(cstring_to_text(data));
}

Datum
test_slru_page_readonly(PG_FUNCTION_ARGS)
{
	int			pageno = PG_GETARG_INT32(0);
	char	   *data = NULL;
	int			slotno;

	/* find page in buffers, reading it if necessary */
	slotno = SimpleLruReadPage_ReadOnly(TestSlruCtl,
										pageno,
										InvalidTransactionId);
	Assert(LWLockHeldByMe(TestSLRULock));
	data = (char *) TestSlruCtl->shared->page_buffer[slotno];
	LWLockRelease(TestSLRULock);

	PG_RETURN_TEXT_P(cstring_to_text(data));
}

Datum
test_slru_page_exists(PG_FUNCTION_ARGS)
{
	int			pageno = PG_GETARG_INT32(0);
	bool		found;

	LWLockAcquire(TestSLRULock, LW_EXCLUSIVE);
	found = SimpleLruDoesPhysicalPageExist(TestSlruCtl, pageno);
	LWLockRelease(TestSLRULock);

	PG_RETURN_BOOL(found);
}

Datum
test_slru_page_sync(PG_FUNCTION_ARGS)
{
	int			pageno = PG_GETARG_INT32(0);
	FileTag		ftag;
	char		path[MAXPGPATH];

	/* note that this flushes the full file a segment is located in */
	ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT;
	SlruSyncFileTag(TestSlruCtl, &ftag, path);

	elog(NOTICE, "Called SlruSyncFileTag() for segment %u on path %s",
		 ftag.segno, path);

	PG_RETURN_VOID();
}

Datum
test_slru_page_delete(PG_FUNCTION_ARGS)
{
	int			pageno = PG_GETARG_INT32(0);
	FileTag		ftag;

	ftag.segno = pageno / SLRU_PAGES_PER_SEGMENT;
	SlruDeleteSegment(TestSlruCtl, ftag.segno);

	elog(NOTICE, "Called SlruDeleteSegment() for segment %u", ftag.segno);

	PG_RETURN_VOID();
}

Datum
test_slru_page_truncate(PG_FUNCTION_ARGS)
{
	int			pageno = PG_GETARG_INT32(0);

	SimpleLruTruncate(TestSlruCtl, pageno);
	PG_RETURN_VOID();
}

Datum
test_slru_delete_all(PG_FUNCTION_ARGS)
{
	/* this calls SlruScanDirCbDeleteAll() internally, ensuring deletion */
	SlruScanDirectory(TestSlruCtl, test_slru_scan_cb, NULL);

	PG_RETURN_VOID();
}

/*
 * Module load callbacks and initialization.
 */

static void
test_slru_shmem_request(void)
{
	if (prev_shmem_request_hook)
		prev_shmem_request_hook();

	/* reserve shared memory for the test SLRU */
	RequestAddinShmemSpace(SimpleLruShmemSize(NUM_TEST_BUFFERS, 0));
}

static bool
test_slru_page_precedes_logically(int page1, int page2)
{
	return page1 < page2;
}

static void
test_slru_shmem_startup(void)
{
	const char	slru_dir_name[] = "pg_test_slru";
	int			test_tranche_id;

	if (prev_shmem_startup_hook)
		prev_shmem_startup_hook();

	/*
	 * Create the SLRU directory if it does not exist yet, from the root of
	 * the data directory.
	 */
	(void) MakePGDirectory(slru_dir_name);

	/* initialize the SLRU facility */
	test_tranche_id = LWLockNewTrancheId();
	LWLockRegisterTranche(test_tranche_id, "test_slru_tranche");
	LWLockInitialize(TestSLRULock, test_tranche_id);

	TestSlruCtl->PagePrecedes = test_slru_page_precedes_logically;
	SimpleLruInit(TestSlruCtl, "TestSLRU",
				  NUM_TEST_BUFFERS, 0, TestSLRULock, slru_dir_name,
				  test_tranche_id, SYNC_HANDLER_NONE);
}

void
_PG_init(void)
{
	if (!process_shared_preload_libraries_in_progress)
		ereport(ERROR,
				(errmsg("cannot load \"%s\" after startup", "test_slru"),
				 errdetail("\"%s\" must be loaded with shared_preload_libraries.",
						   "test_slru")));

	prev_shmem_request_hook = shmem_request_hook;
	shmem_request_hook = test_slru_shmem_request;

	prev_shmem_startup_hook = shmem_startup_hook;
	shmem_startup_hook = test_slru_shmem_startup;
}