Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 77587b5

Browse files
author
Commitfest Bot
committed
[CF 5616] v4 - Extensible storage manager API
This branch was automatically generated by a robot using patches from an email thread registered at: https://commitfest.postgresql.org/patch/5616 The branch will be overwritten each time a new patch version is posted to the thread, and also periodically to check for bitrot caused by changes on the master branch. Patch(es): https://www.postgresql.org/message-id/3217233f-6a86-4792-a055-606134c82d15@proxel.se Author(s): Andreas Karlsson, Anastasia Lubennikova, Matthias van de Meent, Tristan Partin
2 parents 3943f5c + 2b043f1 commit 77587b5

File tree

28 files changed

+968
-257
lines changed

28 files changed

+968
-257
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: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
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
16+
{
17+
RelFileLocator locator;
18+
ForkNumber forknum;
19+
} VolatileRelnKey;
20+
21+
typedef struct
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, SmgrChainIndex chain_index);
31+
static void fsync_checker_immedsync(SMgrRelation reln, ForkNumber forknum, SmgrChainIndex chain_index);
32+
static void fsync_checker_writev(SMgrRelation reln, ForkNumber forknum,
33+
BlockNumber blocknum, const void **buffers,
34+
BlockNumber nblocks, bool skipFsync, SmgrChainIndex chain_index);
35+
static void fsync_checker_writeback(SMgrRelation reln, ForkNumber forknum,
36+
BlockNumber blocknum, BlockNumber nblocks, SmgrChainIndex chain_index);
37+
static void fsync_checker_zeroextend(SMgrRelation reln, ForkNumber forknum,
38+
BlockNumber blocknum, int nblocks, bool skipFsync, SmgrChainIndex chain_index);
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+
.chain_position = SMGR_CHAIN_MODIFIER,
51+
.smgr_init = NULL,
52+
.smgr_shutdown = NULL,
53+
.smgr_open = NULL,
54+
.smgr_close = NULL,
55+
.smgr_create = NULL,
56+
.smgr_exists = NULL,
57+
.smgr_unlink = NULL,
58+
.smgr_extend = fsync_checker_extend,
59+
.smgr_zeroextend = fsync_checker_zeroextend,
60+
.smgr_prefetch = NULL,
61+
.smgr_maxcombine = NULL,
62+
.smgr_readv = NULL,
63+
.smgr_writev = fsync_checker_writev,
64+
.smgr_writeback = fsync_checker_writeback,
65+
.smgr_nblocks = NULL,
66+
.smgr_truncate = NULL,
67+
.smgr_immedsync = fsync_checker_immedsync,
68+
.smgr_registersync = NULL,
69+
};
70+
71+
static HTAB *volatile_relns;
72+
static LWLock *volatile_relns_lock;
73+
static shmem_request_hook_type prev_shmem_request_hook;
74+
static shmem_startup_hook_type prev_shmem_startup_hook;
75+
static checkpoint_create_hook_type prev_checkpoint_create_hook;
76+
77+
void
78+
_PG_init(void)
79+
{
80+
prev_checkpoint_create_hook = checkpoint_create_hook;
81+
checkpoint_create_hook = fsync_checker_checkpoint_create;
82+
83+
prev_shmem_request_hook = shmem_request_hook;
84+
shmem_request_hook = fsync_checker_shmem_request;
85+
86+
prev_shmem_startup_hook = shmem_startup_hook;
87+
shmem_startup_hook = fsync_checker_shmem_startup;
88+
89+
/*
90+
* Relation size of 0 means we can just defer to md, but it would be nice
91+
* to just expose this functionality, so if I needed my own relation, I
92+
* could use MdSmgrRelation as the parent.
93+
*/
94+
fsync_checker_smgr_id = smgr_register(&fsync_checker_smgr, 0);
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+
RelPathStr path;
118+
119+
path = relpathperm(entry->key.locator, entry->key.forknum);
120+
121+
elog(WARNING, "Relation not previously synced: %s", path.str);
122+
}
123+
}
124+
125+
LWLockRelease(volatile_relns_lock);
126+
}
127+
128+
static void
129+
fsync_checker_shmem_request(void)
130+
{
131+
if (prev_shmem_request_hook)
132+
prev_shmem_request_hook();
133+
134+
RequestAddinShmemSpace(hash_estimate_size(1024, sizeof(VolatileRelnEntry)));
135+
RequestNamedLWLockTranche("fsync_checker volatile relns lock", 1);
136+
}
137+
138+
static void
139+
fsync_checker_shmem_startup(void)
140+
{
141+
HASHCTL ctl;
142+
143+
if (prev_shmem_startup_hook)
144+
prev_shmem_startup_hook();
145+
146+
ctl.keysize = sizeof(VolatileRelnKey);
147+
ctl.entrysize = sizeof(VolatileRelnEntry);
148+
volatile_relns = NULL;
149+
volatile_relns_lock = NULL;
150+
151+
/*
152+
* Create or attach to the shared memory state, including hash table
153+
*/
154+
LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
155+
156+
volatile_relns = ShmemInitHash("fsync_checker volatile relns",
157+
1024, 1024, &ctl, HASH_BLOBS | HASH_ELEM);
158+
volatile_relns_lock = &GetNamedLWLockTranche("fsync_checker volatile relns lock")->lock;
159+
160+
LWLockRelease(AddinShmemInitLock);
161+
}
162+
163+
static void
164+
add_reln(SMgrRelation reln, ForkNumber forknum)
165+
{
166+
bool found;
167+
XLogRecPtr lsn;
168+
VolatileRelnKey key;
169+
VolatileRelnEntry *entry;
170+
171+
key.locator = reln->smgr_rlocator.locator;
172+
key.forknum = forknum;
173+
174+
lsn = GetXLogWriteRecPtr();
175+
176+
LWLockAcquire(volatile_relns_lock, LW_EXCLUSIVE);
177+
178+
entry = hash_search(volatile_relns, &key, HASH_ENTER, &found);
179+
if (!found)
180+
entry->lsn = lsn;
181+
182+
LWLockRelease(volatile_relns_lock);
183+
}
184+
185+
static void
186+
remove_reln(SMgrRelation reln, ForkNumber forknum)
187+
{
188+
VolatileRelnKey key;
189+
190+
key.locator = reln->smgr_rlocator.locator;
191+
key.forknum = forknum;
192+
193+
LWLockAcquire(volatile_relns_lock, LW_EXCLUSIVE);
194+
195+
hash_search(volatile_relns, &key, HASH_REMOVE, NULL);
196+
197+
LWLockRelease(volatile_relns_lock);
198+
}
199+
200+
static void
201+
fsync_checker_extend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
202+
const void *buffer, bool skipFsync, SmgrChainIndex chain_index)
203+
{
204+
if (!SmgrIsTemp(reln) && !skipFsync)
205+
add_reln(reln, forknum);
206+
207+
smgr_extend_next(reln, forknum, blocknum, buffer, skipFsync, chain_index + 1);
208+
}
209+
210+
static void
211+
fsync_checker_immedsync(SMgrRelation reln, ForkNumber forknum, SmgrChainIndex chain_index)
212+
{
213+
if (!SmgrIsTemp(reln))
214+
remove_reln(reln, forknum);
215+
216+
smgr_immedsync_next(reln, forknum, chain_index + 1);
217+
}
218+
219+
static void
220+
fsync_checker_writev(SMgrRelation reln, ForkNumber forknum,
221+
BlockNumber blocknum, const void **buffers,
222+
BlockNumber nblocks, bool skipFsync, SmgrChainIndex chain_index)
223+
{
224+
if (!SmgrIsTemp(reln) && !skipFsync)
225+
add_reln(reln, forknum);
226+
227+
smgr_writev_next(reln, forknum, blocknum, buffers, nblocks, skipFsync, chain_index + 1);
228+
}
229+
230+
static void
231+
fsync_checker_writeback(SMgrRelation reln, ForkNumber forknum,
232+
BlockNumber blocknum, BlockNumber nblocks, SmgrChainIndex chain_index)
233+
{
234+
if (!SmgrIsTemp(reln))
235+
remove_reln(reln, forknum);
236+
237+
smgr_writeback_next(reln, forknum, blocknum, nblocks, chain_index + 1);
238+
}
239+
240+
static void
241+
fsync_checker_zeroextend(SMgrRelation reln, ForkNumber forknum,
242+
BlockNumber blocknum, int nblocks, bool skipFsync, SmgrChainIndex chain_index)
243+
{
244+
if (!SmgrIsTemp(reln) && !skipFsync)
245+
add_reln(reln, forknum);
246+
247+
smgr_zeroextend_next(reln, forknum, blocknum, nblocks, skipFsync, chain_index + 1);
248+
}

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/heap/heapam_handler.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,8 @@ heapam_relation_set_new_filelocator(Relation rel,
588588
{
589589
SMgrRelation srel;
590590

591+
RelFileLocator oldlocator = rel->rd_locator;
592+
591593
/*
592594
* Initialize to the minimum XID that could put tuples in the table. We
593595
* know that no xacts older than RecentXmin are still running, so that
@@ -605,7 +607,7 @@ heapam_relation_set_new_filelocator(Relation rel,
605607
*/
606608
*minmulti = GetOldestMultiXactId();
607609

608-
srel = RelationCreateStorage(*newrlocator, persistence, true);
610+
srel = RelationCreateStorage(oldlocator, *newrlocator, persistence, true);
609611

610612
/*
611613
* If required, set up an init fork for an unlogged table so that it can
@@ -615,7 +617,7 @@ heapam_relation_set_new_filelocator(Relation rel,
615617
{
616618
Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
617619
rel->rd_rel->relkind == RELKIND_TOASTVALUE);
618-
smgrcreate(srel, INIT_FORKNUM, false);
620+
smgrcreate(oldlocator, srel, INIT_FORKNUM, false);
619621
log_smgrcreate(newrlocator, INIT_FORKNUM);
620622
}
621623

@@ -648,7 +650,7 @@ heapam_relation_copy_data(Relation rel, const RelFileLocator *newrlocator)
648650
* NOTE: any conflict in relfilenumber value will be caught in
649651
* RelationCreateStorage().
650652
*/
651-
dstrel = RelationCreateStorage(*newrlocator, rel->rd_rel->relpersistence, true);
653+
dstrel = RelationCreateStorage(rel->rd_locator, *newrlocator, rel->rd_rel->relpersistence, true);
652654

653655
/* copy main fork */
654656
RelationCopyStorage(RelationGetSmgr(rel), dstrel, MAIN_FORKNUM,
@@ -660,7 +662,7 @@ heapam_relation_copy_data(Relation rel, const RelFileLocator *newrlocator)
660662
{
661663
if (smgrexists(RelationGetSmgr(rel), forkNum))
662664
{
663-
smgrcreate(dstrel, forkNum, false);
665+
smgrcreate(rel->rd_locator, dstrel, forkNum, false);
664666

665667
/*
666668
* WAL log creation if the relation is persistent, or this is the

src/backend/access/transam/xlog.c

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

211+
checkpoint_create_hook_type checkpoint_create_hook = NULL;
212+
211213
/*
212214
* During recovery, lastFullPageWrites keeps track of full_page_writes that
213215
* the replayed WAL records indicate. It's initialized with full_page_writes
@@ -7173,6 +7175,9 @@ CreateCheckPoint(int flags)
71737175
*/
71747176
END_CRIT_SECTION();
71757177

7178+
if (checkpoint_create_hook != NULL)
7179+
checkpoint_create_hook(&checkPoint);
7180+
71767181
/*
71777182
* In some cases there are groups of actions that must all occur on one
71787183
* side or the other of a checkpoint record. Before flushing the

src/backend/access/transam/xlogutils.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ XLogReadBufferExtended(RelFileLocator rlocator, ForkNumber forknum,
487487
* filesystem loses an inode during a crash. Better to write the data
488488
* until we are actually told to delete the file.)
489489
*/
490-
smgrcreate(smgr, forknum, true);
490+
smgrcreate(rlocator, smgr, forknum, true);
491491

492492
lastblock = smgrnblocks(smgr, forknum);
493493

src/backend/catalog/heap.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ heap_create(const char *relname,
386386
relpersistence,
387387
relfrozenxid, relminmxid);
388388
else if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
389-
RelationCreateStorage(rel->rd_locator, relpersistence, true);
389+
RelationCreateStorage(rel->rd_locator, rel->rd_locator, relpersistence, true);
390390
else
391391
Assert(false);
392392
}

src/backend/catalog/index.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3089,7 +3089,7 @@ index_build(Relation heapRelation,
30893089
if (indexRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
30903090
!smgrexists(RelationGetSmgr(indexRelation), INIT_FORKNUM))
30913091
{
3092-
smgrcreate(RelationGetSmgr(indexRelation), INIT_FORKNUM, false);
3092+
smgrcreate(indexRelation->rd_locator, RelationGetSmgr(indexRelation), INIT_FORKNUM, false);
30933093
log_smgrcreate(&indexRelation->rd_locator, INIT_FORKNUM);
30943094
indexRelation->rd_indam->ambuildempty(indexRelation);
30953095
}

0 commit comments

Comments
 (0)