@@ -72,6 +72,7 @@ static void pg_tde_sign_principal_key_info(TDESignedPrincipalKeyInfo *signed_key
7272static void pg_tde_write_one_map_entry (int fd , const TDEMapEntry * map_entry , off_t * offset , const char * db_map_path );
7373static int keyrotation_init_file (const TDESignedPrincipalKeyInfo * signed_key_info , char * rotated_filename , const char * filename , off_t * curr_pos );
7474static void finalize_key_rotation (const char * path_old , const char * path_new );
75+ static void pg_tde_replace_key_map_entry (const RelFileLocator * rlocator , const InternalKey * rel_key_data , TDEPrincipalKey * principal_key );
7576
7677void
7778pg_tde_save_smgr_key (RelFileLocator rel , const InternalKey * rel_key_data )
@@ -88,7 +89,7 @@ pg_tde_save_smgr_key(RelFileLocator rel, const InternalKey *rel_key_data)
8889 errhint ("Use pg_tde_set_key_using_database_key_provider() or pg_tde_set_key_using_global_key_provider() to configure one." ));
8990 }
9091
91- pg_tde_write_key_map_entry (& rel , rel_key_data , principal_key );
92+ pg_tde_replace_key_map_entry (& rel , rel_key_data , principal_key );
9293 LWLockRelease (lock_pk );
9394}
9495
@@ -362,6 +363,65 @@ pg_tde_delete_principal_key(Oid dbOid)
362363 durable_unlink (path , ERROR );
363364}
364365
366+ /*
367+ * The caller must hold an exclusive lock on the key file to avoid
368+ * concurrent in place updates leading to data conflicts.
369+ */
370+ void
371+ pg_tde_replace_key_map_entry (const RelFileLocator * rlocator , const InternalKey * rel_key_data , TDEPrincipalKey * principal_key )
372+ {
373+ char db_map_path [MAXPGPATH ];
374+ int map_fd ;
375+ off_t curr_pos = 0 ;
376+ off_t write_pos = 0 ;
377+ TDEMapEntry write_map_entry ;
378+ TDESignedPrincipalKeyInfo signed_key_Info ;
379+
380+ Assert (rlocator );
381+
382+ pg_tde_set_db_file_path (rlocator -> dbOid , db_map_path );
383+
384+ pg_tde_sign_principal_key_info (& signed_key_Info , principal_key );
385+
386+ /* Open and validate file for basic correctness. */
387+ map_fd = pg_tde_open_file_write (db_map_path , & signed_key_Info , false, & curr_pos );
388+
389+ /*
390+ * Read until we find an empty slot. Otherwise, read until end. This seems
391+ * to be less frequent than vacuum. So let's keep this function here
392+ * rather than overloading the vacuum process.
393+ */
394+ while (1 )
395+ {
396+ TDEMapEntry read_map_entry ;
397+ off_t prev_pos = curr_pos ;
398+
399+ if (!pg_tde_read_one_map_entry (map_fd , & read_map_entry , & curr_pos ))
400+ {
401+ if (write_pos == 0 )
402+ write_pos = prev_pos ;
403+ break ;
404+ }
405+
406+ if (read_map_entry .spcOid == rlocator -> spcOid && read_map_entry .relNumber == rlocator -> relNumber )
407+ {
408+ write_pos = prev_pos ;
409+ break ;
410+ }
411+
412+ if (write_pos == 0 && read_map_entry .type == MAP_ENTRY_EMPTY )
413+ write_pos = prev_pos ;
414+ }
415+
416+ /* Initialize map entry and encrypt key */
417+ pg_tde_initialize_map_entry (& write_map_entry , principal_key , rlocator , rel_key_data );
418+
419+ /* Write the given entry at curr_pos; i.e. the free entry. */
420+ pg_tde_write_one_map_entry (map_fd , & write_map_entry , & write_pos , db_map_path );
421+
422+ CloseTransientFile (map_fd );
423+ }
424+
365425#endif /* !FRONTEND */
366426
367427/*
0 commit comments