Skip to content

Commit 11271a1

Browse files
committed
Applied patch
1 parent 087cf92 commit 11271a1

File tree

14 files changed

+551
-133
lines changed

14 files changed

+551
-133
lines changed

contrib/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ SUBDIRS = \
1919
dict_int \
2020
dict_xsyn \
2121
earthdistance \
22+
fsync_checker \
2223
file_fdw \
2324
fuzzystrmatch \
2425
hstore \
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# fsync_checker extension
2+
comment = 'SMGR extension for checking volatile writes'
3+
default_version = '1.0'
4+
module_pathname = '$libdir/fsync_checker'
5+
relocatable = true
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
#include "postgres.h"
2+
3+
#include "access/xlog.h"
4+
#include "fmgr.h"
5+
#include "miscadmin.h"
6+
#include "storage/ipc.h"
7+
#include "storage/lwlock.h"
8+
#include "storage/shmem.h"
9+
#include "storage/smgr.h"
10+
#include "storage/md.h"
11+
#include "utils/hsearch.h"
12+
13+
PG_MODULE_MAGIC;
14+
15+
typedef struct volatileRelnKey
16+
{
17+
RelFileLocator locator;
18+
ForkNumber forknum;
19+
} volatileRelnKey;
20+
21+
typedef struct volatileRelnEntry
22+
{
23+
volatileRelnKey key;
24+
XLogRecPtr lsn;
25+
} volatileRelnEntry;
26+
27+
void _PG_init(void);
28+
29+
static void fsync_checker_extend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
30+
const void *buffer, bool skipFsync);
31+
static void fsync_checker_immedsync(SMgrRelation reln, ForkNumber forknum);
32+
static void fsync_checker_writev(SMgrRelation reln, ForkNumber forknum,
33+
BlockNumber blocknum, const void **buffers,
34+
BlockNumber nblocks, bool skipFsync);
35+
static void fsync_checker_writeback(SMgrRelation reln, ForkNumber forknum,
36+
BlockNumber blocknum, BlockNumber nblocks);
37+
static void fsync_checker_zeroextend(SMgrRelation reln, ForkNumber forknum,
38+
BlockNumber blocknum, int nblocks, bool skipFsync);
39+
40+
static void fsync_checker_checkpoint_create(const CheckPoint *checkPoint);
41+
static void fsync_checker_shmem_request(void);
42+
static void fsync_checker_shmem_startup(void);
43+
44+
static void add_reln(SMgrRelation reln, ForkNumber forknum);
45+
static void remove_reln(SMgrRelation reln, ForkNumber forknum);
46+
47+
static SMgrId fsync_checker_smgr_id;
48+
static const struct f_smgr fsync_checker_smgr = {
49+
.name = "fsync_checker",
50+
.smgr_init = mdinit,
51+
.smgr_shutdown = NULL,
52+
.smgr_open = mdopen,
53+
.smgr_close = mdclose,
54+
.smgr_create = mdcreate,
55+
.smgr_exists = mdexists,
56+
.smgr_unlink = mdunlink,
57+
.smgr_extend = fsync_checker_extend,
58+
.smgr_zeroextend = fsync_checker_zeroextend,
59+
.smgr_prefetch = mdprefetch,
60+
.smgr_readv = mdreadv,
61+
.smgr_writev = fsync_checker_writev,
62+
.smgr_writeback = fsync_checker_writeback,
63+
.smgr_nblocks = mdnblocks,
64+
.smgr_truncate = mdtruncate,
65+
.smgr_immedsync = fsync_checker_immedsync,
66+
.smgr_registersync = mdregistersync,
67+
};
68+
69+
static HTAB *volatile_relns;
70+
static LWLock *volatile_relns_lock;
71+
static shmem_request_hook_type prev_shmem_request_hook;
72+
static shmem_startup_hook_type prev_shmem_startup_hook;
73+
static checkpoint_create_hook_type prev_checkpoint_create_hook;
74+
75+
void
76+
_PG_init(void)
77+
{
78+
prev_checkpoint_create_hook = checkpoint_create_hook;
79+
checkpoint_create_hook = fsync_checker_checkpoint_create;
80+
81+
prev_shmem_request_hook = shmem_request_hook;
82+
shmem_request_hook = fsync_checker_shmem_request;
83+
84+
prev_shmem_startup_hook = shmem_startup_hook;
85+
shmem_startup_hook = fsync_checker_shmem_startup;
86+
87+
/*
88+
* Relation size of 0 means we can just defer to md, but it would be nice
89+
* to just expose this functionality, so if I needed my own relation, I
90+
* could use MdSmgrRelation as the parent.
91+
*/
92+
fsync_checker_smgr_id = smgr_register(&fsync_checker_smgr, 0);
93+
94+
storage_manager_id = fsync_checker_smgr_id;
95+
}
96+
97+
static void
98+
fsync_checker_checkpoint_create(const CheckPoint *checkPoint)
99+
{
100+
long num_entries;
101+
HASH_SEQ_STATUS status;
102+
volatileRelnEntry *entry;
103+
104+
if (prev_checkpoint_create_hook)
105+
prev_checkpoint_create_hook(checkPoint);
106+
107+
LWLockAcquire(volatile_relns_lock, LW_EXCLUSIVE);
108+
109+
hash_seq_init(&status, volatile_relns);
110+
111+
num_entries = hash_get_num_entries(volatile_relns);
112+
elog(INFO, "Analyzing %ld volatile relations", num_entries);
113+
while ((entry = hash_seq_search(&status)))
114+
{
115+
if (entry->lsn < checkPoint->redo)
116+
{
117+
char *path;
118+
119+
path = relpathperm(entry->key.locator, entry->key.forknum);
120+
121+
elog(WARNING, "Relation not previously synced: %s", path);
122+
123+
pfree(path);
124+
}
125+
}
126+
127+
LWLockRelease(volatile_relns_lock);
128+
}
129+
130+
static void
131+
fsync_checker_shmem_request(void)
132+
{
133+
if (prev_shmem_request_hook)
134+
prev_shmem_request_hook();
135+
136+
RequestAddinShmemSpace(hash_estimate_size(1024, sizeof(volatileRelnEntry)));
137+
RequestNamedLWLockTranche("fsync_checker volatile relns lock", 1);
138+
}
139+
140+
static void
141+
fsync_checker_shmem_startup(void)
142+
{
143+
HASHCTL ctl;
144+
145+
if (prev_shmem_startup_hook)
146+
prev_shmem_startup_hook();
147+
148+
ctl.keysize = sizeof(volatileRelnKey);
149+
ctl.entrysize = sizeof(volatileRelnEntry);
150+
volatile_relns = NULL;
151+
volatile_relns_lock = NULL;
152+
153+
/*
154+
* Create or attach to the shared memory state, including hash table
155+
*/
156+
LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
157+
158+
volatile_relns = ShmemInitHash("fsync_checker volatile relns",
159+
1024, 1024, &ctl, HASH_BLOBS | HASH_ELEM);
160+
volatile_relns_lock = &GetNamedLWLockTranche("fsync_checker volatile relns lock")->lock;
161+
162+
LWLockRelease(AddinShmemInitLock);
163+
}
164+
165+
static void
166+
add_reln(SMgrRelation reln, ForkNumber forknum)
167+
{
168+
bool found;
169+
XLogRecPtr lsn;
170+
volatileRelnKey key;
171+
volatileRelnEntry *entry;
172+
173+
key.locator = reln->smgr_rlocator.locator;
174+
key.forknum = forknum;
175+
176+
lsn = GetXLogWriteRecPtr();
177+
178+
LWLockAcquire(volatile_relns_lock, LW_EXCLUSIVE);
179+
180+
entry = hash_search(volatile_relns, &key, HASH_ENTER, &found);
181+
if (!found)
182+
entry->lsn = lsn;
183+
184+
LWLockRelease(volatile_relns_lock);
185+
}
186+
187+
static void
188+
remove_reln(SMgrRelation reln, ForkNumber forknum)
189+
{
190+
volatileRelnKey key;
191+
192+
key.locator = reln->smgr_rlocator.locator;
193+
key.forknum = forknum;
194+
195+
LWLockAcquire(volatile_relns_lock, LW_EXCLUSIVE);
196+
197+
hash_search(volatile_relns, &key, HASH_REMOVE, NULL);
198+
199+
LWLockRelease(volatile_relns_lock);
200+
}
201+
202+
static void
203+
fsync_checker_extend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
204+
const void *buffer, bool skipFsync)
205+
{
206+
if (!SmgrIsTemp(reln) && !skipFsync)
207+
add_reln(reln, forknum);
208+
209+
mdextend(reln, forknum, blocknum, buffer, skipFsync);
210+
}
211+
212+
static void
213+
fsync_checker_immedsync(SMgrRelation reln, ForkNumber forknum)
214+
{
215+
if (!SmgrIsTemp(reln))
216+
remove_reln(reln, forknum);
217+
218+
mdimmedsync(reln, forknum);
219+
}
220+
221+
static void
222+
fsync_checker_writev(SMgrRelation reln, ForkNumber forknum,
223+
BlockNumber blocknum, const void **buffers,
224+
BlockNumber nblocks, bool skipFsync)
225+
{
226+
if (!SmgrIsTemp(reln) && !skipFsync)
227+
add_reln(reln, forknum);
228+
229+
mdwritev(reln, forknum, blocknum, buffers, nblocks, skipFsync);
230+
}
231+
232+
static void
233+
fsync_checker_writeback(SMgrRelation reln, ForkNumber forknum,
234+
BlockNumber blocknum, BlockNumber nblocks)
235+
{
236+
if (!SmgrIsTemp(reln))
237+
remove_reln(reln, forknum);
238+
239+
mdwriteback(reln, forknum, blocknum, nblocks);
240+
}
241+
242+
static void
243+
fsync_checker_zeroextend(SMgrRelation reln, ForkNumber forknum,
244+
BlockNumber blocknum, int nblocks, bool skipFsync)
245+
{
246+
if (!SmgrIsTemp(reln) && !skipFsync)
247+
add_reln(reln, forknum);
248+
249+
mdzeroextend(reln, forknum, blocknum, nblocks, skipFsync);
250+
}

contrib/fsync_checker/meson.build

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Copyright (c) 2023, PostgreSQL Global Development Group
2+
3+
fsync_checker_sources = files(
4+
'fsync_checker_smgr.c',
5+
)
6+
7+
if host_system == 'windows'
8+
fsync_checker_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
9+
'--NAME', 'fsync_checker',
10+
'--FILEDESC', 'fsync_checker - SMGR extension for checking volatile relations',])
11+
endif
12+
13+
fsync_checker = shared_module('fsync_checker',
14+
fsync_checker_sources,
15+
kwargs: contrib_mod_args,
16+
)
17+
contrib_targets += fsync_checker
18+
19+
install_data(
20+
'fsync_checker.control',
21+
kwargs: contrib_data_args,
22+
)

contrib/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ subdir('dict_int')
2828
subdir('dict_xsyn')
2929
subdir('earthdistance')
3030
subdir('file_fdw')
31+
subdir('fsync_checker')
3132
subdir('fuzzystrmatch')
3233
subdir('hstore')
3334
subdir('hstore_plperl')

src/backend/access/transam/xlog.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ const struct config_enum_entry archive_mode_options[] = {
209209
*/
210210
CheckpointStatsData CheckpointStats;
211211

212+
checkpoint_create_hook_type checkpoint_create_hook = NULL;
213+
212214
/*
213215
* During recovery, lastFullPageWrites keeps track of full_page_writes that
214216
* the replayed WAL records indicate. It's initialized with full_page_writes
@@ -7095,6 +7097,9 @@ CreateCheckPoint(int flags)
70957097
*/
70967098
END_CRIT_SECTION();
70977099

7100+
if (checkpoint_create_hook != NULL)
7101+
checkpoint_create_hook(&checkPoint);
7102+
70987103
/*
70997104
* In some cases there are groups of actions that must all occur on one
71007105
* side or the other of a checkpoint record. Before flushing the

src/backend/postmaster/postmaster.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,11 @@ PostmasterMain(int argc, char *argv[])
907907
*/
908908
ApplyLauncherRegister();
909909

910+
/*
911+
* Register built-in managers that are not part of static arrays
912+
*/
913+
register_builtin_dynamic_managers();
914+
910915
/*
911916
* process any libraries that should be preloaded at postmaster start
912917
*/

0 commit comments

Comments
 (0)