I wrote: > Andres Freund <andres@xxxxxxxxxxx> writes: >> Cool. And damn: I can't immediately think of a way to optimize this to >> not require this kind of hack in the future. > Maybe the same thing we do with user tables, ie not give up the lock > when we close a toast rel? As long as the internal lock counters > are 64-bit, we'd not have to worry about overflowing them. Like this? This passes check-world, modulo the one very-unsurprising regression test change. I've not tried to do any performance testing. regards, tom lane
diff --git a/src/backend/access/common/detoast.c b/src/backend/access/common/detoast.c index 545a6b8867..3826b4d93e 100644 --- a/src/backend/access/common/detoast.c +++ b/src/backend/access/common/detoast.c @@ -367,7 +367,7 @@ toast_fetch_datum(struct varlena *attr) * case. */ /* - * Open the toast relation and its indexes + * Open the toast relation (but its indexes are dealt with by the AM) */ toastrel = table_open(toast_pointer.va_toastrelid, AccessShareLock); @@ -376,7 +376,7 @@ toast_fetch_datum(struct varlena *attr) attrsize, 0, attrsize, result); /* Close toast table */ - table_close(toastrel, AccessShareLock); + table_close(toastrel, NoLock); return result; } @@ -457,7 +457,7 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset, result); /* Close toast table */ - table_close(toastrel, AccessShareLock); + table_close(toastrel, NoLock); return result; } diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c index 730cd04a2d..f0d0251ce0 100644 --- a/src/backend/access/common/toast_internals.c +++ b/src/backend/access/common/toast_internals.c @@ -27,7 +27,7 @@ #include "utils/rel.h" #include "utils/snapmgr.h" -static bool toastrel_valueid_exists(Relation toastrel, Oid valueid); +static bool toastrel_valueid_exists(Relation toastrel, Oid valueid, LOCKMODE lock); static bool toastid_valueid_exists(Oid toastrelid, Oid valueid); /* ---------- @@ -264,7 +264,8 @@ toast_save_datum(Relation rel, Datum value, * be reclaimed by VACUUM. */ if (toastrel_valueid_exists(toastrel, - toast_pointer.va_valueid)) + toast_pointer.va_valueid, + RowExclusiveLock)) { /* Match, so short-circuit the data storage loop below */ data_todo = 0; @@ -359,8 +360,8 @@ toast_save_datum(Relation rel, Datum value, /* * Done - close toast relation and its indexes */ - toast_close_indexes(toastidxs, num_indexes, RowExclusiveLock); - table_close(toastrel, RowExclusiveLock); + toast_close_indexes(toastidxs, num_indexes, NoLock); + table_close(toastrel, NoLock); /* * Create the TOAST pointer value that we'll return @@ -440,8 +441,8 @@ toast_delete_datum(Relation rel, Datum value, bool is_speculative) * End scan and close relations */ systable_endscan_ordered(toastscan); - toast_close_indexes(toastidxs, num_indexes, RowExclusiveLock); - table_close(toastrel, RowExclusiveLock); + toast_close_indexes(toastidxs, num_indexes, NoLock); + table_close(toastrel, NoLock); } /* ---------- @@ -453,7 +454,7 @@ toast_delete_datum(Relation rel, Datum value, bool is_speculative) * ---------- */ static bool -toastrel_valueid_exists(Relation toastrel, Oid valueid) +toastrel_valueid_exists(Relation toastrel, Oid valueid, LOCKMODE lock) { bool result = false; ScanKeyData toastkey; @@ -464,7 +465,7 @@ toastrel_valueid_exists(Relation toastrel, Oid valueid) /* Fetch a valid index relation */ validIndex = toast_open_indexes(toastrel, - RowExclusiveLock, + lock, &toastidxs, &num_indexes); @@ -489,7 +490,7 @@ toastrel_valueid_exists(Relation toastrel, Oid valueid) systable_endscan(toastscan); /* Clean up */ - toast_close_indexes(toastidxs, num_indexes, RowExclusiveLock); + toast_close_indexes(toastidxs, num_indexes, NoLock); return result; } @@ -508,9 +509,9 @@ toastid_valueid_exists(Oid toastrelid, Oid valueid) toastrel = table_open(toastrelid, AccessShareLock); - result = toastrel_valueid_exists(toastrel, valueid); + result = toastrel_valueid_exists(toastrel, valueid, AccessShareLock); - table_close(toastrel, AccessShareLock); + table_close(toastrel, NoLock); return result; } diff --git a/src/backend/access/heap/heaptoast.c b/src/backend/access/heap/heaptoast.c index 55bbe1d584..c3bfb97c62 100644 --- a/src/backend/access/heap/heaptoast.c +++ b/src/backend/access/heap/heaptoast.c @@ -789,5 +789,5 @@ heap_fetch_toast_slice(Relation toastrel, Oid valueid, int32 attrsize, /* End scan and close indexes. */ systable_endscan_ordered(toastscan); - toast_close_indexes(toastidxs, num_indexes, AccessShareLock); + toast_close_indexes(toastidxs, num_indexes, NoLock); } diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index ec14b060a6..b7a007904e 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -2610,7 +2610,9 @@ select * from my_locks order by 1; relname | max_lockmode -----------+-------------------------- alterlock | ShareUpdateExclusiveLock -(1 row) + pg_toast | AccessShareLock + pg_toast | AccessShareLock +(3 rows) rollback; begin; alter table alterlock cluster on alterlock_pkey;