mirror of https://github.com/postgres/postgres
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. We also remove the subtransaction test which is no longer useful since it tested things very specific to the old key deleteion.pull/220/head
parent
ec51d0895a
commit
a6f774e57e
@ -1,30 +0,0 @@ |
||||
CREATE EXTENSION IF NOT EXISTS pg_tde; |
||||
SELECT pg_tde_add_database_key_provider_file('file-vault','/tmp/pg_tde_test_keyring.per'); |
||||
pg_tde_add_database_key_provider_file |
||||
--------------------------------------- |
||||
1 |
||||
(1 row) |
||||
|
||||
SELECT pg_tde_set_key_using_database_key_provider('test-db-key','file-vault'); |
||||
pg_tde_set_key_using_database_key_provider |
||||
-------------------------------------------- |
||||
|
||||
(1 row) |
||||
|
||||
BEGIN; -- Nesting level 1 |
||||
SAVEPOINT sp; |
||||
CREATE TABLE foo(s TEXT); -- Nesting level 2 |
||||
RELEASE SAVEPOINT sp; |
||||
SAVEPOINT sp; |
||||
CREATE TABLE bar(s TEXT); -- Nesting level 2 |
||||
ROLLBACK TO sp; -- Rollback should not affect first subtransaction |
||||
COMMIT; |
||||
BEGIN; -- Nesting level 1 |
||||
SAVEPOINT sp; |
||||
DROP TABLE foo; -- Nesting level 2 |
||||
RELEASE SAVEPOINT sp; |
||||
SAVEPOINT sp; |
||||
CREATE TABLE bar(s TEXT); -- Nesting level 2 |
||||
ROLLBACK TO sp; -- Rollback should not affect first subtransaction |
||||
COMMIT; |
||||
DROP EXTENSION pg_tde; |
@ -1,25 +0,0 @@ |
||||
CREATE EXTENSION IF NOT EXISTS pg_tde; |
||||
|
||||
SELECT pg_tde_add_database_key_provider_file('file-vault','/tmp/pg_tde_test_keyring.per'); |
||||
SELECT pg_tde_set_key_using_database_key_provider('test-db-key','file-vault'); |
||||
|
||||
|
||||
BEGIN; -- Nesting level 1 |
||||
SAVEPOINT sp; |
||||
CREATE TABLE foo(s TEXT); -- Nesting level 2 |
||||
RELEASE SAVEPOINT sp; |
||||
SAVEPOINT sp; |
||||
CREATE TABLE bar(s TEXT); -- Nesting level 2 |
||||
ROLLBACK TO sp; -- Rollback should not affect first subtransaction |
||||
COMMIT; |
||||
|
||||
BEGIN; -- Nesting level 1 |
||||
SAVEPOINT sp; |
||||
DROP TABLE foo; -- Nesting level 2 |
||||
RELEASE SAVEPOINT sp; |
||||
SAVEPOINT sp; |
||||
CREATE TABLE bar(s TEXT); -- Nesting level 2 |
||||
ROLLBACK TO sp; -- Rollback should not affect first subtransaction |
||||
COMMIT; |
||||
|
||||
DROP EXTENSION pg_tde; |
@ -1,18 +0,0 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pg_tde_xact_handler.h |
||||
* TDE transaction handling. |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
#ifndef PG_TDE_XACT_HANDLER_H |
||||
#define PG_TDE_XACT_HANDLER_H |
||||
|
||||
#include "postgres.h" |
||||
#include "storage/relfilelocator.h" |
||||
|
||||
extern void RegisterTdeXactCallbacks(void); |
||||
extern void RegisterEntryForDeletion(const RelFileLocator *rlocator, off_t map_entry_offset, bool atCommit); |
||||
|
||||
|
||||
#endif /* PG_TDE_XACT_HANDLER_H */ |
@ -1,186 +0,0 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pg_tde_xact_handler.c |
||||
* Transaction handling routines for pg_tde |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* src/transam/pg_tde_xact_handler.c |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#include "postgres.h" |
||||
#include "access/xact.h" |
||||
#include "utils/memutils.h" |
||||
#include "utils/palloc.h" |
||||
#include "utils/elog.h" |
||||
#include "storage/fd.h" |
||||
#include "transam/pg_tde_xact_handler.h" |
||||
#include "access/pg_tde_tdemap.h" |
||||
|
||||
typedef struct PendingMapEntryDelete |
||||
{ |
||||
off_t map_entry_offset; /* map entry offset */ |
||||
RelFileLocator rlocator; /* main for use as relation OID */ |
||||
bool atCommit; /* T=delete at commit; F=delete at abort */ |
||||
int nestLevel; /* xact nesting level of request */ |
||||
struct PendingMapEntryDelete *next; /* linked-list link */ |
||||
} PendingMapEntryDelete; |
||||
|
||||
static PendingMapEntryDelete *pendingDeletes = NULL; /* head of linked list */ |
||||
|
||||
static void do_pending_deletes(bool isCommit); |
||||
static void reassign_pending_deletes_to_parent_xact(void); |
||||
static void pending_delete_cleanup(void); |
||||
|
||||
/* Transaction Callbacks from Backend*/ |
||||
static void |
||||
pg_tde_xact_callback(XactEvent event, void *arg) |
||||
{ |
||||
if (event == XACT_EVENT_PARALLEL_ABORT || |
||||
event == XACT_EVENT_ABORT) |
||||
{ |
||||
ereport(DEBUG2, errmsg("pg_tde_xact_callback: aborting transaction")); |
||||
do_pending_deletes(false); |
||||
} |
||||
else if (event == XACT_EVENT_COMMIT) |
||||
{ |
||||
do_pending_deletes(true); |
||||
pending_delete_cleanup(); |
||||
} |
||||
else if (event == XACT_EVENT_PREPARE) |
||||
{ |
||||
pending_delete_cleanup(); |
||||
} |
||||
} |
||||
|
||||
static void |
||||
pg_tde_subxact_callback(SubXactEvent event, SubTransactionId mySubid, |
||||
SubTransactionId parentSubid, void *arg) |
||||
{ |
||||
/* TODO: takle all possible transaction states */ |
||||
if (event == SUBXACT_EVENT_ABORT_SUB) |
||||
{ |
||||
ereport(DEBUG2, |
||||
errmsg("pg_tde_subxact_callback: aborting subtransaction")); |
||||
do_pending_deletes(false); |
||||
} |
||||
else if (event == SUBXACT_EVENT_COMMIT_SUB) |
||||
{ |
||||
ereport(DEBUG2, |
||||
errmsg("pg_tde_subxact_callback: committing subtransaction")); |
||||
reassign_pending_deletes_to_parent_xact(); |
||||
} |
||||
} |
||||
|
||||
void |
||||
RegisterTdeXactCallbacks(void) |
||||
{ |
||||
RegisterXactCallback(pg_tde_xact_callback, NULL); |
||||
RegisterSubXactCallback(pg_tde_subxact_callback, NULL); |
||||
} |
||||
|
||||
void |
||||
RegisterEntryForDeletion(const RelFileLocator *rlocator, off_t map_entry_offset, bool atCommit) |
||||
{ |
||||
PendingMapEntryDelete *pending; |
||||
|
||||
pending = (PendingMapEntryDelete *) MemoryContextAlloc(TopMemoryContext, sizeof(PendingMapEntryDelete)); |
||||
pending->map_entry_offset = map_entry_offset; |
||||
pending->rlocator = *rlocator; |
||||
pending->atCommit = atCommit; /* delete if abort */ |
||||
pending->nestLevel = GetCurrentTransactionNestLevel(); |
||||
pending->next = pendingDeletes; |
||||
pendingDeletes = pending; |
||||
} |
||||
|
||||
/*
|
||||
* do_pending_deletes() -- Take care of file deletes at end of xact. |
||||
* |
||||
* This also runs when aborting a subxact; we want to clean up a failed |
||||
* subxact immediately. |
||||
* |
||||
*/ |
||||
static void |
||||
do_pending_deletes(bool isCommit) |
||||
{ |
||||
int nestLevel = GetCurrentTransactionNestLevel(); |
||||
PendingMapEntryDelete *pending; |
||||
PendingMapEntryDelete *prev; |
||||
PendingMapEntryDelete *next; |
||||
|
||||
prev = NULL; |
||||
for (pending = pendingDeletes; pending != NULL; pending = next) |
||||
{ |
||||
next = pending->next; |
||||
if (pending->nestLevel != nestLevel) |
||||
{ |
||||
/* outer-level entries should not be processed yet */ |
||||
prev = pending; |
||||
continue; |
||||
} |
||||
|
||||
/* unlink list entry first, so we don't retry on failure */ |
||||
if (prev) |
||||
prev->next = next; |
||||
else |
||||
pendingDeletes = next; |
||||
/* do deletion if called for */ |
||||
if (pending->atCommit == isCommit) |
||||
{ |
||||
ereport(LOG, |
||||
errmsg("pg_tde_xact_callback: deleting entry at offset %d", |
||||
(int) (pending->map_entry_offset))); |
||||
pg_tde_free_key_map_entry(&pending->rlocator, pending->map_entry_offset); |
||||
} |
||||
pfree(pending); |
||||
/* prev does not change */ |
||||
|
||||
} |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* reassign_pending_deletes_to_parent_xact() -- Adjust nesting level of pending deletes. |
||||
* |
||||
* There are several cases to consider: |
||||
* 1. Only top level transaction can perform on-commit deletes. |
||||
* 2. Subtransaction and top level transaction can perform on-abort deletes. |
||||
* So we have to decrement the nesting level of pending deletes to reassing them to the parent transaction |
||||
* if subtransaction was not self aborted. In other words if subtransaction state is commited all its pending |
||||
* deletes are reassigned to the parent transaction. |
||||
*/ |
||||
static void |
||||
reassign_pending_deletes_to_parent_xact(void) |
||||
{ |
||||
PendingMapEntryDelete *pending; |
||||
int nestLevel = GetCurrentTransactionNestLevel(); |
||||
|
||||
for (pending = pendingDeletes; pending != NULL; pending = pending->next) |
||||
{ |
||||
if (pending->nestLevel == nestLevel) |
||||
pending->nestLevel--; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* pending_delete_cleanup -- Clean up after a successful PREPARE or COMMIT |
||||
* |
||||
* What we have to do here is throw away the in-memory state about pending |
||||
* file deletes. It's all been recorded in the 2PC state file and |
||||
* it's no longer our job to worry about it. |
||||
*/ |
||||
static void |
||||
pending_delete_cleanup(void) |
||||
{ |
||||
PendingMapEntryDelete *pending; |
||||
PendingMapEntryDelete *next; |
||||
|
||||
for (pending = pendingDeletes; pending != NULL; pending = next) |
||||
{ |
||||
next = pending->next; |
||||
pendingDeletes = next; |
||||
pfree(pending); |
||||
} |
||||
} |
Loading…
Reference in new issue