Skip to content

Commit 3c1bb0e

Browse files
committed
PG-1444 Move relation key deleteion to smgr_unlink()
Replaces the old way we deleted keys which was built for tde_heap_basic with deleting the the relation key when smgr_unlink() is called on the main fork. This function is always called after commit/abort when a relation deletion has been registered, even if no main fork would exist. This approach means we do not need to WAL log any event for deleting relation keys, the normal SMGR unlink also handles that which fits well into the current approach of doing most of the encryption at the SMGR layer.
1 parent fa96fbe commit 3c1bb0e

File tree

8 files changed

+40
-285
lines changed

8 files changed

+40
-285
lines changed

Diff for: contrib/pg_tde/Makefile

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ src/encryption/enc_aes.o \
3333
src/access/pg_tde_tdemap.o \
3434
src/access/pg_tde_xlog.o \
3535
src/access/pg_tde_xlog_encrypt.o \
36-
src/transam/pg_tde_xact_handler.o \
3736
src/keyring/keyring_curl.o \
3837
src/keyring/keyring_file.o \
3938
src/keyring/keyring_vault.o \

Diff for: contrib/pg_tde/meson.build

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ pg_tde_sources = files(
2121
'src/pg_tde_event_capture.c',
2222
'src/pg_tde_guc.c',
2323
'src/smgr/pg_tde_smgr.c',
24-
'src/transam/pg_tde_xact_handler.c',
2524
)
2625

2726
tde_frontend_sources = files(

Diff for: contrib/pg_tde/src/access/pg_tde_tdemap.c

+16-75
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include "postgres.h"
1414
#include "access/pg_tde_tdemap.h"
1515
#include "common/file_perm.h"
16-
#include "transam/pg_tde_xact_handler.h"
1716
#include "storage/fd.h"
1817
#include "utils/wait_event.h"
1918
#include "utils/memutils.h"
@@ -129,7 +128,6 @@ static int pg_tde_file_header_write(const char *tde_filename, int fd, const TDES
129128
static void pg_tde_sign_principal_key_info(TDESignedPrincipalKeyInfo *signed_key_info, const TDEPrincipalKey *principal_key);
130129
static off_t pg_tde_write_one_map_entry(int fd, const TDEMapEntry *map_entry, off_t *offset, const char *db_map_path);
131130
static void pg_tde_write_key_map_entry(const RelFileLocator *rlocator, InternalKey *rel_key_data, TDEPrincipalKey *principal_key, bool write_xlog);
132-
static bool pg_tde_delete_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_t offset);
133131
static int keyrotation_init_file(const TDESignedPrincipalKeyInfo *signed_key_info, char *rotated_filename, const char *filename, off_t *curr_pos);
134132
static void finalize_key_rotation(const char *path_old, const char *path_new);
135133
static int pg_tde_open_file_write(const char *tde_filename, const TDESignedPrincipalKeyInfo *signed_key_info, bool truncate, off_t *curr_pos);
@@ -486,9 +484,6 @@ pg_tde_write_key_map_entry(const RelFileLocator *rlocator, InternalKey *rel_key_
486484

487485
/* Let's close the file. */
488486
close(map_fd);
489-
490-
/* Register the entry to be freed in case the transaction aborts */
491-
RegisterEntryForDeletion(rlocator, curr_pos, false);
492487
}
493488

494489
/*
@@ -548,51 +543,40 @@ pg_tde_write_key_map_entry_redo(const TDEMapEntry *write_map_entry, TDESignedPri
548543
LWLockRelease(tde_lwlock_enc_keys());
549544
}
550545

551-
static bool
552-
pg_tde_delete_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_t offset)
546+
/*
547+
* Mark relation map entry as free and overwrite the key
548+
*
549+
* This fucntion is called by the pg_tde SMGR when storage is unlinked on
550+
* transaction commit/abort.
551+
*/
552+
void
553+
pg_tde_free_key_map_entry(const RelFileLocator *rlocator)
553554
{
555+
char db_map_path[MAXPGPATH];
554556
File map_fd;
555-
bool found = false;
556557
off_t curr_pos = 0;
557558

558-
/* Open and validate file for basic correctness. */
559-
map_fd = pg_tde_open_file_write(db_map_path, NULL, false, &curr_pos);
559+
Assert(rlocator);
560560

561-
/*
562-
* If we need to delete an entry, we expect an offset value to the start
563-
* of the entry to speed up the operation. Otherwise, we'd be sequentially
564-
* scanning the entire map file.
565-
*/
566-
if (offset > 0)
567-
{
568-
curr_pos = lseek(map_fd, offset, SEEK_SET);
561+
pg_tde_set_db_file_path(rlocator->dbOid, db_map_path);
569562

570-
if (curr_pos == -1)
571-
{
572-
ereport(ERROR,
573-
errcode_for_file_access(),
574-
errmsg("could not seek in tde map file \"%s\": %m",
575-
db_map_path));
576-
}
577-
}
563+
LWLockAcquire(tde_lwlock_enc_keys(), LW_EXCLUSIVE);
564+
565+
/* Open and validate file for basic correctness. */
566+
map_fd = pg_tde_open_file_write(db_map_path, NULL, false, &curr_pos);
578567

579-
/*
580-
* Read until we find an empty slot. Otherwise, read until end. This seems
581-
* to be less frequent than vacuum. So let's keep this function here
582-
* rather than overloading the vacuum process.
583-
*/
584568
while (1)
585569
{
586570
TDEMapEntry read_map_entry;
587571
off_t prev_pos = curr_pos;
572+
bool found;
588573

589574
found = pg_tde_read_one_map_entry(map_fd, rlocator, MAP_ENTRY_VALID, &read_map_entry, &curr_pos);
590575

591576
/* We've reached EOF */
592577
if (curr_pos == prev_pos)
593578
break;
594579

595-
/* We found a valid entry for the relation */
596580
if (found)
597581
{
598582
TDEMapEntry empty_map_entry = {
@@ -607,52 +591,9 @@ pg_tde_delete_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_t
607591
}
608592
}
609593

610-
/* Let's close the file. */
611594
close(map_fd);
612595

613-
/* Return -1 indicating that no entry was removed */
614-
return found;
615-
}
616-
617-
/*
618-
* Called when transaction is being completed; either committed or aborted.
619-
* By default, when a transaction creates an entry, we mark it as MAP_ENTRY_VALID.
620-
* Only during the abort phase of the transaction that we are proceed on with
621-
* marking the entry as MAP_ENTRY_FREE. This optimistic strategy that assumes
622-
* that transaction will commit more often then getting aborted avoids
623-
* unnecessary locking.
624-
*
625-
* The offset allows us to simply seek to the desired location and mark the entry
626-
* as MAP_ENTRY_FREE without needing any further processing.
627-
*/
628-
void
629-
pg_tde_free_key_map_entry(const RelFileLocator *rlocator, off_t offset)
630-
{
631-
bool found;
632-
char db_map_path[MAXPGPATH] = {0};
633-
634-
Assert(rlocator);
635-
636-
/* Get the file paths */
637-
pg_tde_set_db_file_path(rlocator->dbOid, db_map_path);
638-
639-
LWLockAcquire(tde_lwlock_enc_keys(), LW_EXCLUSIVE);
640-
641-
/* Remove the map entry if found */
642-
found = pg_tde_delete_map_entry(rlocator, db_map_path, offset);
643-
644596
LWLockRelease(tde_lwlock_enc_keys());
645-
646-
if (!found)
647-
{
648-
ereport(WARNING,
649-
errcode(ERRCODE_NO_DATA_FOUND),
650-
errmsg("could not find the required map entry for deletion of relation %d in tablespace %d in tde map file \"%s\": %m",
651-
rlocator->relNumber,
652-
rlocator->spcOid,
653-
db_map_path));
654-
655-
}
656597
}
657598

658599
/*

Diff for: contrib/pg_tde/src/include/access/pg_tde_tdemap.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ extern void pg_tde_wal_last_key_set_lsn(XLogRecPtr lsn, const char *keyfile_path
101101

102102
extern InternalKey *pg_tde_create_smgr_key(const RelFileLocatorBackend *newrlocator);
103103
extern void pg_tde_create_wal_key(InternalKey *rel_key_data, const RelFileLocator *newrlocator, uint32 flags);
104-
extern void pg_tde_free_key_map_entry(const RelFileLocator *rlocator, off_t offset);
104+
extern void pg_tde_free_key_map_entry(const RelFileLocator *rlocator);
105105
extern void pg_tde_write_key_map_entry_redo(const TDEMapEntry *write_map_entry, TDESignedPrincipalKeyInfo *signed_key_info);
106106

107107
#define PG_TDE_MAP_FILENAME "pg_tde_%d_map"

Diff for: contrib/pg_tde/src/include/transam/pg_tde_xact_handler.h

-18
This file was deleted.

Diff for: contrib/pg_tde/src/pg_tde.c

-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include "postgres.h"
1414
#include "funcapi.h"
1515
#include "pg_tde.h"
16-
#include "transam/pg_tde_xact_handler.h"
1716
#include "miscadmin.h"
1817
#include "storage/ipc.h"
1918
#include "storage/lwlock.h"
@@ -121,7 +120,6 @@ _PG_init(void)
121120
prev_shmem_startup_hook = shmem_startup_hook;
122121
shmem_startup_hook = tde_shmem_startup;
123122

124-
RegisterTdeXactCallbacks();
125123
InstallFileKeyring();
126124
InstallVaultV2Keyring();
127125
InstallKmipKeyring();

Diff for: contrib/pg_tde/src/smgr/pg_tde_smgr.c

+23-1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,28 @@ tde_mdwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
115115
}
116116
}
117117

118+
static void
119+
tde_mdunlink(RelFileLocatorBackend rlocator, ForkNumber forknum, bool isRedo)
120+
{
121+
mdunlink(rlocator, forknum, isRedo);
122+
123+
/*
124+
* As of PostgreSQL 17 we are only ever called once for all forks, no
125+
* matter if they exist or not, from smgrdounlinkall() so deleting the
126+
* relation key on attempting to delete the init fork is safe.
127+
* Additionally since we unlink the files after commit/abort we do not
128+
* need to care about current accesses.
129+
*
130+
* We support InvalidForkNumber to be similar to mdunlink() but it can
131+
* actually never happen.
132+
*/
133+
if (forknum == INIT_FORKNUM || forknum == InvalidForkNumber)
134+
{
135+
if (!RelFileLocatorBackendIsTemp(rlocator) && GetSMGRRelationKey(rlocator))
136+
pg_tde_free_key_map_entry(&rlocator.locator);
137+
}
138+
}
139+
118140
static void
119141
tde_mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
120142
const void *buffer, bool skipFsync)
@@ -274,7 +296,7 @@ static const struct f_smgr tde_smgr = {
274296
.smgr_close = mdclose,
275297
.smgr_create = tde_mdcreate,
276298
.smgr_exists = mdexists,
277-
.smgr_unlink = mdunlink,
299+
.smgr_unlink = tde_mdunlink,
278300
.smgr_extend = tde_mdextend,
279301
.smgr_zeroextend = mdzeroextend,
280302
.smgr_prefetch = mdprefetch,

0 commit comments

Comments
 (0)