agora inbox for [email protected]help / color / mirror / Atom feed
[PATCH 2/5] Benchmark extension and required core change 22+ messages / 6 participants [nested] [flat]
* [PATCH 2/5] Benchmark extension and required core change @ 2019-06-28 08:03 Kyotaro Horiguchi <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Kyotaro Horiguchi @ 2019-06-28 08:03 UTC (permalink / raw) Micro benchmark extension for SearchSysCache and required core-side code. --- contrib/catcachebench/Makefile | 17 ++ contrib/catcachebench/catcachebench--0.0.sql | 9 + contrib/catcachebench/catcachebench.c | 281 +++++++++++++++++++++++++++ contrib/catcachebench/catcachebench.control | 6 + src/backend/utils/cache/catcache.c | 13 ++ 5 files changed, 326 insertions(+) create mode 100644 contrib/catcachebench/Makefile create mode 100644 contrib/catcachebench/catcachebench--0.0.sql create mode 100644 contrib/catcachebench/catcachebench.c create mode 100644 contrib/catcachebench/catcachebench.control diff --git a/contrib/catcachebench/Makefile b/contrib/catcachebench/Makefile new file mode 100644 index 0000000000..0478818b25 --- /dev/null +++ b/contrib/catcachebench/Makefile @@ -0,0 +1,17 @@ +MODULE_big = catcachebench +OBJS = catcachebench.o + +EXTENSION = catcachebench +DATA = catcachebench--0.0.sql +PGFILEDESC = "catcachebench - benchmark for catcache pruning feature" + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/catcachebench +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/contrib/catcachebench/catcachebench--0.0.sql b/contrib/catcachebench/catcachebench--0.0.sql new file mode 100644 index 0000000000..e091baaaa7 --- /dev/null +++ b/contrib/catcachebench/catcachebench--0.0.sql @@ -0,0 +1,9 @@ +/* contrib/catcachebench/catcachebench--0.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION catcachebench" to load this file. \quit + +CREATE FUNCTION catcachebench(IN type int) +RETURNS double precision +AS 'MODULE_PATHNAME', 'catcachebench' +LANGUAGE C STRICT VOLATILE; diff --git a/contrib/catcachebench/catcachebench.c b/contrib/catcachebench/catcachebench.c new file mode 100644 index 0000000000..0cebbbde4f --- /dev/null +++ b/contrib/catcachebench/catcachebench.c @@ -0,0 +1,281 @@ +/* + * catcachebench: test code for cache pruning feature + */ +#include "postgres.h" +#include "catalog/pg_type.h" +#include "catalog/pg_statistic.h" +#include "executor/spi.h" +#include "libpq/pqsignal.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "utils/timestamp.h" + +Oid tableoids[10000]; +int ntables = 0; +int16 attnums[1000]; +int natts = 0; + +PG_MODULE_MAGIC; + +double catcachebench1(void); +double catcachebench2(void); +double catcachebench3(void); +void collectinfo(void); +void catcachewarmup(void); + +PG_FUNCTION_INFO_V1(catcachebench); + +Datum +catcachebench(PG_FUNCTION_ARGS) +{ + int testtype = PG_GETARG_INT32(0); + double ms; + extern bool _catcache_shrink_buckets; + + collectinfo(); + + /* flush the catalog -- safe? don't mind. */ + + _catcache_shrink_buckets = true; + CatalogCacheFlushCatalog(StatisticRelationId); + _catcache_shrink_buckets = false; + + switch (testtype) + { + case 0: + catcachewarmup(); /* prewarm of syscatalog */ + PG_RETURN_NULL(); + case 1: + ms = catcachebench1(); break; + case 2: + ms = catcachebench2(); break; + case 3: + ms = catcachebench3(); break; + default: + elog(ERROR, "Invalid test type: %d", testtype); + } + + PG_RETURN_DATUM(Float8GetDatum(ms)); +} + +/* + * fetch all attribute entires of all tables. + */ +double +catcachebench1(void) +{ + int t, a; + instr_time start, + duration; + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + for (t = 0 ; t < ntables ; t++) + { + for (a = 0 ; a < natts ; a++) + { + HeapTuple tup; + + tup = SearchSysCache3(STATRELATTINH, + ObjectIdGetDatum(tableoids[t]), + Int16GetDatum(attnums[a]), + BoolGetDatum(false)); + /* should be null, but.. */ + if (HeapTupleIsValid(tup)) + ReleaseSysCache(tup); + } + } + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + return INSTR_TIME_GET_MILLISEC(duration); +}; + +/* + * fetch all attribute entires of a table 6000 times. + */ +double +catcachebench2(void) +{ + const int clock_step = 100; + int t, a; + instr_time start, + duration; + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + for (t = 0 ; t < 60000 ; t++) + { + int ct = clock_step; + + /* + * catcacheclock is updated by transaction timestamp, so needs to + * be updated by other means for this test to work. Here I choosed + * to update the clock every 100 times of table scans. + */ + if (--ct < 0) + { + // We don't have it yet. + //SetCatCacheClock(GetCurrentTimestamp()); + GetCurrentTimestamp(); + ct = clock_step; + } + for (a = 0 ; a < natts ; a++) + { + HeapTuple tup; + + tup = SearchSysCache3(STATRELATTINH, + ObjectIdGetDatum(tableoids[0]), + Int16GetDatum(attnums[a]), + BoolGetDatum(false)); + /* should be null, but.. */ + if (HeapTupleIsValid(tup)) + ReleaseSysCache(tup); + } + } + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + return INSTR_TIME_GET_MILLISEC(duration); +}; + +/* + * fetch all attribute entires of all tables twice with having expiration + * happen. + */ +double +catcachebench3(void) +{ + const int clock_step = 100; + int i, t, a; + instr_time start, + duration; + + PG_SETMASK(&BlockSig); + INSTR_TIME_SET_CURRENT(start); + for (i = 0 ; i < 2 ; i++) + { + int ct = clock_step; + + for (t = 0 ; t < ntables ; t++) + { + /* + * catcacheclock is updated by transaction timestamp, so needs to + * be updated by other means for this test to work. Here I choosed + * to update the clock every 100 tables scan. + */ + if (--ct < 0) + { + // We don't have it yet. + //SetCatCacheClock(GetCurrentTimestamp()); + GetCurrentTimestamp(); + ct = clock_step; + } + for (a = 0 ; a < natts ; a++) + { + HeapTuple tup; + + tup = SearchSysCache3(STATRELATTINH, + ObjectIdGetDatum(tableoids[t]), + Int16GetDatum(attnums[a]), + BoolGetDatum(false)); + /* should be null, but.. */ + if (HeapTupleIsValid(tup)) + ReleaseSysCache(tup); + } + } + } + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + PG_SETMASK(&UnBlockSig); + + return INSTR_TIME_GET_MILLISEC(duration); +}; + +void +catcachewarmup(void) +{ + int t, a; + + /* load up catalog tables */ + for (t = 0 ; t < ntables ; t++) + { + for (a = 0 ; a < natts ; a++) + { + HeapTuple tup; + + tup = SearchSysCache3(STATRELATTINH, + ObjectIdGetDatum(tableoids[t]), + Int16GetDatum(attnums[a]), + BoolGetDatum(false)); + /* should be null, but.. */ + if (HeapTupleIsValid(tup)) + ReleaseSysCache(tup); + } + } +} + +void +collectinfo(void) +{ + int ret; + Datum values[10000]; + bool nulls[10000]; + Oid types0[] = {OIDOID}; + int i; + + ntables = 0; + natts = 0; + + SPI_connect(); + /* collect target tables */ + ret = SPI_execute("select oid from pg_class where relnamespace = (select oid from pg_namespace where nspname = \'test\')", + true, 0); + if (ret != SPI_OK_SELECT) + elog(ERROR, "Failed 1"); + if (SPI_processed == 0) + elog(ERROR, "no relation found in schema \"test\""); + if (SPI_processed > 10000) + elog(ERROR, "too many relation found in schema \"test\""); + + for (i = 0 ; i < SPI_processed ; i++) + { + heap_deform_tuple(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, + values, nulls); + if (nulls[0]) + elog(ERROR, "Failed 2"); + + tableoids[ntables++] = DatumGetObjectId(values[0]); + } + SPI_finish(); + elog(DEBUG1, "%d tables found", ntables); + + values[0] = ObjectIdGetDatum(tableoids[0]); + nulls[0] = false; + SPI_connect(); + ret = SPI_execute_with_args("select attnum from pg_attribute where attrelid = (select oid from pg_class where oid = $1)", + 1, types0, values, NULL, true, 0); + if (SPI_processed == 0) + elog(ERROR, "no attribute found in table %d", tableoids[0]); + if (SPI_processed > 10000) + elog(ERROR, "too many relation found in table %d", tableoids[0]); + + /* collect target attributes. assuming all tables have the same attnums */ + for (i = 0 ; i < SPI_processed ; i++) + { + int16 attnum; + + heap_deform_tuple(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, + values, nulls); + if (nulls[0]) + elog(ERROR, "Failed 3"); + attnum = DatumGetInt16(values[0]); + + if (attnum > 0) + attnums[natts++] = attnum; + } + SPI_finish(); + elog(DEBUG1, "%d attributes found", natts); +} diff --git a/contrib/catcachebench/catcachebench.control b/contrib/catcachebench/catcachebench.control new file mode 100644 index 0000000000..3fc9d2e420 --- /dev/null +++ b/contrib/catcachebench/catcachebench.control @@ -0,0 +1,6 @@ +# catcachebench + +comment = 'benchmark for catcache pruning' +default_version = '0.0' +module_pathname = '$libdir/catcachebench' +relocatable = true diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index 8fc067ce31..98427b67cd 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -716,6 +716,9 @@ ResetCatalogCaches(void) * rather than relying on the relcache to keep a tupdesc for us. Of course * this assumes the tupdesc of a cachable system table will not change...) */ +/* CODE FOR catcachebench: REMOVE ME AFTER USE */ +bool _catcache_shrink_buckets = false; +/* END: CODE FOR catcachebench*/ void CatalogCacheFlushCatalog(Oid catId) { @@ -735,6 +738,16 @@ CatalogCacheFlushCatalog(Oid catId) /* Tell inval.c to call syscache callbacks for this cache */ CallSyscacheCallbacks(cache->id, 0); + + /* CODE FOR catcachebench: REMOVE ME AFTER USE */ + if (_catcache_shrink_buckets) + { + cache->cc_nbuckets = 128; + pfree(cache->cc_bucket); + cache->cc_bucket = palloc0(128 * sizeof(dlist_head)); + elog(LOG, "Catcache reset"); + } + /* END: CODE FOR catcachebench*/ } } -- 2.16.3 ----Next_Part(Mon_Jul_01_16_02_59_2019_106)-- Content-Type: Text/X-Patch; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="v18-0003-Adjust-catcachebench-for-later-patches.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v9 2/4] make common enum for sync methods @ 2023-08-31 14:38 Nathan Bossart <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Nathan Bossart @ 2023-08-31 14:38 UTC (permalink / raw) --- src/backend/storage/file/fd.c | 4 ++-- src/backend/utils/misc/guc_tables.c | 7 ++++--- src/include/common/file_utils.h | 6 ++++++ src/include/storage/fd.h | 6 ------ src/tools/pgindent/typedefs.list | 1 + 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index b490a76ba7..3fed475c38 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -162,7 +162,7 @@ int max_safe_fds = FD_MINFREE; /* default if not changed */ bool data_sync_retry = false; /* How SyncDataDirectory() should do its job. */ -int recovery_init_sync_method = RECOVERY_INIT_SYNC_METHOD_FSYNC; +int recovery_init_sync_method = DATA_DIR_SYNC_METHOD_FSYNC; /* Which kinds of files should be opened with PG_O_DIRECT. */ int io_direct_flags; @@ -3513,7 +3513,7 @@ SyncDataDirectory(void) } #ifdef HAVE_SYNCFS - if (recovery_init_sync_method == RECOVERY_INIT_SYNC_METHOD_SYNCFS) + if (recovery_init_sync_method == DATA_DIR_SYNC_METHOD_SYNCFS) { DIR *dir; struct dirent *de; diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index e565a3092f..5abebe9a9c 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -41,6 +41,7 @@ #include "commands/trigger.h" #include "commands/user.h" #include "commands/vacuum.h" +#include "common/file_utils.h" #include "common/scram-common.h" #include "jit/jit.h" #include "libpq/auth.h" @@ -430,9 +431,9 @@ StaticAssertDecl(lengthof(ssl_protocol_versions_info) == (PG_TLS1_3_VERSION + 2) "array length mismatch"); static const struct config_enum_entry recovery_init_sync_method_options[] = { - {"fsync", RECOVERY_INIT_SYNC_METHOD_FSYNC, false}, + {"fsync", DATA_DIR_SYNC_METHOD_FSYNC, false}, #ifdef HAVE_SYNCFS - {"syncfs", RECOVERY_INIT_SYNC_METHOD_SYNCFS, false}, + {"syncfs", DATA_DIR_SYNC_METHOD_SYNCFS, false}, #endif {NULL, 0, false} }; @@ -4964,7 +4965,7 @@ struct config_enum ConfigureNamesEnum[] = gettext_noop("Sets the method for synchronizing the data directory before crash recovery."), }, &recovery_init_sync_method, - RECOVERY_INIT_SYNC_METHOD_FSYNC, recovery_init_sync_method_options, + DATA_DIR_SYNC_METHOD_FSYNC, recovery_init_sync_method_options, NULL, NULL, NULL }, diff --git a/src/include/common/file_utils.h b/src/include/common/file_utils.h index dd1532bcb0..7da21f15e6 100644 --- a/src/include/common/file_utils.h +++ b/src/include/common/file_utils.h @@ -24,6 +24,12 @@ typedef enum PGFileType PGFILETYPE_LNK } PGFileType; +typedef enum DataDirSyncMethod +{ + DATA_DIR_SYNC_METHOD_FSYNC, + DATA_DIR_SYNC_METHOD_SYNCFS +} DataDirSyncMethod; + struct iovec; /* avoid including port/pg_iovec.h here */ #ifdef FRONTEND diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index aea30c0622..d9d5d9da5f 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -46,12 +46,6 @@ #include <dirent.h> #include <fcntl.h> -typedef enum RecoveryInitSyncMethod -{ - RECOVERY_INIT_SYNC_METHOD_FSYNC, - RECOVERY_INIT_SYNC_METHOD_SYNCFS -} RecoveryInitSyncMethod; - typedef int File; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 49a33c0387..fe571c6265 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -545,6 +545,7 @@ DR_printtup DR_sqlfunction DR_transientrel DWORD +DataDirSyncMethod DataDumperPtr DataPageDeleteStack DatabaseInfo -- 2.25.1 --2fHTh5uZTiUOsy+g Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v9-0003-add-support-for-syncfs-in-frontend-support-functi.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v9 2/4] make common enum for sync methods @ 2023-08-31 14:38 Nathan Bossart <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Nathan Bossart @ 2023-08-31 14:38 UTC (permalink / raw) --- src/backend/storage/file/fd.c | 4 ++-- src/backend/utils/misc/guc_tables.c | 7 ++++--- src/include/common/file_utils.h | 6 ++++++ src/include/storage/fd.h | 6 ------ src/tools/pgindent/typedefs.list | 1 + 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index b490a76ba7..3fed475c38 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -162,7 +162,7 @@ int max_safe_fds = FD_MINFREE; /* default if not changed */ bool data_sync_retry = false; /* How SyncDataDirectory() should do its job. */ -int recovery_init_sync_method = RECOVERY_INIT_SYNC_METHOD_FSYNC; +int recovery_init_sync_method = DATA_DIR_SYNC_METHOD_FSYNC; /* Which kinds of files should be opened with PG_O_DIRECT. */ int io_direct_flags; @@ -3513,7 +3513,7 @@ SyncDataDirectory(void) } #ifdef HAVE_SYNCFS - if (recovery_init_sync_method == RECOVERY_INIT_SYNC_METHOD_SYNCFS) + if (recovery_init_sync_method == DATA_DIR_SYNC_METHOD_SYNCFS) { DIR *dir; struct dirent *de; diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index e565a3092f..5abebe9a9c 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -41,6 +41,7 @@ #include "commands/trigger.h" #include "commands/user.h" #include "commands/vacuum.h" +#include "common/file_utils.h" #include "common/scram-common.h" #include "jit/jit.h" #include "libpq/auth.h" @@ -430,9 +431,9 @@ StaticAssertDecl(lengthof(ssl_protocol_versions_info) == (PG_TLS1_3_VERSION + 2) "array length mismatch"); static const struct config_enum_entry recovery_init_sync_method_options[] = { - {"fsync", RECOVERY_INIT_SYNC_METHOD_FSYNC, false}, + {"fsync", DATA_DIR_SYNC_METHOD_FSYNC, false}, #ifdef HAVE_SYNCFS - {"syncfs", RECOVERY_INIT_SYNC_METHOD_SYNCFS, false}, + {"syncfs", DATA_DIR_SYNC_METHOD_SYNCFS, false}, #endif {NULL, 0, false} }; @@ -4964,7 +4965,7 @@ struct config_enum ConfigureNamesEnum[] = gettext_noop("Sets the method for synchronizing the data directory before crash recovery."), }, &recovery_init_sync_method, - RECOVERY_INIT_SYNC_METHOD_FSYNC, recovery_init_sync_method_options, + DATA_DIR_SYNC_METHOD_FSYNC, recovery_init_sync_method_options, NULL, NULL, NULL }, diff --git a/src/include/common/file_utils.h b/src/include/common/file_utils.h index dd1532bcb0..7da21f15e6 100644 --- a/src/include/common/file_utils.h +++ b/src/include/common/file_utils.h @@ -24,6 +24,12 @@ typedef enum PGFileType PGFILETYPE_LNK } PGFileType; +typedef enum DataDirSyncMethod +{ + DATA_DIR_SYNC_METHOD_FSYNC, + DATA_DIR_SYNC_METHOD_SYNCFS +} DataDirSyncMethod; + struct iovec; /* avoid including port/pg_iovec.h here */ #ifdef FRONTEND diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index aea30c0622..d9d5d9da5f 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -46,12 +46,6 @@ #include <dirent.h> #include <fcntl.h> -typedef enum RecoveryInitSyncMethod -{ - RECOVERY_INIT_SYNC_METHOD_FSYNC, - RECOVERY_INIT_SYNC_METHOD_SYNCFS -} RecoveryInitSyncMethod; - typedef int File; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 49a33c0387..fe571c6265 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -545,6 +545,7 @@ DR_printtup DR_sqlfunction DR_transientrel DWORD +DataDirSyncMethod DataDumperPtr DataPageDeleteStack DatabaseInfo -- 2.25.1 --2fHTh5uZTiUOsy+g Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v9-0003-add-support-for-syncfs-in-frontend-support-functi.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v9 2/4] make common enum for sync methods @ 2023-08-31 14:38 Nathan Bossart <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Nathan Bossart @ 2023-08-31 14:38 UTC (permalink / raw) --- src/backend/storage/file/fd.c | 4 ++-- src/backend/utils/misc/guc_tables.c | 7 ++++--- src/include/common/file_utils.h | 6 ++++++ src/include/storage/fd.h | 6 ------ src/tools/pgindent/typedefs.list | 1 + 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index b490a76ba7..3fed475c38 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -162,7 +162,7 @@ int max_safe_fds = FD_MINFREE; /* default if not changed */ bool data_sync_retry = false; /* How SyncDataDirectory() should do its job. */ -int recovery_init_sync_method = RECOVERY_INIT_SYNC_METHOD_FSYNC; +int recovery_init_sync_method = DATA_DIR_SYNC_METHOD_FSYNC; /* Which kinds of files should be opened with PG_O_DIRECT. */ int io_direct_flags; @@ -3513,7 +3513,7 @@ SyncDataDirectory(void) } #ifdef HAVE_SYNCFS - if (recovery_init_sync_method == RECOVERY_INIT_SYNC_METHOD_SYNCFS) + if (recovery_init_sync_method == DATA_DIR_SYNC_METHOD_SYNCFS) { DIR *dir; struct dirent *de; diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index e565a3092f..5abebe9a9c 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -41,6 +41,7 @@ #include "commands/trigger.h" #include "commands/user.h" #include "commands/vacuum.h" +#include "common/file_utils.h" #include "common/scram-common.h" #include "jit/jit.h" #include "libpq/auth.h" @@ -430,9 +431,9 @@ StaticAssertDecl(lengthof(ssl_protocol_versions_info) == (PG_TLS1_3_VERSION + 2) "array length mismatch"); static const struct config_enum_entry recovery_init_sync_method_options[] = { - {"fsync", RECOVERY_INIT_SYNC_METHOD_FSYNC, false}, + {"fsync", DATA_DIR_SYNC_METHOD_FSYNC, false}, #ifdef HAVE_SYNCFS - {"syncfs", RECOVERY_INIT_SYNC_METHOD_SYNCFS, false}, + {"syncfs", DATA_DIR_SYNC_METHOD_SYNCFS, false}, #endif {NULL, 0, false} }; @@ -4964,7 +4965,7 @@ struct config_enum ConfigureNamesEnum[] = gettext_noop("Sets the method for synchronizing the data directory before crash recovery."), }, &recovery_init_sync_method, - RECOVERY_INIT_SYNC_METHOD_FSYNC, recovery_init_sync_method_options, + DATA_DIR_SYNC_METHOD_FSYNC, recovery_init_sync_method_options, NULL, NULL, NULL }, diff --git a/src/include/common/file_utils.h b/src/include/common/file_utils.h index dd1532bcb0..7da21f15e6 100644 --- a/src/include/common/file_utils.h +++ b/src/include/common/file_utils.h @@ -24,6 +24,12 @@ typedef enum PGFileType PGFILETYPE_LNK } PGFileType; +typedef enum DataDirSyncMethod +{ + DATA_DIR_SYNC_METHOD_FSYNC, + DATA_DIR_SYNC_METHOD_SYNCFS +} DataDirSyncMethod; + struct iovec; /* avoid including port/pg_iovec.h here */ #ifdef FRONTEND diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index aea30c0622..d9d5d9da5f 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -46,12 +46,6 @@ #include <dirent.h> #include <fcntl.h> -typedef enum RecoveryInitSyncMethod -{ - RECOVERY_INIT_SYNC_METHOD_FSYNC, - RECOVERY_INIT_SYNC_METHOD_SYNCFS -} RecoveryInitSyncMethod; - typedef int File; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 49a33c0387..fe571c6265 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -545,6 +545,7 @@ DR_printtup DR_sqlfunction DR_transientrel DWORD +DataDirSyncMethod DataDumperPtr DataPageDeleteStack DatabaseInfo -- 2.25.1 --2fHTh5uZTiUOsy+g Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v9-0003-add-support-for-syncfs-in-frontend-support-functi.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v8 2/4] make common enum for sync methods @ 2023-08-31 14:38 Nathan Bossart <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Nathan Bossart @ 2023-08-31 14:38 UTC (permalink / raw) --- src/backend/storage/file/fd.c | 4 ++-- src/backend/utils/misc/guc_tables.c | 7 ++++--- src/include/common/file_utils.h | 6 ++++++ src/include/storage/fd.h | 6 ------ src/tools/pgindent/typedefs.list | 1 + 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index b490a76ba7..3fed475c38 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -162,7 +162,7 @@ int max_safe_fds = FD_MINFREE; /* default if not changed */ bool data_sync_retry = false; /* How SyncDataDirectory() should do its job. */ -int recovery_init_sync_method = RECOVERY_INIT_SYNC_METHOD_FSYNC; +int recovery_init_sync_method = DATA_DIR_SYNC_METHOD_FSYNC; /* Which kinds of files should be opened with PG_O_DIRECT. */ int io_direct_flags; @@ -3513,7 +3513,7 @@ SyncDataDirectory(void) } #ifdef HAVE_SYNCFS - if (recovery_init_sync_method == RECOVERY_INIT_SYNC_METHOD_SYNCFS) + if (recovery_init_sync_method == DATA_DIR_SYNC_METHOD_SYNCFS) { DIR *dir; struct dirent *de; diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index e565a3092f..5abebe9a9c 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -41,6 +41,7 @@ #include "commands/trigger.h" #include "commands/user.h" #include "commands/vacuum.h" +#include "common/file_utils.h" #include "common/scram-common.h" #include "jit/jit.h" #include "libpq/auth.h" @@ -430,9 +431,9 @@ StaticAssertDecl(lengthof(ssl_protocol_versions_info) == (PG_TLS1_3_VERSION + 2) "array length mismatch"); static const struct config_enum_entry recovery_init_sync_method_options[] = { - {"fsync", RECOVERY_INIT_SYNC_METHOD_FSYNC, false}, + {"fsync", DATA_DIR_SYNC_METHOD_FSYNC, false}, #ifdef HAVE_SYNCFS - {"syncfs", RECOVERY_INIT_SYNC_METHOD_SYNCFS, false}, + {"syncfs", DATA_DIR_SYNC_METHOD_SYNCFS, false}, #endif {NULL, 0, false} }; @@ -4964,7 +4965,7 @@ struct config_enum ConfigureNamesEnum[] = gettext_noop("Sets the method for synchronizing the data directory before crash recovery."), }, &recovery_init_sync_method, - RECOVERY_INIT_SYNC_METHOD_FSYNC, recovery_init_sync_method_options, + DATA_DIR_SYNC_METHOD_FSYNC, recovery_init_sync_method_options, NULL, NULL, NULL }, diff --git a/src/include/common/file_utils.h b/src/include/common/file_utils.h index dd1532bcb0..7da21f15e6 100644 --- a/src/include/common/file_utils.h +++ b/src/include/common/file_utils.h @@ -24,6 +24,12 @@ typedef enum PGFileType PGFILETYPE_LNK } PGFileType; +typedef enum DataDirSyncMethod +{ + DATA_DIR_SYNC_METHOD_FSYNC, + DATA_DIR_SYNC_METHOD_SYNCFS +} DataDirSyncMethod; + struct iovec; /* avoid including port/pg_iovec.h here */ #ifdef FRONTEND diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index aea30c0622..d9d5d9da5f 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -46,12 +46,6 @@ #include <dirent.h> #include <fcntl.h> -typedef enum RecoveryInitSyncMethod -{ - RECOVERY_INIT_SYNC_METHOD_FSYNC, - RECOVERY_INIT_SYNC_METHOD_SYNCFS -} RecoveryInitSyncMethod; - typedef int File; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 49a33c0387..fe571c6265 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -545,6 +545,7 @@ DR_printtup DR_sqlfunction DR_transientrel DWORD +DataDirSyncMethod DataDumperPtr DataPageDeleteStack DatabaseInfo -- 2.25.1 --oyUTqETQ0mS9luUI Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v8-0003-add-support-for-syncfs-in-frontend-support-functi.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v8 2/4] make common enum for sync methods @ 2023-08-31 14:38 Nathan Bossart <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Nathan Bossart @ 2023-08-31 14:38 UTC (permalink / raw) --- src/backend/storage/file/fd.c | 4 ++-- src/backend/utils/misc/guc_tables.c | 7 ++++--- src/include/common/file_utils.h | 6 ++++++ src/include/storage/fd.h | 6 ------ src/tools/pgindent/typedefs.list | 1 + 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index b490a76ba7..3fed475c38 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -162,7 +162,7 @@ int max_safe_fds = FD_MINFREE; /* default if not changed */ bool data_sync_retry = false; /* How SyncDataDirectory() should do its job. */ -int recovery_init_sync_method = RECOVERY_INIT_SYNC_METHOD_FSYNC; +int recovery_init_sync_method = DATA_DIR_SYNC_METHOD_FSYNC; /* Which kinds of files should be opened with PG_O_DIRECT. */ int io_direct_flags; @@ -3513,7 +3513,7 @@ SyncDataDirectory(void) } #ifdef HAVE_SYNCFS - if (recovery_init_sync_method == RECOVERY_INIT_SYNC_METHOD_SYNCFS) + if (recovery_init_sync_method == DATA_DIR_SYNC_METHOD_SYNCFS) { DIR *dir; struct dirent *de; diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index e565a3092f..5abebe9a9c 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -41,6 +41,7 @@ #include "commands/trigger.h" #include "commands/user.h" #include "commands/vacuum.h" +#include "common/file_utils.h" #include "common/scram-common.h" #include "jit/jit.h" #include "libpq/auth.h" @@ -430,9 +431,9 @@ StaticAssertDecl(lengthof(ssl_protocol_versions_info) == (PG_TLS1_3_VERSION + 2) "array length mismatch"); static const struct config_enum_entry recovery_init_sync_method_options[] = { - {"fsync", RECOVERY_INIT_SYNC_METHOD_FSYNC, false}, + {"fsync", DATA_DIR_SYNC_METHOD_FSYNC, false}, #ifdef HAVE_SYNCFS - {"syncfs", RECOVERY_INIT_SYNC_METHOD_SYNCFS, false}, + {"syncfs", DATA_DIR_SYNC_METHOD_SYNCFS, false}, #endif {NULL, 0, false} }; @@ -4964,7 +4965,7 @@ struct config_enum ConfigureNamesEnum[] = gettext_noop("Sets the method for synchronizing the data directory before crash recovery."), }, &recovery_init_sync_method, - RECOVERY_INIT_SYNC_METHOD_FSYNC, recovery_init_sync_method_options, + DATA_DIR_SYNC_METHOD_FSYNC, recovery_init_sync_method_options, NULL, NULL, NULL }, diff --git a/src/include/common/file_utils.h b/src/include/common/file_utils.h index dd1532bcb0..7da21f15e6 100644 --- a/src/include/common/file_utils.h +++ b/src/include/common/file_utils.h @@ -24,6 +24,12 @@ typedef enum PGFileType PGFILETYPE_LNK } PGFileType; +typedef enum DataDirSyncMethod +{ + DATA_DIR_SYNC_METHOD_FSYNC, + DATA_DIR_SYNC_METHOD_SYNCFS +} DataDirSyncMethod; + struct iovec; /* avoid including port/pg_iovec.h here */ #ifdef FRONTEND diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index aea30c0622..d9d5d9da5f 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -46,12 +46,6 @@ #include <dirent.h> #include <fcntl.h> -typedef enum RecoveryInitSyncMethod -{ - RECOVERY_INIT_SYNC_METHOD_FSYNC, - RECOVERY_INIT_SYNC_METHOD_SYNCFS -} RecoveryInitSyncMethod; - typedef int File; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 49a33c0387..fe571c6265 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -545,6 +545,7 @@ DR_printtup DR_sqlfunction DR_transientrel DWORD +DataDirSyncMethod DataDumperPtr DataPageDeleteStack DatabaseInfo -- 2.25.1 --oyUTqETQ0mS9luUI Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v8-0003-add-support-for-syncfs-in-frontend-support-functi.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v9 2/4] make common enum for sync methods @ 2023-08-31 14:38 Nathan Bossart <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Nathan Bossart @ 2023-08-31 14:38 UTC (permalink / raw) --- src/backend/storage/file/fd.c | 4 ++-- src/backend/utils/misc/guc_tables.c | 7 ++++--- src/include/common/file_utils.h | 6 ++++++ src/include/storage/fd.h | 6 ------ src/tools/pgindent/typedefs.list | 1 + 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index b490a76ba7..3fed475c38 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -162,7 +162,7 @@ int max_safe_fds = FD_MINFREE; /* default if not changed */ bool data_sync_retry = false; /* How SyncDataDirectory() should do its job. */ -int recovery_init_sync_method = RECOVERY_INIT_SYNC_METHOD_FSYNC; +int recovery_init_sync_method = DATA_DIR_SYNC_METHOD_FSYNC; /* Which kinds of files should be opened with PG_O_DIRECT. */ int io_direct_flags; @@ -3513,7 +3513,7 @@ SyncDataDirectory(void) } #ifdef HAVE_SYNCFS - if (recovery_init_sync_method == RECOVERY_INIT_SYNC_METHOD_SYNCFS) + if (recovery_init_sync_method == DATA_DIR_SYNC_METHOD_SYNCFS) { DIR *dir; struct dirent *de; diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index e565a3092f..5abebe9a9c 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -41,6 +41,7 @@ #include "commands/trigger.h" #include "commands/user.h" #include "commands/vacuum.h" +#include "common/file_utils.h" #include "common/scram-common.h" #include "jit/jit.h" #include "libpq/auth.h" @@ -430,9 +431,9 @@ StaticAssertDecl(lengthof(ssl_protocol_versions_info) == (PG_TLS1_3_VERSION + 2) "array length mismatch"); static const struct config_enum_entry recovery_init_sync_method_options[] = { - {"fsync", RECOVERY_INIT_SYNC_METHOD_FSYNC, false}, + {"fsync", DATA_DIR_SYNC_METHOD_FSYNC, false}, #ifdef HAVE_SYNCFS - {"syncfs", RECOVERY_INIT_SYNC_METHOD_SYNCFS, false}, + {"syncfs", DATA_DIR_SYNC_METHOD_SYNCFS, false}, #endif {NULL, 0, false} }; @@ -4964,7 +4965,7 @@ struct config_enum ConfigureNamesEnum[] = gettext_noop("Sets the method for synchronizing the data directory before crash recovery."), }, &recovery_init_sync_method, - RECOVERY_INIT_SYNC_METHOD_FSYNC, recovery_init_sync_method_options, + DATA_DIR_SYNC_METHOD_FSYNC, recovery_init_sync_method_options, NULL, NULL, NULL }, diff --git a/src/include/common/file_utils.h b/src/include/common/file_utils.h index dd1532bcb0..7da21f15e6 100644 --- a/src/include/common/file_utils.h +++ b/src/include/common/file_utils.h @@ -24,6 +24,12 @@ typedef enum PGFileType PGFILETYPE_LNK } PGFileType; +typedef enum DataDirSyncMethod +{ + DATA_DIR_SYNC_METHOD_FSYNC, + DATA_DIR_SYNC_METHOD_SYNCFS +} DataDirSyncMethod; + struct iovec; /* avoid including port/pg_iovec.h here */ #ifdef FRONTEND diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index aea30c0622..d9d5d9da5f 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -46,12 +46,6 @@ #include <dirent.h> #include <fcntl.h> -typedef enum RecoveryInitSyncMethod -{ - RECOVERY_INIT_SYNC_METHOD_FSYNC, - RECOVERY_INIT_SYNC_METHOD_SYNCFS -} RecoveryInitSyncMethod; - typedef int File; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 49a33c0387..fe571c6265 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -545,6 +545,7 @@ DR_printtup DR_sqlfunction DR_transientrel DWORD +DataDirSyncMethod DataDumperPtr DataPageDeleteStack DatabaseInfo -- 2.25.1 --2fHTh5uZTiUOsy+g Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v9-0003-add-support-for-syncfs-in-frontend-support-functi.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v9 2/4] make common enum for sync methods @ 2023-08-31 14:38 Nathan Bossart <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Nathan Bossart @ 2023-08-31 14:38 UTC (permalink / raw) --- src/backend/storage/file/fd.c | 4 ++-- src/backend/utils/misc/guc_tables.c | 7 ++++--- src/include/common/file_utils.h | 6 ++++++ src/include/storage/fd.h | 6 ------ src/tools/pgindent/typedefs.list | 1 + 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c index b490a76ba7..3fed475c38 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -162,7 +162,7 @@ int max_safe_fds = FD_MINFREE; /* default if not changed */ bool data_sync_retry = false; /* How SyncDataDirectory() should do its job. */ -int recovery_init_sync_method = RECOVERY_INIT_SYNC_METHOD_FSYNC; +int recovery_init_sync_method = DATA_DIR_SYNC_METHOD_FSYNC; /* Which kinds of files should be opened with PG_O_DIRECT. */ int io_direct_flags; @@ -3513,7 +3513,7 @@ SyncDataDirectory(void) } #ifdef HAVE_SYNCFS - if (recovery_init_sync_method == RECOVERY_INIT_SYNC_METHOD_SYNCFS) + if (recovery_init_sync_method == DATA_DIR_SYNC_METHOD_SYNCFS) { DIR *dir; struct dirent *de; diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index e565a3092f..5abebe9a9c 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -41,6 +41,7 @@ #include "commands/trigger.h" #include "commands/user.h" #include "commands/vacuum.h" +#include "common/file_utils.h" #include "common/scram-common.h" #include "jit/jit.h" #include "libpq/auth.h" @@ -430,9 +431,9 @@ StaticAssertDecl(lengthof(ssl_protocol_versions_info) == (PG_TLS1_3_VERSION + 2) "array length mismatch"); static const struct config_enum_entry recovery_init_sync_method_options[] = { - {"fsync", RECOVERY_INIT_SYNC_METHOD_FSYNC, false}, + {"fsync", DATA_DIR_SYNC_METHOD_FSYNC, false}, #ifdef HAVE_SYNCFS - {"syncfs", RECOVERY_INIT_SYNC_METHOD_SYNCFS, false}, + {"syncfs", DATA_DIR_SYNC_METHOD_SYNCFS, false}, #endif {NULL, 0, false} }; @@ -4964,7 +4965,7 @@ struct config_enum ConfigureNamesEnum[] = gettext_noop("Sets the method for synchronizing the data directory before crash recovery."), }, &recovery_init_sync_method, - RECOVERY_INIT_SYNC_METHOD_FSYNC, recovery_init_sync_method_options, + DATA_DIR_SYNC_METHOD_FSYNC, recovery_init_sync_method_options, NULL, NULL, NULL }, diff --git a/src/include/common/file_utils.h b/src/include/common/file_utils.h index dd1532bcb0..7da21f15e6 100644 --- a/src/include/common/file_utils.h +++ b/src/include/common/file_utils.h @@ -24,6 +24,12 @@ typedef enum PGFileType PGFILETYPE_LNK } PGFileType; +typedef enum DataDirSyncMethod +{ + DATA_DIR_SYNC_METHOD_FSYNC, + DATA_DIR_SYNC_METHOD_SYNCFS +} DataDirSyncMethod; + struct iovec; /* avoid including port/pg_iovec.h here */ #ifdef FRONTEND diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h index aea30c0622..d9d5d9da5f 100644 --- a/src/include/storage/fd.h +++ b/src/include/storage/fd.h @@ -46,12 +46,6 @@ #include <dirent.h> #include <fcntl.h> -typedef enum RecoveryInitSyncMethod -{ - RECOVERY_INIT_SYNC_METHOD_FSYNC, - RECOVERY_INIT_SYNC_METHOD_SYNCFS -} RecoveryInitSyncMethod; - typedef int File; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 49a33c0387..fe571c6265 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -545,6 +545,7 @@ DR_printtup DR_sqlfunction DR_transientrel DWORD +DataDirSyncMethod DataDumperPtr DataPageDeleteStack DatabaseInfo -- 2.25.1 --2fHTh5uZTiUOsy+g Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v9-0003-add-support-for-syncfs-in-frontend-support-functi.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v11 5/7] Row pattern recognition patch (docs). @ 2023-11-08 06:57 Tatsuo Ishii <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Tatsuo Ishii @ 2023-11-08 06:57 UTC (permalink / raw) --- doc/src/sgml/advanced.sgml | 80 ++++++++++++++++++++++++++++++++++++ doc/src/sgml/func.sgml | 54 ++++++++++++++++++++++++ doc/src/sgml/ref/select.sgml | 38 ++++++++++++++++- 3 files changed, 170 insertions(+), 2 deletions(-) diff --git a/doc/src/sgml/advanced.sgml b/doc/src/sgml/advanced.sgml index 755c9f1485..cf18dd887e 100644 --- a/doc/src/sgml/advanced.sgml +++ b/doc/src/sgml/advanced.sgml @@ -537,6 +537,86 @@ WHERE pos < 3; <literal>rank</literal> less than 3. </para> + <para> + Row pattern common syntax can be used to perform row pattern recognition + in a query. Row pattern common syntax includes two sub + clauses: <literal>DEFINE</literal> + and <literal>PATTERN</literal>. <literal>DEFINE</literal> defines + definition variables along with an expression. The expression must be a + logical expression, which means it must + return <literal>TRUE</literal>, <literal>FALSE</literal> + or <literal>NULL</literal>. The expression may comprise column references + and functions. Window functions, aggregate functions and subqueries are + not allowed. An example of <literal>DEFINE</literal> is as follows. + +<programlisting> +DEFINE + LOWPRICE AS price <= 100, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +</programlisting> + + Note that <function>PREV</function> returns the price column in the + previous row if it's called in a context of row pattern recognition. So in + the second line the definition variable "UP" is <literal>TRUE</literal> + when the price column in the current row is greater than the price column + in the previous row. Likewise, "DOWN" is <literal>TRUE</literal> when when + the price column in the current row is lower than the price column in the + previous row. + </para> + <para> + Once <literal>DEFINE</literal> exists, <literal>PATTERN</literal> can be + used. <literal>PATTERN</literal> defines a sequence of rows that satisfies + certain conditions. For example following <literal>PATTERN</literal> + defines that a row starts with the condition "LOWPRICE", then one or more + rows satisfy "UP" and finally one or more rows satisfy "DOWN". Note that + "+" means one or more matches. Also you can use "*", which means zero or + more matches. If a sequence of rows which satisfies the PATTERN is found, + in the starting row of the sequence of rows all window functions and + aggregates are shown in the target list. Note that aggregations only look + into the matched rows, rather than whole frame. In the second or + subsequent rows all window functions and aggregates are NULL. For rows + that do not match the PATTERN, all window functions and aggregates are + shown AS NULL too, except count which shows 0. This is because the + unmatched rows are in an empty frame. Example of + a <literal>SELECT</literal> using the <literal>DEFINE</literal> + and <literal>PATTERN</literal> clause is as follows. + +<programlisting> +SELECT company, tdate, price, + first_value(price) OVER w, + max(price) OVER w, + count(price) OVER w +FROM stock, + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + AFTER MATCH SKIP PAST LAST ROW + INITIAL + PATTERN (LOWPRICE UP+ DOWN+) + DEFINE + LOWPRICE AS price <= 100, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); +</programlisting> +<screen> + company | tdate | price | first_value | max | count +----------+------------+-------+-------------+-----+------- + company1 | 2023-07-01 | 100 | 100 | 200 | 4 + company1 | 2023-07-02 | 200 | | | + company1 | 2023-07-03 | 150 | | | + company1 | 2023-07-04 | 140 | | | + company1 | 2023-07-05 | 150 | | | 0 + company1 | 2023-07-06 | 90 | 90 | 130 | 4 + company1 | 2023-07-07 | 110 | | | + company1 | 2023-07-08 | 130 | | | + company1 | 2023-07-09 | 120 | | | + company1 | 2023-07-10 | 130 | | | 0 +</screen> + </para> + <para> When a query involves multiple window functions, it is possible to write out each one with a separate <literal>OVER</literal> clause, but this is diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index d963f0a0a0..c3a8167c8e 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -21933,6 +21933,7 @@ SELECT count(*) FROM sometable; returns <literal>NULL</literal> if there is no such row. </para></entry> </row> + </tbody> </tgroup> </table> @@ -21972,6 +21973,59 @@ SELECT count(*) FROM sometable; Other frame specifications can be used to obtain other effects. </para> + <para> + Row pattern recognition navigation functions are listed in + <xref linkend="functions-rpr-navigation-table"/>. These functions + can be used to describe DEFINE clause of Row pattern recognition. + </para> + + <table id="functions-rpr-navigation-table"> + <title>Row Pattern Navigation Functions</title> + <tgroup cols="1"> + <thead> + <row> + <entry role="func_table_entry"><para role="func_signature"> + Function + </para> + <para> + Description + </para></entry> + </row> + </thead> + + <tbody> + <row> + <entry role="func_table_entry"><para role="func_signature"> + <indexterm> + <primary>prev</primary> + </indexterm> + <function>prev</function> ( <parameter>value</parameter> <type>anyelement</type> ) + <returnvalue>anyelement</returnvalue> + </para> + <para> + Returns the column value at the previous row; + returns NULL if there is no previous row in the window frame. + </para></entry> + </row> + + <row> + <entry role="func_table_entry"><para role="func_signature"> + <indexterm> + <primary>next</primary> + </indexterm> + <function>next</function> ( <parameter>value</parameter> <type>anyelement</type> ) + <returnvalue>anyelement</returnvalue> + </para> + <para> + Returns the column value at the next row; + returns NULL if there is no next row in the window frame. + </para></entry> + </row> + + </tbody> + </tgroup> + </table> + <note> <para> The SQL standard defines a <literal>RESPECT NULLS</literal> or diff --git a/doc/src/sgml/ref/select.sgml b/doc/src/sgml/ref/select.sgml index 42d78913cf..522ad9dd70 100644 --- a/doc/src/sgml/ref/select.sgml +++ b/doc/src/sgml/ref/select.sgml @@ -969,8 +969,8 @@ WINDOW <replaceable class="parameter">window_name</replaceable> AS ( <replaceabl The <replaceable class="parameter">frame_clause</replaceable> can be one of <synopsis> -{ RANGE | ROWS | GROUPS } <replaceable>frame_start</replaceable> [ <replaceable>frame_exclusion</replaceable> ] -{ RANGE | ROWS | GROUPS } BETWEEN <replaceable>frame_start</replaceable> AND <replaceable>frame_end</replaceable> [ <replaceable>frame_exclusion</replaceable> ] +{ RANGE | ROWS | GROUPS } <replaceable>frame_start</replaceable> [ <replaceable>frame_exclusion</replaceable> ] [row_pattern_common_syntax] +{ RANGE | ROWS | GROUPS } BETWEEN <replaceable>frame_start</replaceable> AND <replaceable>frame_end</replaceable> [ <replaceable>frame_exclusion</replaceable> ] [row_pattern_common_syntax] </synopsis> where <replaceable>frame_start</replaceable> @@ -1077,6 +1077,40 @@ EXCLUDE NO OTHERS a given peer group will be in the frame or excluded from it. </para> + <para> + The + optional <replaceable class="parameter">row_pattern_common_syntax</replaceable> + defines the <firstterm>row pattern recognition condition</firstterm> for + this + window. <replaceable class="parameter">row_pattern_common_syntax</replaceable> + includes following subclauses. <literal>AFTER MATCH SKIP PAST LAST + ROW</literal> or <literal>AFTER MATCH SKIP TO NEXT ROW</literal> controls + how to proceed to next row position after a match + found. With <literal>AFTER MATCH SKIP PAST LAST ROW</literal> (the + default) next row position is next to the last row of previous match. On + the other hand, with <literal>AFTER MATCH SKIP TO NEXT ROW</literal> next + row position is always next to the last row of previous + match. <literal>DEFINE</literal> defines definition variables along with a + boolean expression. <literal>PATTERN</literal> defines a sequence of rows + that satisfies certain conditions using variables defined + in <literal>DEFINE</literal> clause. If the variable is not defined in + the <literal>DEFINE</literal> clause, it is implicitly assumed + following is defined in the <literal>DEFINE</literal> clause. + +<synopsis> +<literal>variable_name</literal> AS TRUE +</synopsis> + + Note that the maximu number of variables defined + in <literal>DEFINE</literal> clause is 26. + +<synopsis> +[ AFTER MATCH SKIP PAST LAST ROW | AFTER MATCH SKIP TO NEXT ROW ] +PATTERN <replaceable class="parameter">pattern_variable_name</replaceable>[+] [, ...] +DEFINE <replaceable class="parameter">definition_varible_name</replaceable> AS <replaceable class="parameter">expression</replaceable> [, ...] +</synopsis> + </para> + <para> The purpose of a <literal>WINDOW</literal> clause is to specify the behavior of <firstterm>window functions</firstterm> appearing in the query's -- 2.25.1 ----Next_Part(Wed_Nov__8_16_37_05_2023_872)-- Content-Type: Text/X-Patch; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="v11-0006-Row-pattern-recognition-patch-tests.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v6 04/14] bufmgr: Change BufferDesc.state to be a 64bit atomic @ 2025-11-06 00:22 Andres Freund <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Andres Freund @ 2025-11-06 00:22 UTC (permalink / raw) This is motivated by wanting to merge buffer content locks into BufferDesc.state in a future commit, rather than having a separate lwlock (see commit c75ebc657ff more details). As this change is rather mechanical, it seems to make sense to split it out into a separate commit, for easier review. Discussion: https://postgr.es/m/fvfmkr5kk4nyex56ejgxj3uzi63isfxovp2biecb4bspbjrze7@az2pljabhnff --- src/include/storage/buf_internals.h | 88 ++++++---- src/backend/storage/buffer/buf_init.c | 2 +- src/backend/storage/buffer/bufmgr.c | 158 +++++++++--------- src/backend/storage/buffer/freelist.c | 24 +-- src/backend/storage/buffer/localbuf.c | 72 ++++---- contrib/pg_buffercache/pg_buffercache_pages.c | 8 +- src/test/modules/test_aio/test_aio.c | 12 +- 7 files changed, 192 insertions(+), 172 deletions(-) diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index 5400c56a965..28519ad2813 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -30,7 +30,7 @@ #include "utils/resowner.h" /* - * Buffer state is a single 32-bit variable where following data is combined. + * Buffer state is a single 64-bit variable where following data is combined. * * - 18 bits refcount * - 4 bits usage count @@ -39,6 +39,9 @@ * Combining these values allows to perform some operations without locking * the buffer header, by modifying them together with a CAS loop. * + * NB: A future commit will use a significant portion of the remaining bits to + * implement buffer locking as part of the state variable. + * * The definition of buffer state components is below. */ #define BUF_REFCOUNT_BITS 18 @@ -49,15 +52,21 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, "parts of buffer state space need to equal 32"); #define BUF_REFCOUNT_ONE 1 -#define BUF_REFCOUNT_MASK ((1U << BUF_REFCOUNT_BITS) - 1) -#define BUF_USAGECOUNT_MASK (((1U << BUF_USAGECOUNT_BITS) - 1) << (BUF_REFCOUNT_BITS)) -#define BUF_USAGECOUNT_ONE (1U << BUF_REFCOUNT_BITS) +#define BUF_REFCOUNT_MASK \ + ((UINT64CONST(1) << BUF_REFCOUNT_BITS) - 1) +#define BUF_USAGECOUNT_MASK \ + (((UINT64CONST(1) << BUF_USAGECOUNT_BITS) - 1) << (BUF_REFCOUNT_BITS)) +#define BUF_USAGECOUNT_ONE \ + (UINT64CONST(1) << BUF_REFCOUNT_BITS) #define BUF_USAGECOUNT_SHIFT BUF_REFCOUNT_BITS -#define BUF_FLAG_MASK (((1U << BUF_FLAG_BITS) - 1) << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS)) +#define BUF_FLAG_MASK \ + (((UINT64CONST(1) << BUF_FLAG_BITS) - 1) << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS)) /* Get refcount and usagecount from buffer state */ -#define BUF_STATE_GET_REFCOUNT(state) ((state) & BUF_REFCOUNT_MASK) -#define BUF_STATE_GET_USAGECOUNT(state) (((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT) +#define BUF_STATE_GET_REFCOUNT(state) \ + ((uint32)((state) & BUF_REFCOUNT_MASK)) +#define BUF_STATE_GET_USAGECOUNT(state) \ + ((uint32)(((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT)) /* * Flags for buffer descriptors @@ -65,17 +74,28 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, * Note: BM_TAG_VALID essentially means that there is a buffer hashtable * entry associated with the buffer's tag. */ -#define BM_LOCKED (1U << 22) /* buffer header is locked */ -#define BM_DIRTY (1U << 23) /* data needs writing */ -#define BM_VALID (1U << 24) /* data is valid */ -#define BM_TAG_VALID (1U << 25) /* tag is assigned */ -#define BM_IO_IN_PROGRESS (1U << 26) /* read or write in progress */ -#define BM_IO_ERROR (1U << 27) /* previous I/O failed */ -#define BM_JUST_DIRTIED (1U << 28) /* dirtied since write started */ -#define BM_PIN_COUNT_WAITER (1U << 29) /* have waiter for sole pin */ -#define BM_CHECKPOINT_NEEDED (1U << 30) /* must write for checkpoint */ -#define BM_PERMANENT (1U << 31) /* permanent buffer (not unlogged, - * or init fork) */ + +/* buffer header is locked */ +#define BM_LOCKED (UINT64CONST(1) << 22) +/* data needs writing */ +#define BM_DIRTY (UINT64CONST(1) << 23) +/* data is valid */ +#define BM_VALID (UINT64CONST(1) << 24) +/* tag is assigned */ +#define BM_TAG_VALID (UINT64CONST(1) << 25) +/* read or write in progress */ +#define BM_IO_IN_PROGRESS (UINT64CONST(1) << 26) +/* previous I/O failed */ +#define BM_IO_ERROR (UINT64CONST(1) << 27) +/* dirtied since write started */ +#define BM_JUST_DIRTIED (UINT64CONST(1) << 28) +/* have waiter for sole pin */ +#define BM_PIN_COUNT_WAITER (UINT64CONST(1) << 29) +/* must write for checkpoint */ +#define BM_CHECKPOINT_NEEDED (UINT64CONST(1) << 30) +/* permanent buffer (not unlogged, or init fork) */ +#define BM_PERMANENT (UINT64CONST(1) << 31) + /* * The maximum allowed value of usage_count represents a tradeoff between * accuracy and speed of the clock-sweep buffer management algorithm. A @@ -86,7 +106,7 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, */ #define BM_MAX_USAGE_COUNT 5 -StaticAssertDecl(BM_MAX_USAGE_COUNT < (1 << BUF_USAGECOUNT_BITS), +StaticAssertDecl(BM_MAX_USAGE_COUNT < (UINT64CONST(1) << BUF_USAGECOUNT_BITS), "BM_MAX_USAGE_COUNT doesn't fit in BUF_USAGECOUNT_BITS bits"); StaticAssertDecl(MAX_BACKENDS_BITS <= BUF_REFCOUNT_BITS, "MAX_BACKENDS_BITS needs to be <= BUF_REFCOUNT_BITS"); @@ -251,8 +271,8 @@ BufMappingPartitionLockByIndex(uint32 index) * We use this same struct for local buffer headers, but the locks are not * used and not all of the flag bits are useful either. To avoid unnecessary * overhead, manipulations of the state field should be done without actual - * atomic operations (i.e. only pg_atomic_read_u32() and - * pg_atomic_unlocked_write_u32()). + * atomic operations (i.e. only pg_atomic_read_u64() and + * pg_atomic_unlocked_write_u64()). * * Be careful to avoid increasing the size of the struct when adding or * reordering members. Keeping it below 64 bytes (the most common CPU @@ -280,7 +300,7 @@ typedef struct BufferDesc * State of the buffer, containing flags, refcount and usagecount. See * BUF_* and BM_* defines at the top of this file. */ - pg_atomic_uint32 state; + pg_atomic_uint64 state; /* * Backend of pin-count waiter. The buffer header spinlock needs to be @@ -386,7 +406,7 @@ BufferDescriptorGetContentLock(const BufferDesc *bdesc) * Functions for acquiring/releasing a shared buffer header's spinlock. Do * not apply these to local buffers! */ -extern uint32 LockBufHdr(BufferDesc *desc); +extern uint64 LockBufHdr(BufferDesc *desc); /* * Unlock the buffer header. @@ -397,9 +417,9 @@ extern uint32 LockBufHdr(BufferDesc *desc); static inline void UnlockBufHdr(BufferDesc *desc) { - Assert(pg_atomic_read_u32(&desc->state) & BM_LOCKED); + Assert(pg_atomic_read_u64(&desc->state) & BM_LOCKED); - pg_atomic_fetch_sub_u32(&desc->state, BM_LOCKED); + pg_atomic_fetch_sub_u64(&desc->state, BM_LOCKED); } /* @@ -410,14 +430,14 @@ UnlockBufHdr(BufferDesc *desc) * Note that this approach would not work for usagecount, since we need to cap * the usagecount at BM_MAX_USAGE_COUNT. */ -static inline uint32 -UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, - uint32 set_bits, uint32 unset_bits, +static inline uint64 +UnlockBufHdrExt(BufferDesc *desc, uint64 old_buf_state, + uint64 set_bits, uint64 unset_bits, int refcount_change) { for (;;) { - uint32 buf_state = old_buf_state; + uint64 buf_state = old_buf_state; Assert(buf_state & BM_LOCKED); @@ -428,7 +448,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, if (refcount_change != 0) buf_state += BUF_REFCOUNT_ONE * refcount_change; - if (pg_atomic_compare_exchange_u32(&desc->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&desc->state, &old_buf_state, buf_state)) { return old_buf_state; @@ -436,7 +456,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, } } -extern uint32 WaitBufHdrUnlocked(BufferDesc *buf); +extern uint64 WaitBufHdrUnlocked(BufferDesc *buf); /* in bufmgr.c */ @@ -496,14 +516,14 @@ extern void TrackNewBufferPin(Buffer buf); /* solely to make it easier to write tests */ extern bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait); -extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio); /* freelist.c */ extern IOContext IOContextForStrategy(BufferAccessStrategy strategy); extern BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy, - uint32 *buf_state, bool *from_ring); + uint64 *buf_state, bool *from_ring); extern bool StrategyRejectBuffer(BufferAccessStrategy strategy, BufferDesc *buf, bool from_ring); @@ -539,7 +559,7 @@ extern BlockNumber ExtendBufferedRelLocal(BufferManagerRelation bmr, uint32 *extended_by); extern void MarkLocalBufferDirty(Buffer buffer); extern void TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, - uint32 set_flag_bits, bool release_aio); + uint64 set_flag_bits, bool release_aio); extern bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait); extern void FlushLocalBuffer(BufferDesc *bufHdr, SMgrRelation reln); extern void InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced); diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index 6fd3a6bbac5..25f71191ec3 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -121,7 +121,7 @@ BufferManagerShmemInit(void) ClearBufferTag(&buf->tag); - pg_atomic_init_u32(&buf->state, 0); + pg_atomic_init_u64(&buf->state, 0); buf->wait_backend_pgprocno = INVALID_PROC_NUMBER; buf->buf_id = i; diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index b682878b1fb..e33fa0cbfec 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -686,7 +686,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN { BufferDesc *bufHdr; BufferTag tag; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(recent_buffer)); @@ -699,7 +699,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN int b = -recent_buffer - 1; bufHdr = GetLocalBufferDescriptor(b); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* Is it still valid and holding the right tag? */ if ((buf_state & BM_VALID) && BufferTagsEqual(&tag, &bufHdr->tag)) @@ -1292,8 +1292,8 @@ StartReadBuffersImpl(ReadBuffersOperation *operation, bufHdr = GetLocalBufferDescriptor(-buffers[i] - 1); else bufHdr = GetBufferDescriptor(buffers[i] - 1); - Assert(pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID); - found = pg_atomic_read_u32(&bufHdr->state) & BM_VALID; + Assert(pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID); + found = pg_atomic_read_u64(&bufHdr->state) & BM_VALID; } else { @@ -1519,10 +1519,10 @@ CheckReadBuffersOperation(ReadBuffersOperation *operation, bool is_complete) GetBufferDescriptor(buffer - 1); Assert(BufferGetBlockNumber(buffer) == operation->blocknum + i); - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_TAG_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_TAG_VALID); if (i < operation->nblocks_done) - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_VALID); } #endif } @@ -1989,8 +1989,8 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, int existing_buf_id; Buffer victim_buffer; BufferDesc *victim_buf_hdr; - uint32 victim_buf_state; - uint32 set_bits = 0; + uint64 victim_buf_state; + uint64 set_bits = 0; /* Make sure we will have room to remember the buffer pin */ ResourceOwnerEnlarge(CurrentResourceOwner); @@ -2157,7 +2157,7 @@ InvalidateBuffer(BufferDesc *buf) uint32 oldHash; /* hash value for oldTag */ LWLock *oldPartitionLock; /* buffer partition lock for it */ uint32 oldFlags; - uint32 buf_state; + uint64 buf_state; /* Save the original buffer tag before dropping the spinlock */ oldTag = buf->tag; @@ -2248,7 +2248,7 @@ retry: static bool InvalidateVictimBuffer(BufferDesc *buf_hdr) { - uint32 buf_state; + uint64 buf_state; uint32 hash; LWLock *partition_lock; BufferTag tag; @@ -2308,10 +2308,10 @@ InvalidateVictimBuffer(BufferDesc *buf_hdr) LWLockRelease(partition_lock); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(!(buf_state & (BM_DIRTY | BM_VALID | BM_TAG_VALID))); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); - Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u32(&buf_hdr->state)) > 0); + Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u64(&buf_hdr->state)) > 0); return true; } @@ -2321,7 +2321,7 @@ GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context) { BufferDesc *buf_hdr; Buffer buf; - uint32 buf_state; + uint64 buf_state; bool from_ring; /* @@ -2454,7 +2454,7 @@ again: /* a final set of sanity checks */ #ifdef USE_ASSERT_CHECKING - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) == 1); Assert(!(buf_state & (BM_TAG_VALID | BM_VALID | BM_DIRTY))); @@ -2745,13 +2745,13 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, */ do { - pg_atomic_fetch_and_u32(&existing_hdr->state, ~BM_VALID); + pg_atomic_fetch_and_u64(&existing_hdr->state, ~BM_VALID); } while (!StartBufferIO(existing_hdr, true, false)); } else { - uint32 buf_state; - uint32 set_bits = 0; + uint64 buf_state; + uint64 set_bits = 0; buf_state = LockBufHdr(victim_buf_hdr); @@ -2927,7 +2927,7 @@ BufferIsDirty(Buffer buffer) Assert(BufferIsLockedByMeInMode(buffer, BUFFER_LOCK_EXCLUSIVE)); } - return pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY; + return pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY; } /* @@ -2943,8 +2943,8 @@ void MarkBufferDirty(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; if (!BufferIsValid(buffer)) elog(ERROR, "bad buffer ID: %d", buffer); @@ -2964,7 +2964,7 @@ MarkBufferDirty(Buffer buffer) * NB: We have to wait for the buffer header spinlock to be not held, as * TerminateBufferIO() relies on the spinlock. */ - old_buf_state = pg_atomic_read_u32(&bufHdr->state); + old_buf_state = pg_atomic_read_u64(&bufHdr->state); for (;;) { if (old_buf_state & BM_LOCKED) @@ -2975,7 +2975,7 @@ MarkBufferDirty(Buffer buffer) Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state |= BM_DIRTY | BM_JUST_DIRTIED; - if (pg_atomic_compare_exchange_u32(&bufHdr->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&bufHdr->state, &old_buf_state, buf_state)) break; } @@ -3079,10 +3079,10 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, if (ref == NULL) { - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { if (unlikely(skip_if_not_valid && !(old_buf_state & BM_VALID))) @@ -3116,7 +3116,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, buf_state += BUF_USAGECOUNT_ONE; } - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, buf_state)) { result = (buf_state & BM_VALID) != 0; @@ -3143,7 +3143,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, * that the buffer page is legitimately non-accessible here. We * cannot meddle with that. */ - result = (pg_atomic_read_u32(&buf->state) & BM_VALID) != 0; + result = (pg_atomic_read_u64(&buf->state) & BM_VALID) != 0; Assert(ref->refcount > 0); ref->refcount++; @@ -3178,7 +3178,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, static void PinBuffer_Locked(BufferDesc *buf) { - uint32 old_buf_state; + uint64 old_buf_state; /* * As explained, We don't expect any preexisting pins. That allows us to @@ -3190,7 +3190,7 @@ PinBuffer_Locked(BufferDesc *buf) * Since we hold the buffer spinlock, we can update the buffer state and * release the lock in one operation. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); UnlockBufHdrExt(buf, old_buf_state, 0, 0, 1); @@ -3220,7 +3220,7 @@ WakePinCountWaiter(BufferDesc *buf) * BM_PIN_COUNT_WAITER if it stops waiting for a reason other than this * backend waking it up. */ - uint32 buf_state = LockBufHdr(buf); + uint64 buf_state = LockBufHdr(buf); if ((buf_state & BM_PIN_COUNT_WAITER) && BUF_STATE_GET_REFCOUNT(buf_state) == 1) @@ -3267,7 +3267,7 @@ UnpinBufferNoOwner(BufferDesc *buf) ref->refcount--; if (ref->refcount == 0) { - uint32 old_buf_state; + uint64 old_buf_state; /* * Mark buffer non-accessible to Valgrind. @@ -3285,7 +3285,7 @@ UnpinBufferNoOwner(BufferDesc *buf) Assert(!LWLockHeldByMe(BufferDescriptorGetContentLock(buf))); /* decrement the shared reference count */ - old_buf_state = pg_atomic_fetch_sub_u32(&buf->state, BUF_REFCOUNT_ONE); + old_buf_state = pg_atomic_fetch_sub_u64(&buf->state, BUF_REFCOUNT_ONE); /* Support LockBufferForCleanup() */ if (old_buf_state & BM_PIN_COUNT_WAITER) @@ -3342,7 +3342,7 @@ TrackNewBufferPin(Buffer buf) static void BufferSync(int flags) { - uint32 buf_state; + uint64 buf_state; int buf_id; int num_to_scan; int num_spaces; @@ -3352,7 +3352,7 @@ BufferSync(int flags) Oid last_tsid; binaryheap *ts_heap; int i; - uint32 mask = BM_DIRTY; + uint64 mask = BM_DIRTY; WritebackContext wb_context; /* @@ -3384,7 +3384,7 @@ BufferSync(int flags) for (buf_id = 0; buf_id < NBuffers; buf_id++) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); - uint32 set_bits = 0; + uint64 set_bits = 0; /* * Header spinlock is enough to examine BM_DIRTY, see comment in @@ -3551,7 +3551,7 @@ BufferSync(int flags) * write the buffer though we didn't need to. It doesn't seem worth * guarding against this, though. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_CHECKPOINT_NEEDED) + if (pg_atomic_read_u64(&bufHdr->state) & BM_CHECKPOINT_NEEDED) { if (SyncOneBuffer(buf_id, false, &wb_context) & BUF_WRITTEN) { @@ -3921,7 +3921,7 @@ SyncOneBuffer(int buf_id, bool skip_recently_used, WritebackContext *wb_context) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); int result = 0; - uint32 buf_state; + uint64 buf_state; BufferTag tag; /* Make sure we can handle the pin */ @@ -4169,7 +4169,7 @@ DebugPrintBufferRefcount(Buffer buffer) int32 loccount; char *result; ProcNumber backend; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); if (BufferIsLocal(buffer)) @@ -4186,9 +4186,9 @@ DebugPrintBufferRefcount(Buffer buffer) } /* theoretically we should lock the bufhdr here */ - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); - result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%x, refcount=%u %d)", + result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%" PRIx64 ", refcount=%u %d)", buffer, relpathbackend(BufTagGetRelFileLocator(&buf->tag), backend, BufTagGetForkNum(&buf->tag)).str, @@ -4288,7 +4288,7 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object, instr_time io_start; Block bufBlock; char *bufToWrite; - uint32 buf_state; + uint64 buf_state; /* * Try to start an I/O operation. If StartBufferIO returns false, then @@ -4486,7 +4486,7 @@ BufferIsPermanent(Buffer buffer) * not random garbage. */ bufHdr = GetBufferDescriptor(buffer - 1); - return (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT) != 0; + return (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT) != 0; } /* @@ -4949,11 +4949,11 @@ FlushRelationBuffers(Relation rel) { for (i = 0; i < NLocBuffer; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetLocalBufferDescriptor(i); if (BufTagMatchesRelFileLocator(&bufHdr->tag, &rel->rd_locator) && - ((buf_state = pg_atomic_read_u32(&bufHdr->state)) & + ((buf_state = pg_atomic_read_u64(&bufHdr->state)) & (BM_VALID | BM_DIRTY)) == (BM_VALID | BM_DIRTY)) { ErrorContextCallback errcallback; @@ -4989,7 +4989,7 @@ FlushRelationBuffers(Relation rel) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5061,7 +5061,7 @@ FlushRelationsAllBuffers(SMgrRelation *smgrs, int nrels) { SMgrSortArray *srelent = NULL; BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; /* * As in DropRelationBuffers, an unlocked precheck should be safe and @@ -5310,7 +5310,7 @@ FlushDatabaseBuffers(Oid dbid) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5458,13 +5458,13 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * is only intended to be used in cases where failing to write out the * data would be harmless anyway, it doesn't really matter. */ - if ((pg_atomic_read_u32(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != + if ((pg_atomic_read_u64(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != (BM_DIRTY | BM_JUST_DIRTIED)) { XLogRecPtr lsn = InvalidXLogRecPtr; bool dirtied = false; bool delayChkptFlags = false; - uint32 buf_state; + uint64 buf_state; /* * If we need to protect hint bit updates from torn writes, WAL-log a @@ -5476,7 +5476,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * when we call XLogInsert() since the value changes dynamically. */ if (XLogHintBitIsNeeded() && - (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT)) + (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT)) { /* * If we must not write WAL, due to a relfilelocator-specific @@ -5576,8 +5576,8 @@ UnlockBuffers(void) if (buf) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; buf_state = LockBufHdr(buf); @@ -5708,8 +5708,8 @@ LockBufferForCleanup(Buffer buffer) for (;;) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; /* Try to acquire lock */ LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); @@ -5857,7 +5857,7 @@ bool ConditionalLockBufferForCleanup(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state, + uint64 buf_state, refcount; Assert(BufferIsValid(buffer)); @@ -5915,7 +5915,7 @@ bool IsBufferCleanupOK(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); @@ -5971,7 +5971,7 @@ WaitIO(BufferDesc *buf) ConditionVariablePrepareToSleep(cv); for (;;) { - uint32 buf_state; + uint64 buf_state; PgAioWaitRef iow; /* @@ -6045,7 +6045,7 @@ WaitIO(BufferDesc *buf) bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; ResourceOwnerEnlarge(CurrentResourceOwner); @@ -6101,11 +6101,11 @@ StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) * is being released) */ void -TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio) { - uint32 buf_state; - uint32 unset_flag_bits = 0; + uint64 buf_state; + uint64 unset_flag_bits = 0; int refcount_change = 0; buf_state = LockBufHdr(buf); @@ -6166,7 +6166,7 @@ static void AbortBufferIO(Buffer buffer) { BufferDesc *buf_hdr = GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; buf_state = LockBufHdr(buf_hdr); Assert(buf_state & (BM_IO_IN_PROGRESS | BM_TAG_VALID)); @@ -6260,11 +6260,11 @@ rlocator_comparator(const void *p1, const void *p2) /* * Lock buffer header - set BM_LOCKED in buffer state. */ -uint32 +uint64 LockBufHdr(BufferDesc *desc) { SpinDelayStatus delayStatus; - uint32 old_buf_state; + uint64 old_buf_state; Assert(!BufferIsLocal(BufferDescriptorGetBuffer(desc))); @@ -6273,7 +6273,7 @@ LockBufHdr(BufferDesc *desc) while (true) { /* set BM_LOCKED flag */ - old_buf_state = pg_atomic_fetch_or_u32(&desc->state, BM_LOCKED); + old_buf_state = pg_atomic_fetch_or_u64(&desc->state, BM_LOCKED); /* if it wasn't set before we're OK */ if (!(old_buf_state & BM_LOCKED)) break; @@ -6290,20 +6290,20 @@ LockBufHdr(BufferDesc *desc) * Obviously the buffer could be locked by the time the value is returned, so * this is primarily useful in CAS style loops. */ -pg_noinline uint32 +pg_noinline uint64 WaitBufHdrUnlocked(BufferDesc *buf) { SpinDelayStatus delayStatus; - uint32 buf_state; + uint64 buf_state; init_local_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); while (buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); } finish_spin_delay(&delayStatus); @@ -6591,12 +6591,12 @@ ResOwnerPrintBufferPin(Datum res) static bool EvictUnpinnedBufferInternal(BufferDesc *desc, bool *buffer_flushed) { - uint32 buf_state; + uint64 buf_state; bool result; *buffer_flushed = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -6690,12 +6690,12 @@ EvictAllUnpinnedBuffers(int32 *buffers_evicted, int32 *buffers_flushed, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_flushed; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -6742,7 +6742,7 @@ EvictRelUnpinnedBuffers(Relation rel, int32 *buffers_evicted, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_flushed; CHECK_FOR_INTERRUPTS(); @@ -6809,7 +6809,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) BufferDesc *buf_hdr = is_temp ? GetLocalBufferDescriptor(-buffer - 1) : GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; /* * Check that all the buffers are actually ones that could conceivably @@ -6827,7 +6827,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) } if (is_temp) - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); else buf_state = LockBufHdr(buf_hdr); @@ -6865,7 +6865,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) if (is_temp) { buf_state += BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else UnlockBufHdrExt(buf_hdr, buf_state, 0, 0, 1); @@ -7051,13 +7051,13 @@ buffer_readv_complete_one(PgAioTargetData *td, uint8 buf_off, Buffer buffer, : GetBufferDescriptor(buffer - 1); BufferTag tag = buf_hdr->tag; char *bufdata = BufferGetBlock(buffer); - uint32 set_flag_bits; + uint64 set_flag_bits; int piv_flags; /* check that the buffer is in the expected state for a read */ #ifdef USE_ASSERT_CHECKING { - uint32 buf_state = pg_atomic_read_u32(&buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_VALID)); diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c index 28d952b3534..1d4f19a9afd 100644 --- a/src/backend/storage/buffer/freelist.c +++ b/src/backend/storage/buffer/freelist.c @@ -86,7 +86,7 @@ typedef struct BufferAccessStrategyData /* Prototypes for internal functions */ static BufferDesc *GetBufferFromRing(BufferAccessStrategy strategy, - uint32 *buf_state); + uint64 *buf_state); static void AddBufferToRing(BufferAccessStrategy strategy, BufferDesc *buf); @@ -171,7 +171,7 @@ ClockSweepTick(void) * before returning. */ BufferDesc * -StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_ring) +StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_ring) { BufferDesc *buf; int bgwprocno; @@ -230,8 +230,8 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r trycounter = NBuffers; for (;;) { - uint32 old_buf_state; - uint32 local_buf_state; + uint64 old_buf_state; + uint64 local_buf_state; buf = GetBufferDescriptor(ClockSweepTick()); @@ -239,7 +239,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r * Check whether the buffer can be used and pin it if so. Do this * using a CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -277,7 +277,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r { local_buf_state -= BUF_USAGECOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { trycounter = NBuffers; @@ -289,7 +289,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { /* Found a usable buffer */ @@ -655,12 +655,12 @@ FreeAccessStrategy(BufferAccessStrategy strategy) * returning. */ static BufferDesc * -GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) +GetBufferFromRing(BufferAccessStrategy strategy, uint64 *buf_state) { BufferDesc *buf; Buffer bufnum; - uint32 old_buf_state; - uint32 local_buf_state; /* to avoid repeated (de-)referencing */ + uint64 old_buf_state; + uint64 local_buf_state; /* to avoid repeated (de-)referencing */ /* Advance to next ring slot */ @@ -682,7 +682,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) * Check whether the buffer can be used and pin it if so. Do this using a * CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -710,7 +710,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { *buf_state = local_buf_state; diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index 15aac7d1c9f..a41a5facd3a 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -148,7 +148,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, } else { - uint32 buf_state; + uint64 buf_state; victim_buffer = GetLocalVictimBuffer(); bufid = -victim_buffer - 1; @@ -165,10 +165,10 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, */ bufHdr->tag = newTag; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); buf_state &= ~(BUF_FLAG_MASK | BUF_USAGECOUNT_MASK); buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); *foundPtr = false; } @@ -245,12 +245,12 @@ GetLocalVictimBuffer(void) if (LocalRefCount[victim_bufid] == 0) { - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0) { buf_state -= BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); trycounter = NLocBuffer; } else if (BUF_STATE_GET_REFCOUNT(buf_state) > 0) @@ -286,13 +286,13 @@ GetLocalVictimBuffer(void) * this buffer is not referenced but it might still be dirty. if that's * the case, write it out before reusing it! */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY) FlushLocalBuffer(bufHdr, NULL); /* * Remove the victim buffer from the hashtable and mark as invalid. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID) + if (pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID) { InvalidateLocalBuffer(bufHdr, false); @@ -417,7 +417,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, if (found) { BufferDesc *existing_hdr; - uint32 buf_state; + uint64 buf_state; UnpinLocalBuffer(BufferDescriptorGetBuffer(victim_buf_hdr)); @@ -428,18 +428,18 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, /* * Clear the BM_VALID bit, do StartLocalBufferIO() and proceed. */ - buf_state = pg_atomic_read_u32(&existing_hdr->state); + buf_state = pg_atomic_read_u64(&existing_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_DIRTY)); buf_state &= ~BM_VALID; - pg_atomic_unlocked_write_u32(&existing_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&existing_hdr->state, buf_state); /* no need to loop for local buffers */ StartLocalBufferIO(existing_hdr, true, false); } else { - uint32 buf_state = pg_atomic_read_u32(&victim_buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&victim_buf_hdr->state); Assert(!(buf_state & (BM_VALID | BM_TAG_VALID | BM_DIRTY | BM_JUST_DIRTIED))); @@ -447,7 +447,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&victim_buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&victim_buf_hdr->state, buf_state); hresult->id = victim_buf_id; @@ -467,13 +467,13 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, { Buffer buf = buffers[i]; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); buf_state |= BM_VALID; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } *extended_by = extend_by; @@ -492,7 +492,7 @@ MarkLocalBufferDirty(Buffer buffer) { int bufid; BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsLocal(buffer)); @@ -506,14 +506,14 @@ MarkLocalBufferDirty(Buffer buffer) bufHdr = GetLocalBufferDescriptor(bufid); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_DIRTY)) pgBufferUsage.local_blks_dirtied++; buf_state |= BM_DIRTY; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -522,7 +522,7 @@ MarkLocalBufferDirty(Buffer buffer) bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; /* * With AIO the buffer could have IO in progress, e.g. when there are two @@ -542,7 +542,7 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) /* Once we get here, there is definitely no I/O active on this buffer */ /* Check if someone else already did the I/O */ - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (forInput ? (buf_state & BM_VALID) : !(buf_state & BM_DIRTY)) { return false; @@ -559,11 +559,11 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) * Like TerminateBufferIO, but for local buffers */ void -TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bits, +TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint64 set_flag_bits, bool release_aio) { /* Only need to adjust flags */ - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); /* BM_IO_IN_PROGRESS isn't currently used for local buffers */ @@ -582,7 +582,7 @@ TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bit } buf_state |= set_flag_bits; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); /* local buffers don't track IO using resowners */ @@ -606,7 +606,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) { Buffer buffer = BufferDescriptorGetBuffer(bufHdr); int bufid = -buffer - 1; - uint32 buf_state; + uint64 buf_state; LocalBufferLookupEnt *hresult; /* @@ -622,7 +622,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) Assert(!pgaio_wref_valid(&bufHdr->io_wref)); } - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* * We need to test not just LocalRefCount[bufid] but also the BufferDesc @@ -647,7 +647,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) ClearBufferTag(&bufHdr->tag); buf_state &= ~BUF_FLAG_MASK; buf_state &= ~BUF_USAGECOUNT_MASK; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -671,9 +671,9 @@ DropRelationLocalBuffers(RelFileLocator rlocator, ForkNumber *forkNum, for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_TAG_VALID) || !BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -706,9 +706,9 @@ DropRelationAllLocalBuffers(RelFileLocator rlocator) for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if ((buf_state & BM_TAG_VALID) && BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -804,11 +804,11 @@ InitLocalBuffers(void) bool PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { - uint32 buf_state; + uint64 buf_state; Buffer buffer = BufferDescriptorGetBuffer(buf_hdr); int bufid = -buffer - 1; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); if (LocalRefCount[bufid] == 0) { @@ -819,7 +819,7 @@ PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { buf_state += BUF_USAGECOUNT_ONE; } - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* * See comment in PinBuffer(). @@ -856,14 +856,14 @@ UnpinLocalBufferNoOwner(Buffer buffer) if (--LocalRefCount[buffid] == 0) { BufferDesc *buf_hdr = GetLocalBufferDescriptor(buffid); - uint32 buf_state; + uint64 buf_state; NLocalPinnedBuffers--; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state -= BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* see comment in UnpinBufferNoOwner */ VALGRIND_MAKE_MEM_NOACCESS(LocalBufHdrGetBlock(buf_hdr), BLCKSZ); diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index c29b784dfa1..32bd8aa784a 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -192,7 +192,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) for (i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -559,7 +559,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -570,7 +570,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) * noticeably increase the cost of the function. */ bufHdr = GetBufferDescriptor(i); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (buf_state & BM_VALID) { @@ -620,7 +620,7 @@ pg_buffercache_usage_counts(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); int usage_count; CHECK_FOR_INTERRUPTS(); diff --git a/src/test/modules/test_aio/test_aio.c b/src/test/modules/test_aio/test_aio.c index d7eadeab256..488d98e7e66 100644 --- a/src/test/modules/test_aio/test_aio.c +++ b/src/test/modules/test_aio/test_aio.c @@ -308,9 +308,9 @@ create_toy_buffer(Relation rel, BlockNumber blkno) { Buffer buf; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; bool was_pinned = false; - uint32 unset_bits = 0; + uint64 unset_bits = 0; /* place buffer in shared buffers without erroring out */ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO_AND_LOCK, NULL); @@ -319,7 +319,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); } else { @@ -340,7 +340,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_state &= ~unset_bits; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else { @@ -489,7 +489,7 @@ invalidate_rel_block(PG_FUNCTION_ARGS) LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); - if (pg_atomic_read_u32(&buf_hdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&buf_hdr->state) & BM_DIRTY) { if (BufferIsLocal(buf)) FlushLocalBuffer(buf_hdr, NULL); @@ -572,7 +572,7 @@ buffer_call_terminate_io(PG_FUNCTION_ARGS) bool io_error = PG_GETARG_BOOL(3); bool release_aio = PG_GETARG_BOOL(4); bool clear_dirty = false; - uint32 set_flag_bits = 0; + uint64 set_flag_bits = 0; if (io_error) set_flag_bits |= BM_IO_ERROR; -- 2.48.1.76.g4e746b1a31.dirty --mhhc7c45w3dmihtp Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6-0005-Rename-BUFFERPIN-wait-event-class-to-BUFFER.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v6 04/14] bufmgr: Change BufferDesc.state to be a 64bit atomic @ 2025-11-06 00:22 Andres Freund <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Andres Freund @ 2025-11-06 00:22 UTC (permalink / raw) This is motivated by wanting to merge buffer content locks into BufferDesc.state in a future commit, rather than having a separate lwlock (see commit c75ebc657ff more details). As this change is rather mechanical, it seems to make sense to split it out into a separate commit, for easier review. Discussion: https://postgr.es/m/fvfmkr5kk4nyex56ejgxj3uzi63isfxovp2biecb4bspbjrze7@az2pljabhnff --- src/include/storage/buf_internals.h | 88 ++++++---- src/backend/storage/buffer/buf_init.c | 2 +- src/backend/storage/buffer/bufmgr.c | 158 +++++++++--------- src/backend/storage/buffer/freelist.c | 24 +-- src/backend/storage/buffer/localbuf.c | 72 ++++---- contrib/pg_buffercache/pg_buffercache_pages.c | 8 +- src/test/modules/test_aio/test_aio.c | 12 +- 7 files changed, 192 insertions(+), 172 deletions(-) diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index 5400c56a965..28519ad2813 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -30,7 +30,7 @@ #include "utils/resowner.h" /* - * Buffer state is a single 32-bit variable where following data is combined. + * Buffer state is a single 64-bit variable where following data is combined. * * - 18 bits refcount * - 4 bits usage count @@ -39,6 +39,9 @@ * Combining these values allows to perform some operations without locking * the buffer header, by modifying them together with a CAS loop. * + * NB: A future commit will use a significant portion of the remaining bits to + * implement buffer locking as part of the state variable. + * * The definition of buffer state components is below. */ #define BUF_REFCOUNT_BITS 18 @@ -49,15 +52,21 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, "parts of buffer state space need to equal 32"); #define BUF_REFCOUNT_ONE 1 -#define BUF_REFCOUNT_MASK ((1U << BUF_REFCOUNT_BITS) - 1) -#define BUF_USAGECOUNT_MASK (((1U << BUF_USAGECOUNT_BITS) - 1) << (BUF_REFCOUNT_BITS)) -#define BUF_USAGECOUNT_ONE (1U << BUF_REFCOUNT_BITS) +#define BUF_REFCOUNT_MASK \ + ((UINT64CONST(1) << BUF_REFCOUNT_BITS) - 1) +#define BUF_USAGECOUNT_MASK \ + (((UINT64CONST(1) << BUF_USAGECOUNT_BITS) - 1) << (BUF_REFCOUNT_BITS)) +#define BUF_USAGECOUNT_ONE \ + (UINT64CONST(1) << BUF_REFCOUNT_BITS) #define BUF_USAGECOUNT_SHIFT BUF_REFCOUNT_BITS -#define BUF_FLAG_MASK (((1U << BUF_FLAG_BITS) - 1) << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS)) +#define BUF_FLAG_MASK \ + (((UINT64CONST(1) << BUF_FLAG_BITS) - 1) << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS)) /* Get refcount and usagecount from buffer state */ -#define BUF_STATE_GET_REFCOUNT(state) ((state) & BUF_REFCOUNT_MASK) -#define BUF_STATE_GET_USAGECOUNT(state) (((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT) +#define BUF_STATE_GET_REFCOUNT(state) \ + ((uint32)((state) & BUF_REFCOUNT_MASK)) +#define BUF_STATE_GET_USAGECOUNT(state) \ + ((uint32)(((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT)) /* * Flags for buffer descriptors @@ -65,17 +74,28 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, * Note: BM_TAG_VALID essentially means that there is a buffer hashtable * entry associated with the buffer's tag. */ -#define BM_LOCKED (1U << 22) /* buffer header is locked */ -#define BM_DIRTY (1U << 23) /* data needs writing */ -#define BM_VALID (1U << 24) /* data is valid */ -#define BM_TAG_VALID (1U << 25) /* tag is assigned */ -#define BM_IO_IN_PROGRESS (1U << 26) /* read or write in progress */ -#define BM_IO_ERROR (1U << 27) /* previous I/O failed */ -#define BM_JUST_DIRTIED (1U << 28) /* dirtied since write started */ -#define BM_PIN_COUNT_WAITER (1U << 29) /* have waiter for sole pin */ -#define BM_CHECKPOINT_NEEDED (1U << 30) /* must write for checkpoint */ -#define BM_PERMANENT (1U << 31) /* permanent buffer (not unlogged, - * or init fork) */ + +/* buffer header is locked */ +#define BM_LOCKED (UINT64CONST(1) << 22) +/* data needs writing */ +#define BM_DIRTY (UINT64CONST(1) << 23) +/* data is valid */ +#define BM_VALID (UINT64CONST(1) << 24) +/* tag is assigned */ +#define BM_TAG_VALID (UINT64CONST(1) << 25) +/* read or write in progress */ +#define BM_IO_IN_PROGRESS (UINT64CONST(1) << 26) +/* previous I/O failed */ +#define BM_IO_ERROR (UINT64CONST(1) << 27) +/* dirtied since write started */ +#define BM_JUST_DIRTIED (UINT64CONST(1) << 28) +/* have waiter for sole pin */ +#define BM_PIN_COUNT_WAITER (UINT64CONST(1) << 29) +/* must write for checkpoint */ +#define BM_CHECKPOINT_NEEDED (UINT64CONST(1) << 30) +/* permanent buffer (not unlogged, or init fork) */ +#define BM_PERMANENT (UINT64CONST(1) << 31) + /* * The maximum allowed value of usage_count represents a tradeoff between * accuracy and speed of the clock-sweep buffer management algorithm. A @@ -86,7 +106,7 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, */ #define BM_MAX_USAGE_COUNT 5 -StaticAssertDecl(BM_MAX_USAGE_COUNT < (1 << BUF_USAGECOUNT_BITS), +StaticAssertDecl(BM_MAX_USAGE_COUNT < (UINT64CONST(1) << BUF_USAGECOUNT_BITS), "BM_MAX_USAGE_COUNT doesn't fit in BUF_USAGECOUNT_BITS bits"); StaticAssertDecl(MAX_BACKENDS_BITS <= BUF_REFCOUNT_BITS, "MAX_BACKENDS_BITS needs to be <= BUF_REFCOUNT_BITS"); @@ -251,8 +271,8 @@ BufMappingPartitionLockByIndex(uint32 index) * We use this same struct for local buffer headers, but the locks are not * used and not all of the flag bits are useful either. To avoid unnecessary * overhead, manipulations of the state field should be done without actual - * atomic operations (i.e. only pg_atomic_read_u32() and - * pg_atomic_unlocked_write_u32()). + * atomic operations (i.e. only pg_atomic_read_u64() and + * pg_atomic_unlocked_write_u64()). * * Be careful to avoid increasing the size of the struct when adding or * reordering members. Keeping it below 64 bytes (the most common CPU @@ -280,7 +300,7 @@ typedef struct BufferDesc * State of the buffer, containing flags, refcount and usagecount. See * BUF_* and BM_* defines at the top of this file. */ - pg_atomic_uint32 state; + pg_atomic_uint64 state; /* * Backend of pin-count waiter. The buffer header spinlock needs to be @@ -386,7 +406,7 @@ BufferDescriptorGetContentLock(const BufferDesc *bdesc) * Functions for acquiring/releasing a shared buffer header's spinlock. Do * not apply these to local buffers! */ -extern uint32 LockBufHdr(BufferDesc *desc); +extern uint64 LockBufHdr(BufferDesc *desc); /* * Unlock the buffer header. @@ -397,9 +417,9 @@ extern uint32 LockBufHdr(BufferDesc *desc); static inline void UnlockBufHdr(BufferDesc *desc) { - Assert(pg_atomic_read_u32(&desc->state) & BM_LOCKED); + Assert(pg_atomic_read_u64(&desc->state) & BM_LOCKED); - pg_atomic_fetch_sub_u32(&desc->state, BM_LOCKED); + pg_atomic_fetch_sub_u64(&desc->state, BM_LOCKED); } /* @@ -410,14 +430,14 @@ UnlockBufHdr(BufferDesc *desc) * Note that this approach would not work for usagecount, since we need to cap * the usagecount at BM_MAX_USAGE_COUNT. */ -static inline uint32 -UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, - uint32 set_bits, uint32 unset_bits, +static inline uint64 +UnlockBufHdrExt(BufferDesc *desc, uint64 old_buf_state, + uint64 set_bits, uint64 unset_bits, int refcount_change) { for (;;) { - uint32 buf_state = old_buf_state; + uint64 buf_state = old_buf_state; Assert(buf_state & BM_LOCKED); @@ -428,7 +448,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, if (refcount_change != 0) buf_state += BUF_REFCOUNT_ONE * refcount_change; - if (pg_atomic_compare_exchange_u32(&desc->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&desc->state, &old_buf_state, buf_state)) { return old_buf_state; @@ -436,7 +456,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, } } -extern uint32 WaitBufHdrUnlocked(BufferDesc *buf); +extern uint64 WaitBufHdrUnlocked(BufferDesc *buf); /* in bufmgr.c */ @@ -496,14 +516,14 @@ extern void TrackNewBufferPin(Buffer buf); /* solely to make it easier to write tests */ extern bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait); -extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio); /* freelist.c */ extern IOContext IOContextForStrategy(BufferAccessStrategy strategy); extern BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy, - uint32 *buf_state, bool *from_ring); + uint64 *buf_state, bool *from_ring); extern bool StrategyRejectBuffer(BufferAccessStrategy strategy, BufferDesc *buf, bool from_ring); @@ -539,7 +559,7 @@ extern BlockNumber ExtendBufferedRelLocal(BufferManagerRelation bmr, uint32 *extended_by); extern void MarkLocalBufferDirty(Buffer buffer); extern void TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, - uint32 set_flag_bits, bool release_aio); + uint64 set_flag_bits, bool release_aio); extern bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait); extern void FlushLocalBuffer(BufferDesc *bufHdr, SMgrRelation reln); extern void InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced); diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index 6fd3a6bbac5..25f71191ec3 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -121,7 +121,7 @@ BufferManagerShmemInit(void) ClearBufferTag(&buf->tag); - pg_atomic_init_u32(&buf->state, 0); + pg_atomic_init_u64(&buf->state, 0); buf->wait_backend_pgprocno = INVALID_PROC_NUMBER; buf->buf_id = i; diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index b682878b1fb..e33fa0cbfec 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -686,7 +686,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN { BufferDesc *bufHdr; BufferTag tag; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(recent_buffer)); @@ -699,7 +699,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN int b = -recent_buffer - 1; bufHdr = GetLocalBufferDescriptor(b); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* Is it still valid and holding the right tag? */ if ((buf_state & BM_VALID) && BufferTagsEqual(&tag, &bufHdr->tag)) @@ -1292,8 +1292,8 @@ StartReadBuffersImpl(ReadBuffersOperation *operation, bufHdr = GetLocalBufferDescriptor(-buffers[i] - 1); else bufHdr = GetBufferDescriptor(buffers[i] - 1); - Assert(pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID); - found = pg_atomic_read_u32(&bufHdr->state) & BM_VALID; + Assert(pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID); + found = pg_atomic_read_u64(&bufHdr->state) & BM_VALID; } else { @@ -1519,10 +1519,10 @@ CheckReadBuffersOperation(ReadBuffersOperation *operation, bool is_complete) GetBufferDescriptor(buffer - 1); Assert(BufferGetBlockNumber(buffer) == operation->blocknum + i); - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_TAG_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_TAG_VALID); if (i < operation->nblocks_done) - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_VALID); } #endif } @@ -1989,8 +1989,8 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, int existing_buf_id; Buffer victim_buffer; BufferDesc *victim_buf_hdr; - uint32 victim_buf_state; - uint32 set_bits = 0; + uint64 victim_buf_state; + uint64 set_bits = 0; /* Make sure we will have room to remember the buffer pin */ ResourceOwnerEnlarge(CurrentResourceOwner); @@ -2157,7 +2157,7 @@ InvalidateBuffer(BufferDesc *buf) uint32 oldHash; /* hash value for oldTag */ LWLock *oldPartitionLock; /* buffer partition lock for it */ uint32 oldFlags; - uint32 buf_state; + uint64 buf_state; /* Save the original buffer tag before dropping the spinlock */ oldTag = buf->tag; @@ -2248,7 +2248,7 @@ retry: static bool InvalidateVictimBuffer(BufferDesc *buf_hdr) { - uint32 buf_state; + uint64 buf_state; uint32 hash; LWLock *partition_lock; BufferTag tag; @@ -2308,10 +2308,10 @@ InvalidateVictimBuffer(BufferDesc *buf_hdr) LWLockRelease(partition_lock); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(!(buf_state & (BM_DIRTY | BM_VALID | BM_TAG_VALID))); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); - Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u32(&buf_hdr->state)) > 0); + Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u64(&buf_hdr->state)) > 0); return true; } @@ -2321,7 +2321,7 @@ GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context) { BufferDesc *buf_hdr; Buffer buf; - uint32 buf_state; + uint64 buf_state; bool from_ring; /* @@ -2454,7 +2454,7 @@ again: /* a final set of sanity checks */ #ifdef USE_ASSERT_CHECKING - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) == 1); Assert(!(buf_state & (BM_TAG_VALID | BM_VALID | BM_DIRTY))); @@ -2745,13 +2745,13 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, */ do { - pg_atomic_fetch_and_u32(&existing_hdr->state, ~BM_VALID); + pg_atomic_fetch_and_u64(&existing_hdr->state, ~BM_VALID); } while (!StartBufferIO(existing_hdr, true, false)); } else { - uint32 buf_state; - uint32 set_bits = 0; + uint64 buf_state; + uint64 set_bits = 0; buf_state = LockBufHdr(victim_buf_hdr); @@ -2927,7 +2927,7 @@ BufferIsDirty(Buffer buffer) Assert(BufferIsLockedByMeInMode(buffer, BUFFER_LOCK_EXCLUSIVE)); } - return pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY; + return pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY; } /* @@ -2943,8 +2943,8 @@ void MarkBufferDirty(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; if (!BufferIsValid(buffer)) elog(ERROR, "bad buffer ID: %d", buffer); @@ -2964,7 +2964,7 @@ MarkBufferDirty(Buffer buffer) * NB: We have to wait for the buffer header spinlock to be not held, as * TerminateBufferIO() relies on the spinlock. */ - old_buf_state = pg_atomic_read_u32(&bufHdr->state); + old_buf_state = pg_atomic_read_u64(&bufHdr->state); for (;;) { if (old_buf_state & BM_LOCKED) @@ -2975,7 +2975,7 @@ MarkBufferDirty(Buffer buffer) Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state |= BM_DIRTY | BM_JUST_DIRTIED; - if (pg_atomic_compare_exchange_u32(&bufHdr->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&bufHdr->state, &old_buf_state, buf_state)) break; } @@ -3079,10 +3079,10 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, if (ref == NULL) { - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { if (unlikely(skip_if_not_valid && !(old_buf_state & BM_VALID))) @@ -3116,7 +3116,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, buf_state += BUF_USAGECOUNT_ONE; } - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, buf_state)) { result = (buf_state & BM_VALID) != 0; @@ -3143,7 +3143,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, * that the buffer page is legitimately non-accessible here. We * cannot meddle with that. */ - result = (pg_atomic_read_u32(&buf->state) & BM_VALID) != 0; + result = (pg_atomic_read_u64(&buf->state) & BM_VALID) != 0; Assert(ref->refcount > 0); ref->refcount++; @@ -3178,7 +3178,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, static void PinBuffer_Locked(BufferDesc *buf) { - uint32 old_buf_state; + uint64 old_buf_state; /* * As explained, We don't expect any preexisting pins. That allows us to @@ -3190,7 +3190,7 @@ PinBuffer_Locked(BufferDesc *buf) * Since we hold the buffer spinlock, we can update the buffer state and * release the lock in one operation. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); UnlockBufHdrExt(buf, old_buf_state, 0, 0, 1); @@ -3220,7 +3220,7 @@ WakePinCountWaiter(BufferDesc *buf) * BM_PIN_COUNT_WAITER if it stops waiting for a reason other than this * backend waking it up. */ - uint32 buf_state = LockBufHdr(buf); + uint64 buf_state = LockBufHdr(buf); if ((buf_state & BM_PIN_COUNT_WAITER) && BUF_STATE_GET_REFCOUNT(buf_state) == 1) @@ -3267,7 +3267,7 @@ UnpinBufferNoOwner(BufferDesc *buf) ref->refcount--; if (ref->refcount == 0) { - uint32 old_buf_state; + uint64 old_buf_state; /* * Mark buffer non-accessible to Valgrind. @@ -3285,7 +3285,7 @@ UnpinBufferNoOwner(BufferDesc *buf) Assert(!LWLockHeldByMe(BufferDescriptorGetContentLock(buf))); /* decrement the shared reference count */ - old_buf_state = pg_atomic_fetch_sub_u32(&buf->state, BUF_REFCOUNT_ONE); + old_buf_state = pg_atomic_fetch_sub_u64(&buf->state, BUF_REFCOUNT_ONE); /* Support LockBufferForCleanup() */ if (old_buf_state & BM_PIN_COUNT_WAITER) @@ -3342,7 +3342,7 @@ TrackNewBufferPin(Buffer buf) static void BufferSync(int flags) { - uint32 buf_state; + uint64 buf_state; int buf_id; int num_to_scan; int num_spaces; @@ -3352,7 +3352,7 @@ BufferSync(int flags) Oid last_tsid; binaryheap *ts_heap; int i; - uint32 mask = BM_DIRTY; + uint64 mask = BM_DIRTY; WritebackContext wb_context; /* @@ -3384,7 +3384,7 @@ BufferSync(int flags) for (buf_id = 0; buf_id < NBuffers; buf_id++) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); - uint32 set_bits = 0; + uint64 set_bits = 0; /* * Header spinlock is enough to examine BM_DIRTY, see comment in @@ -3551,7 +3551,7 @@ BufferSync(int flags) * write the buffer though we didn't need to. It doesn't seem worth * guarding against this, though. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_CHECKPOINT_NEEDED) + if (pg_atomic_read_u64(&bufHdr->state) & BM_CHECKPOINT_NEEDED) { if (SyncOneBuffer(buf_id, false, &wb_context) & BUF_WRITTEN) { @@ -3921,7 +3921,7 @@ SyncOneBuffer(int buf_id, bool skip_recently_used, WritebackContext *wb_context) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); int result = 0; - uint32 buf_state; + uint64 buf_state; BufferTag tag; /* Make sure we can handle the pin */ @@ -4169,7 +4169,7 @@ DebugPrintBufferRefcount(Buffer buffer) int32 loccount; char *result; ProcNumber backend; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); if (BufferIsLocal(buffer)) @@ -4186,9 +4186,9 @@ DebugPrintBufferRefcount(Buffer buffer) } /* theoretically we should lock the bufhdr here */ - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); - result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%x, refcount=%u %d)", + result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%" PRIx64 ", refcount=%u %d)", buffer, relpathbackend(BufTagGetRelFileLocator(&buf->tag), backend, BufTagGetForkNum(&buf->tag)).str, @@ -4288,7 +4288,7 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object, instr_time io_start; Block bufBlock; char *bufToWrite; - uint32 buf_state; + uint64 buf_state; /* * Try to start an I/O operation. If StartBufferIO returns false, then @@ -4486,7 +4486,7 @@ BufferIsPermanent(Buffer buffer) * not random garbage. */ bufHdr = GetBufferDescriptor(buffer - 1); - return (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT) != 0; + return (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT) != 0; } /* @@ -4949,11 +4949,11 @@ FlushRelationBuffers(Relation rel) { for (i = 0; i < NLocBuffer; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetLocalBufferDescriptor(i); if (BufTagMatchesRelFileLocator(&bufHdr->tag, &rel->rd_locator) && - ((buf_state = pg_atomic_read_u32(&bufHdr->state)) & + ((buf_state = pg_atomic_read_u64(&bufHdr->state)) & (BM_VALID | BM_DIRTY)) == (BM_VALID | BM_DIRTY)) { ErrorContextCallback errcallback; @@ -4989,7 +4989,7 @@ FlushRelationBuffers(Relation rel) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5061,7 +5061,7 @@ FlushRelationsAllBuffers(SMgrRelation *smgrs, int nrels) { SMgrSortArray *srelent = NULL; BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; /* * As in DropRelationBuffers, an unlocked precheck should be safe and @@ -5310,7 +5310,7 @@ FlushDatabaseBuffers(Oid dbid) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5458,13 +5458,13 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * is only intended to be used in cases where failing to write out the * data would be harmless anyway, it doesn't really matter. */ - if ((pg_atomic_read_u32(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != + if ((pg_atomic_read_u64(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != (BM_DIRTY | BM_JUST_DIRTIED)) { XLogRecPtr lsn = InvalidXLogRecPtr; bool dirtied = false; bool delayChkptFlags = false; - uint32 buf_state; + uint64 buf_state; /* * If we need to protect hint bit updates from torn writes, WAL-log a @@ -5476,7 +5476,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * when we call XLogInsert() since the value changes dynamically. */ if (XLogHintBitIsNeeded() && - (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT)) + (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT)) { /* * If we must not write WAL, due to a relfilelocator-specific @@ -5576,8 +5576,8 @@ UnlockBuffers(void) if (buf) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; buf_state = LockBufHdr(buf); @@ -5708,8 +5708,8 @@ LockBufferForCleanup(Buffer buffer) for (;;) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; /* Try to acquire lock */ LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); @@ -5857,7 +5857,7 @@ bool ConditionalLockBufferForCleanup(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state, + uint64 buf_state, refcount; Assert(BufferIsValid(buffer)); @@ -5915,7 +5915,7 @@ bool IsBufferCleanupOK(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); @@ -5971,7 +5971,7 @@ WaitIO(BufferDesc *buf) ConditionVariablePrepareToSleep(cv); for (;;) { - uint32 buf_state; + uint64 buf_state; PgAioWaitRef iow; /* @@ -6045,7 +6045,7 @@ WaitIO(BufferDesc *buf) bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; ResourceOwnerEnlarge(CurrentResourceOwner); @@ -6101,11 +6101,11 @@ StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) * is being released) */ void -TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio) { - uint32 buf_state; - uint32 unset_flag_bits = 0; + uint64 buf_state; + uint64 unset_flag_bits = 0; int refcount_change = 0; buf_state = LockBufHdr(buf); @@ -6166,7 +6166,7 @@ static void AbortBufferIO(Buffer buffer) { BufferDesc *buf_hdr = GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; buf_state = LockBufHdr(buf_hdr); Assert(buf_state & (BM_IO_IN_PROGRESS | BM_TAG_VALID)); @@ -6260,11 +6260,11 @@ rlocator_comparator(const void *p1, const void *p2) /* * Lock buffer header - set BM_LOCKED in buffer state. */ -uint32 +uint64 LockBufHdr(BufferDesc *desc) { SpinDelayStatus delayStatus; - uint32 old_buf_state; + uint64 old_buf_state; Assert(!BufferIsLocal(BufferDescriptorGetBuffer(desc))); @@ -6273,7 +6273,7 @@ LockBufHdr(BufferDesc *desc) while (true) { /* set BM_LOCKED flag */ - old_buf_state = pg_atomic_fetch_or_u32(&desc->state, BM_LOCKED); + old_buf_state = pg_atomic_fetch_or_u64(&desc->state, BM_LOCKED); /* if it wasn't set before we're OK */ if (!(old_buf_state & BM_LOCKED)) break; @@ -6290,20 +6290,20 @@ LockBufHdr(BufferDesc *desc) * Obviously the buffer could be locked by the time the value is returned, so * this is primarily useful in CAS style loops. */ -pg_noinline uint32 +pg_noinline uint64 WaitBufHdrUnlocked(BufferDesc *buf) { SpinDelayStatus delayStatus; - uint32 buf_state; + uint64 buf_state; init_local_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); while (buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); } finish_spin_delay(&delayStatus); @@ -6591,12 +6591,12 @@ ResOwnerPrintBufferPin(Datum res) static bool EvictUnpinnedBufferInternal(BufferDesc *desc, bool *buffer_flushed) { - uint32 buf_state; + uint64 buf_state; bool result; *buffer_flushed = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -6690,12 +6690,12 @@ EvictAllUnpinnedBuffers(int32 *buffers_evicted, int32 *buffers_flushed, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_flushed; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -6742,7 +6742,7 @@ EvictRelUnpinnedBuffers(Relation rel, int32 *buffers_evicted, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_flushed; CHECK_FOR_INTERRUPTS(); @@ -6809,7 +6809,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) BufferDesc *buf_hdr = is_temp ? GetLocalBufferDescriptor(-buffer - 1) : GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; /* * Check that all the buffers are actually ones that could conceivably @@ -6827,7 +6827,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) } if (is_temp) - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); else buf_state = LockBufHdr(buf_hdr); @@ -6865,7 +6865,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) if (is_temp) { buf_state += BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else UnlockBufHdrExt(buf_hdr, buf_state, 0, 0, 1); @@ -7051,13 +7051,13 @@ buffer_readv_complete_one(PgAioTargetData *td, uint8 buf_off, Buffer buffer, : GetBufferDescriptor(buffer - 1); BufferTag tag = buf_hdr->tag; char *bufdata = BufferGetBlock(buffer); - uint32 set_flag_bits; + uint64 set_flag_bits; int piv_flags; /* check that the buffer is in the expected state for a read */ #ifdef USE_ASSERT_CHECKING { - uint32 buf_state = pg_atomic_read_u32(&buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_VALID)); diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c index 28d952b3534..1d4f19a9afd 100644 --- a/src/backend/storage/buffer/freelist.c +++ b/src/backend/storage/buffer/freelist.c @@ -86,7 +86,7 @@ typedef struct BufferAccessStrategyData /* Prototypes for internal functions */ static BufferDesc *GetBufferFromRing(BufferAccessStrategy strategy, - uint32 *buf_state); + uint64 *buf_state); static void AddBufferToRing(BufferAccessStrategy strategy, BufferDesc *buf); @@ -171,7 +171,7 @@ ClockSweepTick(void) * before returning. */ BufferDesc * -StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_ring) +StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_ring) { BufferDesc *buf; int bgwprocno; @@ -230,8 +230,8 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r trycounter = NBuffers; for (;;) { - uint32 old_buf_state; - uint32 local_buf_state; + uint64 old_buf_state; + uint64 local_buf_state; buf = GetBufferDescriptor(ClockSweepTick()); @@ -239,7 +239,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r * Check whether the buffer can be used and pin it if so. Do this * using a CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -277,7 +277,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r { local_buf_state -= BUF_USAGECOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { trycounter = NBuffers; @@ -289,7 +289,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { /* Found a usable buffer */ @@ -655,12 +655,12 @@ FreeAccessStrategy(BufferAccessStrategy strategy) * returning. */ static BufferDesc * -GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) +GetBufferFromRing(BufferAccessStrategy strategy, uint64 *buf_state) { BufferDesc *buf; Buffer bufnum; - uint32 old_buf_state; - uint32 local_buf_state; /* to avoid repeated (de-)referencing */ + uint64 old_buf_state; + uint64 local_buf_state; /* to avoid repeated (de-)referencing */ /* Advance to next ring slot */ @@ -682,7 +682,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) * Check whether the buffer can be used and pin it if so. Do this using a * CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -710,7 +710,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { *buf_state = local_buf_state; diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index 15aac7d1c9f..a41a5facd3a 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -148,7 +148,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, } else { - uint32 buf_state; + uint64 buf_state; victim_buffer = GetLocalVictimBuffer(); bufid = -victim_buffer - 1; @@ -165,10 +165,10 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, */ bufHdr->tag = newTag; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); buf_state &= ~(BUF_FLAG_MASK | BUF_USAGECOUNT_MASK); buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); *foundPtr = false; } @@ -245,12 +245,12 @@ GetLocalVictimBuffer(void) if (LocalRefCount[victim_bufid] == 0) { - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0) { buf_state -= BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); trycounter = NLocBuffer; } else if (BUF_STATE_GET_REFCOUNT(buf_state) > 0) @@ -286,13 +286,13 @@ GetLocalVictimBuffer(void) * this buffer is not referenced but it might still be dirty. if that's * the case, write it out before reusing it! */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY) FlushLocalBuffer(bufHdr, NULL); /* * Remove the victim buffer from the hashtable and mark as invalid. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID) + if (pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID) { InvalidateLocalBuffer(bufHdr, false); @@ -417,7 +417,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, if (found) { BufferDesc *existing_hdr; - uint32 buf_state; + uint64 buf_state; UnpinLocalBuffer(BufferDescriptorGetBuffer(victim_buf_hdr)); @@ -428,18 +428,18 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, /* * Clear the BM_VALID bit, do StartLocalBufferIO() and proceed. */ - buf_state = pg_atomic_read_u32(&existing_hdr->state); + buf_state = pg_atomic_read_u64(&existing_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_DIRTY)); buf_state &= ~BM_VALID; - pg_atomic_unlocked_write_u32(&existing_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&existing_hdr->state, buf_state); /* no need to loop for local buffers */ StartLocalBufferIO(existing_hdr, true, false); } else { - uint32 buf_state = pg_atomic_read_u32(&victim_buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&victim_buf_hdr->state); Assert(!(buf_state & (BM_VALID | BM_TAG_VALID | BM_DIRTY | BM_JUST_DIRTIED))); @@ -447,7 +447,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&victim_buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&victim_buf_hdr->state, buf_state); hresult->id = victim_buf_id; @@ -467,13 +467,13 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, { Buffer buf = buffers[i]; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); buf_state |= BM_VALID; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } *extended_by = extend_by; @@ -492,7 +492,7 @@ MarkLocalBufferDirty(Buffer buffer) { int bufid; BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsLocal(buffer)); @@ -506,14 +506,14 @@ MarkLocalBufferDirty(Buffer buffer) bufHdr = GetLocalBufferDescriptor(bufid); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_DIRTY)) pgBufferUsage.local_blks_dirtied++; buf_state |= BM_DIRTY; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -522,7 +522,7 @@ MarkLocalBufferDirty(Buffer buffer) bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; /* * With AIO the buffer could have IO in progress, e.g. when there are two @@ -542,7 +542,7 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) /* Once we get here, there is definitely no I/O active on this buffer */ /* Check if someone else already did the I/O */ - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (forInput ? (buf_state & BM_VALID) : !(buf_state & BM_DIRTY)) { return false; @@ -559,11 +559,11 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) * Like TerminateBufferIO, but for local buffers */ void -TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bits, +TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint64 set_flag_bits, bool release_aio) { /* Only need to adjust flags */ - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); /* BM_IO_IN_PROGRESS isn't currently used for local buffers */ @@ -582,7 +582,7 @@ TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bit } buf_state |= set_flag_bits; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); /* local buffers don't track IO using resowners */ @@ -606,7 +606,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) { Buffer buffer = BufferDescriptorGetBuffer(bufHdr); int bufid = -buffer - 1; - uint32 buf_state; + uint64 buf_state; LocalBufferLookupEnt *hresult; /* @@ -622,7 +622,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) Assert(!pgaio_wref_valid(&bufHdr->io_wref)); } - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* * We need to test not just LocalRefCount[bufid] but also the BufferDesc @@ -647,7 +647,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) ClearBufferTag(&bufHdr->tag); buf_state &= ~BUF_FLAG_MASK; buf_state &= ~BUF_USAGECOUNT_MASK; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -671,9 +671,9 @@ DropRelationLocalBuffers(RelFileLocator rlocator, ForkNumber *forkNum, for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_TAG_VALID) || !BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -706,9 +706,9 @@ DropRelationAllLocalBuffers(RelFileLocator rlocator) for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if ((buf_state & BM_TAG_VALID) && BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -804,11 +804,11 @@ InitLocalBuffers(void) bool PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { - uint32 buf_state; + uint64 buf_state; Buffer buffer = BufferDescriptorGetBuffer(buf_hdr); int bufid = -buffer - 1; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); if (LocalRefCount[bufid] == 0) { @@ -819,7 +819,7 @@ PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { buf_state += BUF_USAGECOUNT_ONE; } - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* * See comment in PinBuffer(). @@ -856,14 +856,14 @@ UnpinLocalBufferNoOwner(Buffer buffer) if (--LocalRefCount[buffid] == 0) { BufferDesc *buf_hdr = GetLocalBufferDescriptor(buffid); - uint32 buf_state; + uint64 buf_state; NLocalPinnedBuffers--; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state -= BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* see comment in UnpinBufferNoOwner */ VALGRIND_MAKE_MEM_NOACCESS(LocalBufHdrGetBlock(buf_hdr), BLCKSZ); diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index c29b784dfa1..32bd8aa784a 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -192,7 +192,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) for (i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -559,7 +559,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -570,7 +570,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) * noticeably increase the cost of the function. */ bufHdr = GetBufferDescriptor(i); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (buf_state & BM_VALID) { @@ -620,7 +620,7 @@ pg_buffercache_usage_counts(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); int usage_count; CHECK_FOR_INTERRUPTS(); diff --git a/src/test/modules/test_aio/test_aio.c b/src/test/modules/test_aio/test_aio.c index d7eadeab256..488d98e7e66 100644 --- a/src/test/modules/test_aio/test_aio.c +++ b/src/test/modules/test_aio/test_aio.c @@ -308,9 +308,9 @@ create_toy_buffer(Relation rel, BlockNumber blkno) { Buffer buf; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; bool was_pinned = false; - uint32 unset_bits = 0; + uint64 unset_bits = 0; /* place buffer in shared buffers without erroring out */ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO_AND_LOCK, NULL); @@ -319,7 +319,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); } else { @@ -340,7 +340,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_state &= ~unset_bits; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else { @@ -489,7 +489,7 @@ invalidate_rel_block(PG_FUNCTION_ARGS) LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); - if (pg_atomic_read_u32(&buf_hdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&buf_hdr->state) & BM_DIRTY) { if (BufferIsLocal(buf)) FlushLocalBuffer(buf_hdr, NULL); @@ -572,7 +572,7 @@ buffer_call_terminate_io(PG_FUNCTION_ARGS) bool io_error = PG_GETARG_BOOL(3); bool release_aio = PG_GETARG_BOOL(4); bool clear_dirty = false; - uint32 set_flag_bits = 0; + uint64 set_flag_bits = 0; if (io_error) set_flag_bits |= BM_IO_ERROR; -- 2.48.1.76.g4e746b1a31.dirty --mhhc7c45w3dmihtp Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v6-0005-Rename-BUFFERPIN-wait-event-class-to-BUFFER.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v7 11/15] bufmgr: Change BufferDesc.state to be a 64bit atomic @ 2025-12-02 23:46 Andres Freund <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Andres Freund @ 2025-12-02 23:46 UTC (permalink / raw) This is motivated by wanting to merge buffer content locks into BufferDesc.state in a future commit, rather than having a separate lwlock (see commit c75ebc657ff more details). As this change is rather mechanical, it seems to make sense to split it out into a separate commit, for easier review. Reviewed-by: Melanie Plageman <[email protected]> Discussion: https://postgr.es/m/fvfmkr5kk4nyex56ejgxj3uzi63isfxovp2biecb4bspbjrze7@az2pljabhnff --- src/include/storage/buf_internals.h | 88 +++++---- src/include/storage/procnumber.h | 14 +- src/backend/storage/buffer/buf_init.c | 2 +- src/backend/storage/buffer/bufmgr.c | 170 +++++++++--------- src/backend/storage/buffer/freelist.c | 24 +-- src/backend/storage/buffer/localbuf.c | 72 ++++---- contrib/pg_buffercache/pg_buffercache_pages.c | 8 +- src/test/modules/test_aio/test_aio.c | 12 +- 8 files changed, 205 insertions(+), 185 deletions(-) diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index 5400c56a965..28519ad2813 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -30,7 +30,7 @@ #include "utils/resowner.h" /* - * Buffer state is a single 32-bit variable where following data is combined. + * Buffer state is a single 64-bit variable where following data is combined. * * - 18 bits refcount * - 4 bits usage count @@ -39,6 +39,9 @@ * Combining these values allows to perform some operations without locking * the buffer header, by modifying them together with a CAS loop. * + * NB: A future commit will use a significant portion of the remaining bits to + * implement buffer locking as part of the state variable. + * * The definition of buffer state components is below. */ #define BUF_REFCOUNT_BITS 18 @@ -49,15 +52,21 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, "parts of buffer state space need to equal 32"); #define BUF_REFCOUNT_ONE 1 -#define BUF_REFCOUNT_MASK ((1U << BUF_REFCOUNT_BITS) - 1) -#define BUF_USAGECOUNT_MASK (((1U << BUF_USAGECOUNT_BITS) - 1) << (BUF_REFCOUNT_BITS)) -#define BUF_USAGECOUNT_ONE (1U << BUF_REFCOUNT_BITS) +#define BUF_REFCOUNT_MASK \ + ((UINT64CONST(1) << BUF_REFCOUNT_BITS) - 1) +#define BUF_USAGECOUNT_MASK \ + (((UINT64CONST(1) << BUF_USAGECOUNT_BITS) - 1) << (BUF_REFCOUNT_BITS)) +#define BUF_USAGECOUNT_ONE \ + (UINT64CONST(1) << BUF_REFCOUNT_BITS) #define BUF_USAGECOUNT_SHIFT BUF_REFCOUNT_BITS -#define BUF_FLAG_MASK (((1U << BUF_FLAG_BITS) - 1) << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS)) +#define BUF_FLAG_MASK \ + (((UINT64CONST(1) << BUF_FLAG_BITS) - 1) << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS)) /* Get refcount and usagecount from buffer state */ -#define BUF_STATE_GET_REFCOUNT(state) ((state) & BUF_REFCOUNT_MASK) -#define BUF_STATE_GET_USAGECOUNT(state) (((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT) +#define BUF_STATE_GET_REFCOUNT(state) \ + ((uint32)((state) & BUF_REFCOUNT_MASK)) +#define BUF_STATE_GET_USAGECOUNT(state) \ + ((uint32)(((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT)) /* * Flags for buffer descriptors @@ -65,17 +74,28 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, * Note: BM_TAG_VALID essentially means that there is a buffer hashtable * entry associated with the buffer's tag. */ -#define BM_LOCKED (1U << 22) /* buffer header is locked */ -#define BM_DIRTY (1U << 23) /* data needs writing */ -#define BM_VALID (1U << 24) /* data is valid */ -#define BM_TAG_VALID (1U << 25) /* tag is assigned */ -#define BM_IO_IN_PROGRESS (1U << 26) /* read or write in progress */ -#define BM_IO_ERROR (1U << 27) /* previous I/O failed */ -#define BM_JUST_DIRTIED (1U << 28) /* dirtied since write started */ -#define BM_PIN_COUNT_WAITER (1U << 29) /* have waiter for sole pin */ -#define BM_CHECKPOINT_NEEDED (1U << 30) /* must write for checkpoint */ -#define BM_PERMANENT (1U << 31) /* permanent buffer (not unlogged, - * or init fork) */ + +/* buffer header is locked */ +#define BM_LOCKED (UINT64CONST(1) << 22) +/* data needs writing */ +#define BM_DIRTY (UINT64CONST(1) << 23) +/* data is valid */ +#define BM_VALID (UINT64CONST(1) << 24) +/* tag is assigned */ +#define BM_TAG_VALID (UINT64CONST(1) << 25) +/* read or write in progress */ +#define BM_IO_IN_PROGRESS (UINT64CONST(1) << 26) +/* previous I/O failed */ +#define BM_IO_ERROR (UINT64CONST(1) << 27) +/* dirtied since write started */ +#define BM_JUST_DIRTIED (UINT64CONST(1) << 28) +/* have waiter for sole pin */ +#define BM_PIN_COUNT_WAITER (UINT64CONST(1) << 29) +/* must write for checkpoint */ +#define BM_CHECKPOINT_NEEDED (UINT64CONST(1) << 30) +/* permanent buffer (not unlogged, or init fork) */ +#define BM_PERMANENT (UINT64CONST(1) << 31) + /* * The maximum allowed value of usage_count represents a tradeoff between * accuracy and speed of the clock-sweep buffer management algorithm. A @@ -86,7 +106,7 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, */ #define BM_MAX_USAGE_COUNT 5 -StaticAssertDecl(BM_MAX_USAGE_COUNT < (1 << BUF_USAGECOUNT_BITS), +StaticAssertDecl(BM_MAX_USAGE_COUNT < (UINT64CONST(1) << BUF_USAGECOUNT_BITS), "BM_MAX_USAGE_COUNT doesn't fit in BUF_USAGECOUNT_BITS bits"); StaticAssertDecl(MAX_BACKENDS_BITS <= BUF_REFCOUNT_BITS, "MAX_BACKENDS_BITS needs to be <= BUF_REFCOUNT_BITS"); @@ -251,8 +271,8 @@ BufMappingPartitionLockByIndex(uint32 index) * We use this same struct for local buffer headers, but the locks are not * used and not all of the flag bits are useful either. To avoid unnecessary * overhead, manipulations of the state field should be done without actual - * atomic operations (i.e. only pg_atomic_read_u32() and - * pg_atomic_unlocked_write_u32()). + * atomic operations (i.e. only pg_atomic_read_u64() and + * pg_atomic_unlocked_write_u64()). * * Be careful to avoid increasing the size of the struct when adding or * reordering members. Keeping it below 64 bytes (the most common CPU @@ -280,7 +300,7 @@ typedef struct BufferDesc * State of the buffer, containing flags, refcount and usagecount. See * BUF_* and BM_* defines at the top of this file. */ - pg_atomic_uint32 state; + pg_atomic_uint64 state; /* * Backend of pin-count waiter. The buffer header spinlock needs to be @@ -386,7 +406,7 @@ BufferDescriptorGetContentLock(const BufferDesc *bdesc) * Functions for acquiring/releasing a shared buffer header's spinlock. Do * not apply these to local buffers! */ -extern uint32 LockBufHdr(BufferDesc *desc); +extern uint64 LockBufHdr(BufferDesc *desc); /* * Unlock the buffer header. @@ -397,9 +417,9 @@ extern uint32 LockBufHdr(BufferDesc *desc); static inline void UnlockBufHdr(BufferDesc *desc) { - Assert(pg_atomic_read_u32(&desc->state) & BM_LOCKED); + Assert(pg_atomic_read_u64(&desc->state) & BM_LOCKED); - pg_atomic_fetch_sub_u32(&desc->state, BM_LOCKED); + pg_atomic_fetch_sub_u64(&desc->state, BM_LOCKED); } /* @@ -410,14 +430,14 @@ UnlockBufHdr(BufferDesc *desc) * Note that this approach would not work for usagecount, since we need to cap * the usagecount at BM_MAX_USAGE_COUNT. */ -static inline uint32 -UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, - uint32 set_bits, uint32 unset_bits, +static inline uint64 +UnlockBufHdrExt(BufferDesc *desc, uint64 old_buf_state, + uint64 set_bits, uint64 unset_bits, int refcount_change) { for (;;) { - uint32 buf_state = old_buf_state; + uint64 buf_state = old_buf_state; Assert(buf_state & BM_LOCKED); @@ -428,7 +448,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, if (refcount_change != 0) buf_state += BUF_REFCOUNT_ONE * refcount_change; - if (pg_atomic_compare_exchange_u32(&desc->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&desc->state, &old_buf_state, buf_state)) { return old_buf_state; @@ -436,7 +456,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, } } -extern uint32 WaitBufHdrUnlocked(BufferDesc *buf); +extern uint64 WaitBufHdrUnlocked(BufferDesc *buf); /* in bufmgr.c */ @@ -496,14 +516,14 @@ extern void TrackNewBufferPin(Buffer buf); /* solely to make it easier to write tests */ extern bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait); -extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio); /* freelist.c */ extern IOContext IOContextForStrategy(BufferAccessStrategy strategy); extern BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy, - uint32 *buf_state, bool *from_ring); + uint64 *buf_state, bool *from_ring); extern bool StrategyRejectBuffer(BufferAccessStrategy strategy, BufferDesc *buf, bool from_ring); @@ -539,7 +559,7 @@ extern BlockNumber ExtendBufferedRelLocal(BufferManagerRelation bmr, uint32 *extended_by); extern void MarkLocalBufferDirty(Buffer buffer); extern void TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, - uint32 set_flag_bits, bool release_aio); + uint64 set_flag_bits, bool release_aio); extern bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait); extern void FlushLocalBuffer(BufferDesc *bufHdr, SMgrRelation reln); extern void InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced); diff --git a/src/include/storage/procnumber.h b/src/include/storage/procnumber.h index 2ddaaf0c646..6baac7c77f1 100644 --- a/src/include/storage/procnumber.h +++ b/src/include/storage/procnumber.h @@ -27,13 +27,13 @@ typedef int ProcNumber; /* * Note: MAX_BACKENDS_BITS is 18 as that is the space available for buffer - * refcounts in buf_internals.h. This limitation could be lifted by using a - * 64bit state; but it's unlikely to be worthwhile as 2^18-1 backends exceed - * currently realistic configurations. Even if that limitation were removed, - * we still could not a) exceed 2^23-1 because inval.c stores the ProcNumber - * as a 3-byte signed integer, b) INT_MAX/4 because some places compute - * 4*MaxBackends without any overflow check. We check that the configured - * number of backends does not exceed MAX_BACKENDS in InitializeMaxBackends(). + * refcounts in buf_internals.h. This limitation could be lifted, but it's + * unlikely to be worthwhile as 2^18-1 backends exceed currently realistic + * configurations. Even if that limitation were removed, we still could not a) + * exceed 2^23-1 because inval.c stores the ProcNumber as a 3-byte signed + * integer, b) INT_MAX/4 because some places compute 4*MaxBackends without any + * overflow check. We check that the configured number of backends does not + * exceed MAX_BACKENDS in InitializeMaxBackends(). */ #define MAX_BACKENDS_BITS 18 #define MAX_BACKENDS ((1U << MAX_BACKENDS_BITS)-1) diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index 6fd3a6bbac5..25f71191ec3 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -121,7 +121,7 @@ BufferManagerShmemInit(void) ClearBufferTag(&buf->tag); - pg_atomic_init_u32(&buf->state, 0); + pg_atomic_init_u64(&buf->state, 0); buf->wait_backend_pgprocno = INVALID_PROC_NUMBER; buf->buf_id = i; diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index be32bd596f6..d0b8f8d20eb 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -775,7 +775,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN { BufferDesc *bufHdr; BufferTag tag; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(recent_buffer)); @@ -788,7 +788,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN int b = -recent_buffer - 1; bufHdr = GetLocalBufferDescriptor(b); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* Is it still valid and holding the right tag? */ if ((buf_state & BM_VALID) && BufferTagsEqual(&tag, &bufHdr->tag)) @@ -1381,8 +1381,8 @@ StartReadBuffersImpl(ReadBuffersOperation *operation, bufHdr = GetLocalBufferDescriptor(-buffers[i] - 1); else bufHdr = GetBufferDescriptor(buffers[i] - 1); - Assert(pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID); - found = pg_atomic_read_u32(&bufHdr->state) & BM_VALID; + Assert(pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID); + found = pg_atomic_read_u64(&bufHdr->state) & BM_VALID; } else { @@ -1608,10 +1608,10 @@ CheckReadBuffersOperation(ReadBuffersOperation *operation, bool is_complete) GetBufferDescriptor(buffer - 1); Assert(BufferGetBlockNumber(buffer) == operation->blocknum + i); - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_TAG_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_TAG_VALID); if (i < operation->nblocks_done) - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_VALID); } #endif } @@ -2078,8 +2078,8 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, int existing_buf_id; Buffer victim_buffer; BufferDesc *victim_buf_hdr; - uint32 victim_buf_state; - uint32 set_bits = 0; + uint64 victim_buf_state; + uint64 set_bits = 0; /* Make sure we will have room to remember the buffer pin */ ResourceOwnerEnlarge(CurrentResourceOwner); @@ -2246,7 +2246,7 @@ InvalidateBuffer(BufferDesc *buf) uint32 oldHash; /* hash value for oldTag */ LWLock *oldPartitionLock; /* buffer partition lock for it */ uint32 oldFlags; - uint32 buf_state; + uint64 buf_state; /* Save the original buffer tag before dropping the spinlock */ oldTag = buf->tag; @@ -2337,7 +2337,7 @@ retry: static bool InvalidateVictimBuffer(BufferDesc *buf_hdr) { - uint32 buf_state; + uint64 buf_state; uint32 hash; LWLock *partition_lock; BufferTag tag; @@ -2397,10 +2397,10 @@ InvalidateVictimBuffer(BufferDesc *buf_hdr) LWLockRelease(partition_lock); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(!(buf_state & (BM_DIRTY | BM_VALID | BM_TAG_VALID))); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); - Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u32(&buf_hdr->state)) > 0); + Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u64(&buf_hdr->state)) > 0); return true; } @@ -2410,7 +2410,7 @@ GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context) { BufferDesc *buf_hdr; Buffer buf; - uint32 buf_state; + uint64 buf_state; bool from_ring; /* @@ -2543,7 +2543,7 @@ again: /* a final set of sanity checks */ #ifdef USE_ASSERT_CHECKING - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) == 1); Assert(!(buf_state & (BM_TAG_VALID | BM_VALID | BM_DIRTY))); @@ -2834,13 +2834,13 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, */ do { - pg_atomic_fetch_and_u32(&existing_hdr->state, ~BM_VALID); + pg_atomic_fetch_and_u64(&existing_hdr->state, ~BM_VALID); } while (!StartBufferIO(existing_hdr, true, false)); } else { - uint32 buf_state; - uint32 set_bits = 0; + uint64 buf_state; + uint64 set_bits = 0; buf_state = LockBufHdr(victim_buf_hdr); @@ -3016,7 +3016,7 @@ BufferIsDirty(Buffer buffer) Assert(BufferIsLockedByMeInMode(buffer, BUFFER_LOCK_EXCLUSIVE)); } - return pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY; + return pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY; } /* @@ -3032,8 +3032,8 @@ void MarkBufferDirty(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; if (!BufferIsValid(buffer)) elog(ERROR, "bad buffer ID: %d", buffer); @@ -3053,7 +3053,7 @@ MarkBufferDirty(Buffer buffer) * NB: We have to wait for the buffer header spinlock to be not held, as * TerminateBufferIO() relies on the spinlock. */ - old_buf_state = pg_atomic_read_u32(&bufHdr->state); + old_buf_state = pg_atomic_read_u64(&bufHdr->state); for (;;) { if (old_buf_state & BM_LOCKED) @@ -3064,7 +3064,7 @@ MarkBufferDirty(Buffer buffer) Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state |= BM_DIRTY | BM_JUST_DIRTIED; - if (pg_atomic_compare_exchange_u32(&bufHdr->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&bufHdr->state, &old_buf_state, buf_state)) break; } @@ -3168,10 +3168,10 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, if (ref == NULL) { - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { if (unlikely(skip_if_not_valid && !(old_buf_state & BM_VALID))) @@ -3205,7 +3205,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, buf_state += BUF_USAGECOUNT_ONE; } - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, buf_state)) { result = (buf_state & BM_VALID) != 0; @@ -3232,7 +3232,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, * that the buffer page is legitimately non-accessible here. We * cannot meddle with that. */ - result = (pg_atomic_read_u32(&buf->state) & BM_VALID) != 0; + result = (pg_atomic_read_u64(&buf->state) & BM_VALID) != 0; Assert(ref->data.refcount > 0); ref->data.refcount++; @@ -3267,7 +3267,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, static void PinBuffer_Locked(BufferDesc *buf) { - uint32 old_buf_state; + uint64 old_buf_state; /* * As explained, We don't expect any preexisting pins. That allows us to @@ -3279,7 +3279,7 @@ PinBuffer_Locked(BufferDesc *buf) * Since we hold the buffer spinlock, we can update the buffer state and * release the lock in one operation. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); UnlockBufHdrExt(buf, old_buf_state, 0, 0, 1); @@ -3309,7 +3309,7 @@ WakePinCountWaiter(BufferDesc *buf) * BM_PIN_COUNT_WAITER if it stops waiting for a reason other than this * backend waking it up. */ - uint32 buf_state = LockBufHdr(buf); + uint64 buf_state = LockBufHdr(buf); if ((buf_state & BM_PIN_COUNT_WAITER) && BUF_STATE_GET_REFCOUNT(buf_state) == 1) @@ -3356,7 +3356,7 @@ UnpinBufferNoOwner(BufferDesc *buf) ref->data.refcount--; if (ref->data.refcount == 0) { - uint32 old_buf_state; + uint64 old_buf_state; /* * Mark buffer non-accessible to Valgrind. @@ -3374,7 +3374,7 @@ UnpinBufferNoOwner(BufferDesc *buf) Assert(!LWLockHeldByMe(BufferDescriptorGetContentLock(buf))); /* decrement the shared reference count */ - old_buf_state = pg_atomic_fetch_sub_u32(&buf->state, BUF_REFCOUNT_ONE); + old_buf_state = pg_atomic_fetch_sub_u64(&buf->state, BUF_REFCOUNT_ONE); /* Support LockBufferForCleanup() */ if (old_buf_state & BM_PIN_COUNT_WAITER) @@ -3431,7 +3431,7 @@ TrackNewBufferPin(Buffer buf) static void BufferSync(int flags) { - uint32 buf_state; + uint64 buf_state; int buf_id; int num_to_scan; int num_spaces; @@ -3441,7 +3441,7 @@ BufferSync(int flags) Oid last_tsid; binaryheap *ts_heap; int i; - uint32 mask = BM_DIRTY; + uint64 mask = BM_DIRTY; WritebackContext wb_context; /* @@ -3473,7 +3473,7 @@ BufferSync(int flags) for (buf_id = 0; buf_id < NBuffers; buf_id++) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); - uint32 set_bits = 0; + uint64 set_bits = 0; /* * Header spinlock is enough to examine BM_DIRTY, see comment in @@ -3640,7 +3640,7 @@ BufferSync(int flags) * write the buffer though we didn't need to. It doesn't seem worth * guarding against this, though. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_CHECKPOINT_NEEDED) + if (pg_atomic_read_u64(&bufHdr->state) & BM_CHECKPOINT_NEEDED) { if (SyncOneBuffer(buf_id, false, &wb_context) & BUF_WRITTEN) { @@ -4010,7 +4010,7 @@ SyncOneBuffer(int buf_id, bool skip_recently_used, WritebackContext *wb_context) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); int result = 0; - uint32 buf_state; + uint64 buf_state; BufferTag tag; /* Make sure we can handle the pin */ @@ -4259,7 +4259,7 @@ DebugPrintBufferRefcount(Buffer buffer) int32 loccount; char *result; ProcNumber backend; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); if (BufferIsLocal(buffer)) @@ -4276,9 +4276,9 @@ DebugPrintBufferRefcount(Buffer buffer) } /* theoretically we should lock the bufhdr here */ - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); - result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%x, refcount=%u %d)", + result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%" PRIx64 ", refcount=%u %d)", buffer, relpathbackend(BufTagGetRelFileLocator(&buf->tag), backend, BufTagGetForkNum(&buf->tag)).str, @@ -4378,7 +4378,7 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object, instr_time io_start; Block bufBlock; char *bufToWrite; - uint32 buf_state; + uint64 buf_state; /* * Try to start an I/O operation. If StartBufferIO returns false, then @@ -4576,7 +4576,7 @@ BufferIsPermanent(Buffer buffer) * not random garbage. */ bufHdr = GetBufferDescriptor(buffer - 1); - return (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT) != 0; + return (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT) != 0; } /* @@ -5039,11 +5039,11 @@ FlushRelationBuffers(Relation rel) { for (i = 0; i < NLocBuffer; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetLocalBufferDescriptor(i); if (BufTagMatchesRelFileLocator(&bufHdr->tag, &rel->rd_locator) && - ((buf_state = pg_atomic_read_u32(&bufHdr->state)) & + ((buf_state = pg_atomic_read_u64(&bufHdr->state)) & (BM_VALID | BM_DIRTY)) == (BM_VALID | BM_DIRTY)) { ErrorContextCallback errcallback; @@ -5079,7 +5079,7 @@ FlushRelationBuffers(Relation rel) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5151,7 +5151,7 @@ FlushRelationsAllBuffers(SMgrRelation *smgrs, int nrels) { SMgrSortArray *srelent = NULL; BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; /* * As in DropRelationBuffers, an unlocked precheck should be safe and @@ -5400,7 +5400,7 @@ FlushDatabaseBuffers(Oid dbid) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5548,13 +5548,13 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * is only intended to be used in cases where failing to write out the * data would be harmless anyway, it doesn't really matter. */ - if ((pg_atomic_read_u32(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != + if ((pg_atomic_read_u64(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != (BM_DIRTY | BM_JUST_DIRTIED)) { XLogRecPtr lsn = InvalidXLogRecPtr; bool dirtied = false; bool delayChkptFlags = false; - uint32 buf_state; + uint64 buf_state; /* * If we need to protect hint bit updates from torn writes, WAL-log a @@ -5566,7 +5566,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * when we call XLogInsert() since the value changes dynamically. */ if (XLogHintBitIsNeeded() && - (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT)) + (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT)) { /* * If we must not write WAL, due to a relfilelocator-specific @@ -5666,8 +5666,8 @@ UnlockBuffers(void) if (buf) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; buf_state = LockBufHdr(buf); @@ -5798,8 +5798,8 @@ LockBufferForCleanup(Buffer buffer) for (;;) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; /* Try to acquire lock */ LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); @@ -5947,7 +5947,7 @@ bool ConditionalLockBufferForCleanup(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state, + uint64 buf_state, refcount; Assert(BufferIsValid(buffer)); @@ -6005,7 +6005,7 @@ bool IsBufferCleanupOK(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); @@ -6061,7 +6061,7 @@ WaitIO(BufferDesc *buf) ConditionVariablePrepareToSleep(cv); for (;;) { - uint32 buf_state; + uint64 buf_state; PgAioWaitRef iow; /* @@ -6135,7 +6135,7 @@ WaitIO(BufferDesc *buf) bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; ResourceOwnerEnlarge(CurrentResourceOwner); @@ -6191,11 +6191,11 @@ StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) * is being released) */ void -TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio) { - uint32 buf_state; - uint32 unset_flag_bits = 0; + uint64 buf_state; + uint64 unset_flag_bits = 0; int refcount_change = 0; buf_state = LockBufHdr(buf); @@ -6256,7 +6256,7 @@ static void AbortBufferIO(Buffer buffer) { BufferDesc *buf_hdr = GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; buf_state = LockBufHdr(buf_hdr); Assert(buf_state & (BM_IO_IN_PROGRESS | BM_TAG_VALID)); @@ -6350,10 +6350,10 @@ rlocator_comparator(const void *p1, const void *p2) /* * Lock buffer header - set BM_LOCKED in buffer state. */ -uint32 +uint64 LockBufHdr(BufferDesc *desc) { - uint32 old_buf_state; + uint64 old_buf_state; Assert(!BufferIsLocal(BufferDescriptorGetBuffer(desc))); @@ -6362,7 +6362,7 @@ LockBufHdr(BufferDesc *desc) * infrastructure. The work necessary for that shows up in profiles and is * rarely necessary. */ - old_buf_state = pg_atomic_fetch_or_u32(&desc->state, BM_LOCKED); + old_buf_state = pg_atomic_fetch_or_u64(&desc->state, BM_LOCKED); if (unlikely(old_buf_state & BM_LOCKED)) { @@ -6373,7 +6373,7 @@ LockBufHdr(BufferDesc *desc) while (true) { /* set BM_LOCKED flag */ - old_buf_state = pg_atomic_fetch_or_u32(&desc->state, BM_LOCKED); + old_buf_state = pg_atomic_fetch_or_u64(&desc->state, BM_LOCKED); /* if it wasn't set before we're OK */ if (!(old_buf_state & BM_LOCKED)) break; @@ -6392,20 +6392,20 @@ LockBufHdr(BufferDesc *desc) * Obviously the buffer could be locked by the time the value is returned, so * this is primarily useful in CAS style loops. */ -pg_noinline uint32 +pg_noinline uint64 WaitBufHdrUnlocked(BufferDesc *buf) { SpinDelayStatus delayStatus; - uint32 buf_state; + uint64 buf_state; init_local_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); while (buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); } finish_spin_delay(&delayStatus); @@ -6693,12 +6693,12 @@ ResOwnerPrintBufferPin(Datum res) static bool EvictUnpinnedBufferInternal(BufferDesc *desc, bool *buffer_flushed) { - uint32 buf_state; + uint64 buf_state; bool result; *buffer_flushed = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -6792,12 +6792,12 @@ EvictAllUnpinnedBuffers(int32 *buffers_evicted, int32 *buffers_flushed, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_flushed; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -6844,7 +6844,7 @@ EvictRelUnpinnedBuffers(Relation rel, int32 *buffers_evicted, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_flushed; CHECK_FOR_INTERRUPTS(); @@ -6886,12 +6886,12 @@ static bool MarkDirtyUnpinnedBufferInternal(Buffer buf, BufferDesc *desc, bool *buffer_already_dirty) { - uint32 buf_state; + uint64 buf_state; bool result = false; *buffer_already_dirty = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -6989,7 +6989,7 @@ MarkDirtyRelUnpinnedBuffers(Relation rel, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_already_dirty; CHECK_FOR_INTERRUPTS(); @@ -7043,12 +7043,12 @@ MarkDirtyAllUnpinnedBuffers(int32 *buffers_dirtied, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_already_dirty; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -7099,7 +7099,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) BufferDesc *buf_hdr = is_temp ? GetLocalBufferDescriptor(-buffer - 1) : GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; /* * Check that all the buffers are actually ones that could conceivably @@ -7117,7 +7117,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) } if (is_temp) - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); else buf_state = LockBufHdr(buf_hdr); @@ -7155,7 +7155,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) if (is_temp) { buf_state += BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else UnlockBufHdrExt(buf_hdr, buf_state, 0, 0, 1); @@ -7341,13 +7341,13 @@ buffer_readv_complete_one(PgAioTargetData *td, uint8 buf_off, Buffer buffer, : GetBufferDescriptor(buffer - 1); BufferTag tag = buf_hdr->tag; char *bufdata = BufferGetBlock(buffer); - uint32 set_flag_bits; + uint64 set_flag_bits; int piv_flags; /* check that the buffer is in the expected state for a read */ #ifdef USE_ASSERT_CHECKING { - uint32 buf_state = pg_atomic_read_u32(&buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_VALID)); diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c index 28d952b3534..1d4f19a9afd 100644 --- a/src/backend/storage/buffer/freelist.c +++ b/src/backend/storage/buffer/freelist.c @@ -86,7 +86,7 @@ typedef struct BufferAccessStrategyData /* Prototypes for internal functions */ static BufferDesc *GetBufferFromRing(BufferAccessStrategy strategy, - uint32 *buf_state); + uint64 *buf_state); static void AddBufferToRing(BufferAccessStrategy strategy, BufferDesc *buf); @@ -171,7 +171,7 @@ ClockSweepTick(void) * before returning. */ BufferDesc * -StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_ring) +StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_ring) { BufferDesc *buf; int bgwprocno; @@ -230,8 +230,8 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r trycounter = NBuffers; for (;;) { - uint32 old_buf_state; - uint32 local_buf_state; + uint64 old_buf_state; + uint64 local_buf_state; buf = GetBufferDescriptor(ClockSweepTick()); @@ -239,7 +239,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r * Check whether the buffer can be used and pin it if so. Do this * using a CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -277,7 +277,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r { local_buf_state -= BUF_USAGECOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { trycounter = NBuffers; @@ -289,7 +289,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { /* Found a usable buffer */ @@ -655,12 +655,12 @@ FreeAccessStrategy(BufferAccessStrategy strategy) * returning. */ static BufferDesc * -GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) +GetBufferFromRing(BufferAccessStrategy strategy, uint64 *buf_state) { BufferDesc *buf; Buffer bufnum; - uint32 old_buf_state; - uint32 local_buf_state; /* to avoid repeated (de-)referencing */ + uint64 old_buf_state; + uint64 local_buf_state; /* to avoid repeated (de-)referencing */ /* Advance to next ring slot */ @@ -682,7 +682,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) * Check whether the buffer can be used and pin it if so. Do this using a * CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -710,7 +710,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { *buf_state = local_buf_state; diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index 15aac7d1c9f..a41a5facd3a 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -148,7 +148,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, } else { - uint32 buf_state; + uint64 buf_state; victim_buffer = GetLocalVictimBuffer(); bufid = -victim_buffer - 1; @@ -165,10 +165,10 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, */ bufHdr->tag = newTag; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); buf_state &= ~(BUF_FLAG_MASK | BUF_USAGECOUNT_MASK); buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); *foundPtr = false; } @@ -245,12 +245,12 @@ GetLocalVictimBuffer(void) if (LocalRefCount[victim_bufid] == 0) { - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0) { buf_state -= BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); trycounter = NLocBuffer; } else if (BUF_STATE_GET_REFCOUNT(buf_state) > 0) @@ -286,13 +286,13 @@ GetLocalVictimBuffer(void) * this buffer is not referenced but it might still be dirty. if that's * the case, write it out before reusing it! */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY) FlushLocalBuffer(bufHdr, NULL); /* * Remove the victim buffer from the hashtable and mark as invalid. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID) + if (pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID) { InvalidateLocalBuffer(bufHdr, false); @@ -417,7 +417,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, if (found) { BufferDesc *existing_hdr; - uint32 buf_state; + uint64 buf_state; UnpinLocalBuffer(BufferDescriptorGetBuffer(victim_buf_hdr)); @@ -428,18 +428,18 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, /* * Clear the BM_VALID bit, do StartLocalBufferIO() and proceed. */ - buf_state = pg_atomic_read_u32(&existing_hdr->state); + buf_state = pg_atomic_read_u64(&existing_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_DIRTY)); buf_state &= ~BM_VALID; - pg_atomic_unlocked_write_u32(&existing_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&existing_hdr->state, buf_state); /* no need to loop for local buffers */ StartLocalBufferIO(existing_hdr, true, false); } else { - uint32 buf_state = pg_atomic_read_u32(&victim_buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&victim_buf_hdr->state); Assert(!(buf_state & (BM_VALID | BM_TAG_VALID | BM_DIRTY | BM_JUST_DIRTIED))); @@ -447,7 +447,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&victim_buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&victim_buf_hdr->state, buf_state); hresult->id = victim_buf_id; @@ -467,13 +467,13 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, { Buffer buf = buffers[i]; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); buf_state |= BM_VALID; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } *extended_by = extend_by; @@ -492,7 +492,7 @@ MarkLocalBufferDirty(Buffer buffer) { int bufid; BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsLocal(buffer)); @@ -506,14 +506,14 @@ MarkLocalBufferDirty(Buffer buffer) bufHdr = GetLocalBufferDescriptor(bufid); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_DIRTY)) pgBufferUsage.local_blks_dirtied++; buf_state |= BM_DIRTY; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -522,7 +522,7 @@ MarkLocalBufferDirty(Buffer buffer) bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; /* * With AIO the buffer could have IO in progress, e.g. when there are two @@ -542,7 +542,7 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) /* Once we get here, there is definitely no I/O active on this buffer */ /* Check if someone else already did the I/O */ - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (forInput ? (buf_state & BM_VALID) : !(buf_state & BM_DIRTY)) { return false; @@ -559,11 +559,11 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) * Like TerminateBufferIO, but for local buffers */ void -TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bits, +TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint64 set_flag_bits, bool release_aio) { /* Only need to adjust flags */ - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); /* BM_IO_IN_PROGRESS isn't currently used for local buffers */ @@ -582,7 +582,7 @@ TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bit } buf_state |= set_flag_bits; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); /* local buffers don't track IO using resowners */ @@ -606,7 +606,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) { Buffer buffer = BufferDescriptorGetBuffer(bufHdr); int bufid = -buffer - 1; - uint32 buf_state; + uint64 buf_state; LocalBufferLookupEnt *hresult; /* @@ -622,7 +622,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) Assert(!pgaio_wref_valid(&bufHdr->io_wref)); } - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* * We need to test not just LocalRefCount[bufid] but also the BufferDesc @@ -647,7 +647,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) ClearBufferTag(&bufHdr->tag); buf_state &= ~BUF_FLAG_MASK; buf_state &= ~BUF_USAGECOUNT_MASK; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -671,9 +671,9 @@ DropRelationLocalBuffers(RelFileLocator rlocator, ForkNumber *forkNum, for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_TAG_VALID) || !BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -706,9 +706,9 @@ DropRelationAllLocalBuffers(RelFileLocator rlocator) for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if ((buf_state & BM_TAG_VALID) && BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -804,11 +804,11 @@ InitLocalBuffers(void) bool PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { - uint32 buf_state; + uint64 buf_state; Buffer buffer = BufferDescriptorGetBuffer(buf_hdr); int bufid = -buffer - 1; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); if (LocalRefCount[bufid] == 0) { @@ -819,7 +819,7 @@ PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { buf_state += BUF_USAGECOUNT_ONE; } - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* * See comment in PinBuffer(). @@ -856,14 +856,14 @@ UnpinLocalBufferNoOwner(Buffer buffer) if (--LocalRefCount[buffid] == 0) { BufferDesc *buf_hdr = GetLocalBufferDescriptor(buffid); - uint32 buf_state; + uint64 buf_state; NLocalPinnedBuffers--; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state -= BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* see comment in UnpinBufferNoOwner */ VALGRIND_MAKE_MEM_NOACCESS(LocalBufHdrGetBlock(buf_hdr), BLCKSZ); diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index 702307a49e2..294caf7a1eb 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -199,7 +199,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) for (i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -615,7 +615,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -626,7 +626,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) * noticeably increase the cost of the function. */ bufHdr = GetBufferDescriptor(i); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (buf_state & BM_VALID) { @@ -676,7 +676,7 @@ pg_buffercache_usage_counts(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); int usage_count; CHECK_FOR_INTERRUPTS(); diff --git a/src/test/modules/test_aio/test_aio.c b/src/test/modules/test_aio/test_aio.c index d7eadeab256..488d98e7e66 100644 --- a/src/test/modules/test_aio/test_aio.c +++ b/src/test/modules/test_aio/test_aio.c @@ -308,9 +308,9 @@ create_toy_buffer(Relation rel, BlockNumber blkno) { Buffer buf; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; bool was_pinned = false; - uint32 unset_bits = 0; + uint64 unset_bits = 0; /* place buffer in shared buffers without erroring out */ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO_AND_LOCK, NULL); @@ -319,7 +319,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); } else { @@ -340,7 +340,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_state &= ~unset_bits; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else { @@ -489,7 +489,7 @@ invalidate_rel_block(PG_FUNCTION_ARGS) LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); - if (pg_atomic_read_u32(&buf_hdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&buf_hdr->state) & BM_DIRTY) { if (BufferIsLocal(buf)) FlushLocalBuffer(buf_hdr, NULL); @@ -572,7 +572,7 @@ buffer_call_terminate_io(PG_FUNCTION_ARGS) bool io_error = PG_GETARG_BOOL(3); bool release_aio = PG_GETARG_BOOL(4); bool clear_dirty = false; - uint32 set_flag_bits = 0; + uint64 set_flag_bits = 0; if (io_error) set_flag_bits |= BM_IO_ERROR; -- 2.48.1.76.g4e746b1a31.dirty --kad4mm4awdo7v2ki Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v7-0012-bufmgr-Implement-buffer-content-locks-independent.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v8 06/10] bufmgr: Change BufferDesc.state to be a 64bit atomic @ 2025-12-18 23:28 Andres Freund <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Andres Freund @ 2025-12-18 23:28 UTC (permalink / raw) This is motivated by wanting to merge buffer content locks into BufferDesc.state in a future commit, rather than having a separate lwlock (see commit c75ebc657ff more details). As this change is rather mechanical, it seems to make sense to split it out into a separate commit, for easier review. Reviewed-by: Melanie Plageman <[email protected]> Discussion: https://postgr.es/m/fvfmkr5kk4nyex56ejgxj3uzi63isfxovp2biecb4bspbjrze7@az2pljabhnff --- src/include/storage/buf_internals.h | 88 +++++---- src/include/storage/procnumber.h | 14 +- src/backend/storage/buffer/buf_init.c | 2 +- src/backend/storage/buffer/bufmgr.c | 170 +++++++++--------- src/backend/storage/buffer/freelist.c | 24 +-- src/backend/storage/buffer/localbuf.c | 72 ++++---- contrib/pg_buffercache/pg_buffercache_pages.c | 8 +- src/test/modules/test_aio/test_aio.c | 12 +- 8 files changed, 205 insertions(+), 185 deletions(-) diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index 5400c56a965..28519ad2813 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -30,7 +30,7 @@ #include "utils/resowner.h" /* - * Buffer state is a single 32-bit variable where following data is combined. + * Buffer state is a single 64-bit variable where following data is combined. * * - 18 bits refcount * - 4 bits usage count @@ -39,6 +39,9 @@ * Combining these values allows to perform some operations without locking * the buffer header, by modifying them together with a CAS loop. * + * NB: A future commit will use a significant portion of the remaining bits to + * implement buffer locking as part of the state variable. + * * The definition of buffer state components is below. */ #define BUF_REFCOUNT_BITS 18 @@ -49,15 +52,21 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, "parts of buffer state space need to equal 32"); #define BUF_REFCOUNT_ONE 1 -#define BUF_REFCOUNT_MASK ((1U << BUF_REFCOUNT_BITS) - 1) -#define BUF_USAGECOUNT_MASK (((1U << BUF_USAGECOUNT_BITS) - 1) << (BUF_REFCOUNT_BITS)) -#define BUF_USAGECOUNT_ONE (1U << BUF_REFCOUNT_BITS) +#define BUF_REFCOUNT_MASK \ + ((UINT64CONST(1) << BUF_REFCOUNT_BITS) - 1) +#define BUF_USAGECOUNT_MASK \ + (((UINT64CONST(1) << BUF_USAGECOUNT_BITS) - 1) << (BUF_REFCOUNT_BITS)) +#define BUF_USAGECOUNT_ONE \ + (UINT64CONST(1) << BUF_REFCOUNT_BITS) #define BUF_USAGECOUNT_SHIFT BUF_REFCOUNT_BITS -#define BUF_FLAG_MASK (((1U << BUF_FLAG_BITS) - 1) << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS)) +#define BUF_FLAG_MASK \ + (((UINT64CONST(1) << BUF_FLAG_BITS) - 1) << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS)) /* Get refcount and usagecount from buffer state */ -#define BUF_STATE_GET_REFCOUNT(state) ((state) & BUF_REFCOUNT_MASK) -#define BUF_STATE_GET_USAGECOUNT(state) (((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT) +#define BUF_STATE_GET_REFCOUNT(state) \ + ((uint32)((state) & BUF_REFCOUNT_MASK)) +#define BUF_STATE_GET_USAGECOUNT(state) \ + ((uint32)(((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT)) /* * Flags for buffer descriptors @@ -65,17 +74,28 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, * Note: BM_TAG_VALID essentially means that there is a buffer hashtable * entry associated with the buffer's tag. */ -#define BM_LOCKED (1U << 22) /* buffer header is locked */ -#define BM_DIRTY (1U << 23) /* data needs writing */ -#define BM_VALID (1U << 24) /* data is valid */ -#define BM_TAG_VALID (1U << 25) /* tag is assigned */ -#define BM_IO_IN_PROGRESS (1U << 26) /* read or write in progress */ -#define BM_IO_ERROR (1U << 27) /* previous I/O failed */ -#define BM_JUST_DIRTIED (1U << 28) /* dirtied since write started */ -#define BM_PIN_COUNT_WAITER (1U << 29) /* have waiter for sole pin */ -#define BM_CHECKPOINT_NEEDED (1U << 30) /* must write for checkpoint */ -#define BM_PERMANENT (1U << 31) /* permanent buffer (not unlogged, - * or init fork) */ + +/* buffer header is locked */ +#define BM_LOCKED (UINT64CONST(1) << 22) +/* data needs writing */ +#define BM_DIRTY (UINT64CONST(1) << 23) +/* data is valid */ +#define BM_VALID (UINT64CONST(1) << 24) +/* tag is assigned */ +#define BM_TAG_VALID (UINT64CONST(1) << 25) +/* read or write in progress */ +#define BM_IO_IN_PROGRESS (UINT64CONST(1) << 26) +/* previous I/O failed */ +#define BM_IO_ERROR (UINT64CONST(1) << 27) +/* dirtied since write started */ +#define BM_JUST_DIRTIED (UINT64CONST(1) << 28) +/* have waiter for sole pin */ +#define BM_PIN_COUNT_WAITER (UINT64CONST(1) << 29) +/* must write for checkpoint */ +#define BM_CHECKPOINT_NEEDED (UINT64CONST(1) << 30) +/* permanent buffer (not unlogged, or init fork) */ +#define BM_PERMANENT (UINT64CONST(1) << 31) + /* * The maximum allowed value of usage_count represents a tradeoff between * accuracy and speed of the clock-sweep buffer management algorithm. A @@ -86,7 +106,7 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, */ #define BM_MAX_USAGE_COUNT 5 -StaticAssertDecl(BM_MAX_USAGE_COUNT < (1 << BUF_USAGECOUNT_BITS), +StaticAssertDecl(BM_MAX_USAGE_COUNT < (UINT64CONST(1) << BUF_USAGECOUNT_BITS), "BM_MAX_USAGE_COUNT doesn't fit in BUF_USAGECOUNT_BITS bits"); StaticAssertDecl(MAX_BACKENDS_BITS <= BUF_REFCOUNT_BITS, "MAX_BACKENDS_BITS needs to be <= BUF_REFCOUNT_BITS"); @@ -251,8 +271,8 @@ BufMappingPartitionLockByIndex(uint32 index) * We use this same struct for local buffer headers, but the locks are not * used and not all of the flag bits are useful either. To avoid unnecessary * overhead, manipulations of the state field should be done without actual - * atomic operations (i.e. only pg_atomic_read_u32() and - * pg_atomic_unlocked_write_u32()). + * atomic operations (i.e. only pg_atomic_read_u64() and + * pg_atomic_unlocked_write_u64()). * * Be careful to avoid increasing the size of the struct when adding or * reordering members. Keeping it below 64 bytes (the most common CPU @@ -280,7 +300,7 @@ typedef struct BufferDesc * State of the buffer, containing flags, refcount and usagecount. See * BUF_* and BM_* defines at the top of this file. */ - pg_atomic_uint32 state; + pg_atomic_uint64 state; /* * Backend of pin-count waiter. The buffer header spinlock needs to be @@ -386,7 +406,7 @@ BufferDescriptorGetContentLock(const BufferDesc *bdesc) * Functions for acquiring/releasing a shared buffer header's spinlock. Do * not apply these to local buffers! */ -extern uint32 LockBufHdr(BufferDesc *desc); +extern uint64 LockBufHdr(BufferDesc *desc); /* * Unlock the buffer header. @@ -397,9 +417,9 @@ extern uint32 LockBufHdr(BufferDesc *desc); static inline void UnlockBufHdr(BufferDesc *desc) { - Assert(pg_atomic_read_u32(&desc->state) & BM_LOCKED); + Assert(pg_atomic_read_u64(&desc->state) & BM_LOCKED); - pg_atomic_fetch_sub_u32(&desc->state, BM_LOCKED); + pg_atomic_fetch_sub_u64(&desc->state, BM_LOCKED); } /* @@ -410,14 +430,14 @@ UnlockBufHdr(BufferDesc *desc) * Note that this approach would not work for usagecount, since we need to cap * the usagecount at BM_MAX_USAGE_COUNT. */ -static inline uint32 -UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, - uint32 set_bits, uint32 unset_bits, +static inline uint64 +UnlockBufHdrExt(BufferDesc *desc, uint64 old_buf_state, + uint64 set_bits, uint64 unset_bits, int refcount_change) { for (;;) { - uint32 buf_state = old_buf_state; + uint64 buf_state = old_buf_state; Assert(buf_state & BM_LOCKED); @@ -428,7 +448,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, if (refcount_change != 0) buf_state += BUF_REFCOUNT_ONE * refcount_change; - if (pg_atomic_compare_exchange_u32(&desc->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&desc->state, &old_buf_state, buf_state)) { return old_buf_state; @@ -436,7 +456,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, } } -extern uint32 WaitBufHdrUnlocked(BufferDesc *buf); +extern uint64 WaitBufHdrUnlocked(BufferDesc *buf); /* in bufmgr.c */ @@ -496,14 +516,14 @@ extern void TrackNewBufferPin(Buffer buf); /* solely to make it easier to write tests */ extern bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait); -extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio); /* freelist.c */ extern IOContext IOContextForStrategy(BufferAccessStrategy strategy); extern BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy, - uint32 *buf_state, bool *from_ring); + uint64 *buf_state, bool *from_ring); extern bool StrategyRejectBuffer(BufferAccessStrategy strategy, BufferDesc *buf, bool from_ring); @@ -539,7 +559,7 @@ extern BlockNumber ExtendBufferedRelLocal(BufferManagerRelation bmr, uint32 *extended_by); extern void MarkLocalBufferDirty(Buffer buffer); extern void TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, - uint32 set_flag_bits, bool release_aio); + uint64 set_flag_bits, bool release_aio); extern bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait); extern void FlushLocalBuffer(BufferDesc *bufHdr, SMgrRelation reln); extern void InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced); diff --git a/src/include/storage/procnumber.h b/src/include/storage/procnumber.h index 2ddaaf0c646..6baac7c77f1 100644 --- a/src/include/storage/procnumber.h +++ b/src/include/storage/procnumber.h @@ -27,13 +27,13 @@ typedef int ProcNumber; /* * Note: MAX_BACKENDS_BITS is 18 as that is the space available for buffer - * refcounts in buf_internals.h. This limitation could be lifted by using a - * 64bit state; but it's unlikely to be worthwhile as 2^18-1 backends exceed - * currently realistic configurations. Even if that limitation were removed, - * we still could not a) exceed 2^23-1 because inval.c stores the ProcNumber - * as a 3-byte signed integer, b) INT_MAX/4 because some places compute - * 4*MaxBackends without any overflow check. We check that the configured - * number of backends does not exceed MAX_BACKENDS in InitializeMaxBackends(). + * refcounts in buf_internals.h. This limitation could be lifted, but it's + * unlikely to be worthwhile as 2^18-1 backends exceed currently realistic + * configurations. Even if that limitation were removed, we still could not a) + * exceed 2^23-1 because inval.c stores the ProcNumber as a 3-byte signed + * integer, b) INT_MAX/4 because some places compute 4*MaxBackends without any + * overflow check. We check that the configured number of backends does not + * exceed MAX_BACKENDS in InitializeMaxBackends(). */ #define MAX_BACKENDS_BITS 18 #define MAX_BACKENDS ((1U << MAX_BACKENDS_BITS)-1) diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index 6fd3a6bbac5..25f71191ec3 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -121,7 +121,7 @@ BufferManagerShmemInit(void) ClearBufferTag(&buf->tag); - pg_atomic_init_u32(&buf->state, 0); + pg_atomic_init_u64(&buf->state, 0); buf->wait_backend_pgprocno = INVALID_PROC_NUMBER; buf->buf_id = i; diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index eb55102b0d7..03d99d294d5 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -780,7 +780,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN { BufferDesc *bufHdr; BufferTag tag; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(recent_buffer)); @@ -793,7 +793,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN int b = -recent_buffer - 1; bufHdr = GetLocalBufferDescriptor(b); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* Is it still valid and holding the right tag? */ if ((buf_state & BM_VALID) && BufferTagsEqual(&tag, &bufHdr->tag)) @@ -1386,8 +1386,8 @@ StartReadBuffersImpl(ReadBuffersOperation *operation, bufHdr = GetLocalBufferDescriptor(-buffers[i] - 1); else bufHdr = GetBufferDescriptor(buffers[i] - 1); - Assert(pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID); - found = pg_atomic_read_u32(&bufHdr->state) & BM_VALID; + Assert(pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID); + found = pg_atomic_read_u64(&bufHdr->state) & BM_VALID; } else { @@ -1613,10 +1613,10 @@ CheckReadBuffersOperation(ReadBuffersOperation *operation, bool is_complete) GetBufferDescriptor(buffer - 1); Assert(BufferGetBlockNumber(buffer) == operation->blocknum + i); - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_TAG_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_TAG_VALID); if (i < operation->nblocks_done) - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_VALID); } #endif } @@ -2083,8 +2083,8 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, int existing_buf_id; Buffer victim_buffer; BufferDesc *victim_buf_hdr; - uint32 victim_buf_state; - uint32 set_bits = 0; + uint64 victim_buf_state; + uint64 set_bits = 0; /* Make sure we will have room to remember the buffer pin */ ResourceOwnerEnlarge(CurrentResourceOwner); @@ -2251,7 +2251,7 @@ InvalidateBuffer(BufferDesc *buf) uint32 oldHash; /* hash value for oldTag */ LWLock *oldPartitionLock; /* buffer partition lock for it */ uint32 oldFlags; - uint32 buf_state; + uint64 buf_state; /* Save the original buffer tag before dropping the spinlock */ oldTag = buf->tag; @@ -2342,7 +2342,7 @@ retry: static bool InvalidateVictimBuffer(BufferDesc *buf_hdr) { - uint32 buf_state; + uint64 buf_state; uint32 hash; LWLock *partition_lock; BufferTag tag; @@ -2402,10 +2402,10 @@ InvalidateVictimBuffer(BufferDesc *buf_hdr) LWLockRelease(partition_lock); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(!(buf_state & (BM_DIRTY | BM_VALID | BM_TAG_VALID))); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); - Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u32(&buf_hdr->state)) > 0); + Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u64(&buf_hdr->state)) > 0); return true; } @@ -2415,7 +2415,7 @@ GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context) { BufferDesc *buf_hdr; Buffer buf; - uint32 buf_state; + uint64 buf_state; bool from_ring; /* @@ -2548,7 +2548,7 @@ again: /* a final set of sanity checks */ #ifdef USE_ASSERT_CHECKING - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) == 1); Assert(!(buf_state & (BM_TAG_VALID | BM_VALID | BM_DIRTY))); @@ -2839,13 +2839,13 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, */ do { - pg_atomic_fetch_and_u32(&existing_hdr->state, ~BM_VALID); + pg_atomic_fetch_and_u64(&existing_hdr->state, ~BM_VALID); } while (!StartBufferIO(existing_hdr, true, false)); } else { - uint32 buf_state; - uint32 set_bits = 0; + uint64 buf_state; + uint64 set_bits = 0; buf_state = LockBufHdr(victim_buf_hdr); @@ -3021,7 +3021,7 @@ BufferIsDirty(Buffer buffer) Assert(BufferIsLockedByMeInMode(buffer, BUFFER_LOCK_EXCLUSIVE)); } - return pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY; + return pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY; } /* @@ -3037,8 +3037,8 @@ void MarkBufferDirty(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; if (!BufferIsValid(buffer)) elog(ERROR, "bad buffer ID: %d", buffer); @@ -3058,7 +3058,7 @@ MarkBufferDirty(Buffer buffer) * NB: We have to wait for the buffer header spinlock to be not held, as * TerminateBufferIO() relies on the spinlock. */ - old_buf_state = pg_atomic_read_u32(&bufHdr->state); + old_buf_state = pg_atomic_read_u64(&bufHdr->state); for (;;) { if (old_buf_state & BM_LOCKED) @@ -3069,7 +3069,7 @@ MarkBufferDirty(Buffer buffer) Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state |= BM_DIRTY | BM_JUST_DIRTIED; - if (pg_atomic_compare_exchange_u32(&bufHdr->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&bufHdr->state, &old_buf_state, buf_state)) break; } @@ -3173,10 +3173,10 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, if (ref == NULL) { - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { if (unlikely(skip_if_not_valid && !(old_buf_state & BM_VALID))) @@ -3210,7 +3210,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, buf_state += BUF_USAGECOUNT_ONE; } - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, buf_state)) { result = (buf_state & BM_VALID) != 0; @@ -3237,7 +3237,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, * that the buffer page is legitimately non-accessible here. We * cannot meddle with that. */ - result = (pg_atomic_read_u32(&buf->state) & BM_VALID) != 0; + result = (pg_atomic_read_u64(&buf->state) & BM_VALID) != 0; Assert(ref->data.refcount > 0); ref->data.refcount++; @@ -3272,7 +3272,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, static void PinBuffer_Locked(BufferDesc *buf) { - uint32 old_buf_state; + uint64 old_buf_state; /* * As explained, We don't expect any preexisting pins. That allows us to @@ -3284,7 +3284,7 @@ PinBuffer_Locked(BufferDesc *buf) * Since we hold the buffer spinlock, we can update the buffer state and * release the lock in one operation. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); UnlockBufHdrExt(buf, old_buf_state, 0, 0, 1); @@ -3314,7 +3314,7 @@ WakePinCountWaiter(BufferDesc *buf) * BM_PIN_COUNT_WAITER if it stops waiting for a reason other than this * backend waking it up. */ - uint32 buf_state = LockBufHdr(buf); + uint64 buf_state = LockBufHdr(buf); if ((buf_state & BM_PIN_COUNT_WAITER) && BUF_STATE_GET_REFCOUNT(buf_state) == 1) @@ -3361,7 +3361,7 @@ UnpinBufferNoOwner(BufferDesc *buf) ref->data.refcount--; if (ref->data.refcount == 0) { - uint32 old_buf_state; + uint64 old_buf_state; /* * Mark buffer non-accessible to Valgrind. @@ -3379,7 +3379,7 @@ UnpinBufferNoOwner(BufferDesc *buf) Assert(!LWLockHeldByMe(BufferDescriptorGetContentLock(buf))); /* decrement the shared reference count */ - old_buf_state = pg_atomic_fetch_sub_u32(&buf->state, BUF_REFCOUNT_ONE); + old_buf_state = pg_atomic_fetch_sub_u64(&buf->state, BUF_REFCOUNT_ONE); /* Support LockBufferForCleanup() */ if (old_buf_state & BM_PIN_COUNT_WAITER) @@ -3436,7 +3436,7 @@ TrackNewBufferPin(Buffer buf) static void BufferSync(int flags) { - uint32 buf_state; + uint64 buf_state; int buf_id; int num_to_scan; int num_spaces; @@ -3446,7 +3446,7 @@ BufferSync(int flags) Oid last_tsid; binaryheap *ts_heap; int i; - uint32 mask = BM_DIRTY; + uint64 mask = BM_DIRTY; WritebackContext wb_context; /* @@ -3478,7 +3478,7 @@ BufferSync(int flags) for (buf_id = 0; buf_id < NBuffers; buf_id++) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); - uint32 set_bits = 0; + uint64 set_bits = 0; /* * Header spinlock is enough to examine BM_DIRTY, see comment in @@ -3645,7 +3645,7 @@ BufferSync(int flags) * write the buffer though we didn't need to. It doesn't seem worth * guarding against this, though. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_CHECKPOINT_NEEDED) + if (pg_atomic_read_u64(&bufHdr->state) & BM_CHECKPOINT_NEEDED) { if (SyncOneBuffer(buf_id, false, &wb_context) & BUF_WRITTEN) { @@ -4015,7 +4015,7 @@ SyncOneBuffer(int buf_id, bool skip_recently_used, WritebackContext *wb_context) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); int result = 0; - uint32 buf_state; + uint64 buf_state; BufferTag tag; /* Make sure we can handle the pin */ @@ -4264,7 +4264,7 @@ DebugPrintBufferRefcount(Buffer buffer) int32 loccount; char *result; ProcNumber backend; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); if (BufferIsLocal(buffer)) @@ -4281,9 +4281,9 @@ DebugPrintBufferRefcount(Buffer buffer) } /* theoretically we should lock the bufhdr here */ - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); - result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%x, refcount=%u %d)", + result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%" PRIx64 ", refcount=%u %d)", buffer, relpathbackend(BufTagGetRelFileLocator(&buf->tag), backend, BufTagGetForkNum(&buf->tag)).str, @@ -4383,7 +4383,7 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object, instr_time io_start; Block bufBlock; char *bufToWrite; - uint32 buf_state; + uint64 buf_state; /* * Try to start an I/O operation. If StartBufferIO returns false, then @@ -4581,7 +4581,7 @@ BufferIsPermanent(Buffer buffer) * not random garbage. */ bufHdr = GetBufferDescriptor(buffer - 1); - return (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT) != 0; + return (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT) != 0; } /* @@ -5044,11 +5044,11 @@ FlushRelationBuffers(Relation rel) { for (i = 0; i < NLocBuffer; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetLocalBufferDescriptor(i); if (BufTagMatchesRelFileLocator(&bufHdr->tag, &rel->rd_locator) && - ((buf_state = pg_atomic_read_u32(&bufHdr->state)) & + ((buf_state = pg_atomic_read_u64(&bufHdr->state)) & (BM_VALID | BM_DIRTY)) == (BM_VALID | BM_DIRTY)) { ErrorContextCallback errcallback; @@ -5084,7 +5084,7 @@ FlushRelationBuffers(Relation rel) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5156,7 +5156,7 @@ FlushRelationsAllBuffers(SMgrRelation *smgrs, int nrels) { SMgrSortArray *srelent = NULL; BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; /* * As in DropRelationBuffers, an unlocked precheck should be safe and @@ -5405,7 +5405,7 @@ FlushDatabaseBuffers(Oid dbid) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5553,13 +5553,13 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * is only intended to be used in cases where failing to write out the * data would be harmless anyway, it doesn't really matter. */ - if ((pg_atomic_read_u32(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != + if ((pg_atomic_read_u64(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != (BM_DIRTY | BM_JUST_DIRTIED)) { XLogRecPtr lsn = InvalidXLogRecPtr; bool dirtied = false; bool delayChkptFlags = false; - uint32 buf_state; + uint64 buf_state; /* * If we need to protect hint bit updates from torn writes, WAL-log a @@ -5571,7 +5571,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * when we call XLogInsert() since the value changes dynamically. */ if (XLogHintBitIsNeeded() && - (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT)) + (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT)) { /* * If we must not write WAL, due to a relfilelocator-specific @@ -5671,8 +5671,8 @@ UnlockBuffers(void) if (buf) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; buf_state = LockBufHdr(buf); @@ -5803,8 +5803,8 @@ LockBufferForCleanup(Buffer buffer) for (;;) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; /* Try to acquire lock */ LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); @@ -5952,7 +5952,7 @@ bool ConditionalLockBufferForCleanup(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state, + uint64 buf_state, refcount; Assert(BufferIsValid(buffer)); @@ -6010,7 +6010,7 @@ bool IsBufferCleanupOK(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); @@ -6066,7 +6066,7 @@ WaitIO(BufferDesc *buf) ConditionVariablePrepareToSleep(cv); for (;;) { - uint32 buf_state; + uint64 buf_state; PgAioWaitRef iow; /* @@ -6140,7 +6140,7 @@ WaitIO(BufferDesc *buf) bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; ResourceOwnerEnlarge(CurrentResourceOwner); @@ -6196,11 +6196,11 @@ StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) * is being released) */ void -TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio) { - uint32 buf_state; - uint32 unset_flag_bits = 0; + uint64 buf_state; + uint64 unset_flag_bits = 0; int refcount_change = 0; buf_state = LockBufHdr(buf); @@ -6261,7 +6261,7 @@ static void AbortBufferIO(Buffer buffer) { BufferDesc *buf_hdr = GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; buf_state = LockBufHdr(buf_hdr); Assert(buf_state & (BM_IO_IN_PROGRESS | BM_TAG_VALID)); @@ -6355,10 +6355,10 @@ rlocator_comparator(const void *p1, const void *p2) /* * Lock buffer header - set BM_LOCKED in buffer state. */ -uint32 +uint64 LockBufHdr(BufferDesc *desc) { - uint32 old_buf_state; + uint64 old_buf_state; Assert(!BufferIsLocal(BufferDescriptorGetBuffer(desc))); @@ -6369,7 +6369,7 @@ LockBufHdr(BufferDesc *desc) * the spin-delay infrastructure. The work necessary for that shows up * in profiles and is rarely necessary. */ - old_buf_state = pg_atomic_fetch_or_u32(&desc->state, BM_LOCKED); + old_buf_state = pg_atomic_fetch_or_u64(&desc->state, BM_LOCKED); if (likely(!(old_buf_state & BM_LOCKED))) break; /* got lock */ @@ -6382,7 +6382,7 @@ LockBufHdr(BufferDesc *desc) while (old_buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - old_buf_state = pg_atomic_read_u32(&desc->state); + old_buf_state = pg_atomic_read_u64(&desc->state); } finish_spin_delay(&delayStatus); } @@ -6403,20 +6403,20 @@ LockBufHdr(BufferDesc *desc) * Obviously the buffer could be locked by the time the value is returned, so * this is primarily useful in CAS style loops. */ -pg_noinline uint32 +pg_noinline uint64 WaitBufHdrUnlocked(BufferDesc *buf) { SpinDelayStatus delayStatus; - uint32 buf_state; + uint64 buf_state; init_local_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); while (buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); } finish_spin_delay(&delayStatus); @@ -6704,12 +6704,12 @@ ResOwnerPrintBufferPin(Datum res) static bool EvictUnpinnedBufferInternal(BufferDesc *desc, bool *buffer_flushed) { - uint32 buf_state; + uint64 buf_state; bool result; *buffer_flushed = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -6803,12 +6803,12 @@ EvictAllUnpinnedBuffers(int32 *buffers_evicted, int32 *buffers_flushed, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_flushed; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -6855,7 +6855,7 @@ EvictRelUnpinnedBuffers(Relation rel, int32 *buffers_evicted, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_flushed; CHECK_FOR_INTERRUPTS(); @@ -6897,12 +6897,12 @@ static bool MarkDirtyUnpinnedBufferInternal(Buffer buf, BufferDesc *desc, bool *buffer_already_dirty) { - uint32 buf_state; + uint64 buf_state; bool result = false; *buffer_already_dirty = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -7000,7 +7000,7 @@ MarkDirtyRelUnpinnedBuffers(Relation rel, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_already_dirty; CHECK_FOR_INTERRUPTS(); @@ -7054,12 +7054,12 @@ MarkDirtyAllUnpinnedBuffers(int32 *buffers_dirtied, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_already_dirty; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -7110,7 +7110,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) BufferDesc *buf_hdr = is_temp ? GetLocalBufferDescriptor(-buffer - 1) : GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; /* * Check that all the buffers are actually ones that could conceivably @@ -7128,7 +7128,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) } if (is_temp) - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); else buf_state = LockBufHdr(buf_hdr); @@ -7166,7 +7166,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) if (is_temp) { buf_state += BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else UnlockBufHdrExt(buf_hdr, buf_state, 0, 0, 1); @@ -7352,13 +7352,13 @@ buffer_readv_complete_one(PgAioTargetData *td, uint8 buf_off, Buffer buffer, : GetBufferDescriptor(buffer - 1); BufferTag tag = buf_hdr->tag; char *bufdata = BufferGetBlock(buffer); - uint32 set_flag_bits; + uint64 set_flag_bits; int piv_flags; /* check that the buffer is in the expected state for a read */ #ifdef USE_ASSERT_CHECKING { - uint32 buf_state = pg_atomic_read_u32(&buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_VALID)); diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c index 28d952b3534..1d4f19a9afd 100644 --- a/src/backend/storage/buffer/freelist.c +++ b/src/backend/storage/buffer/freelist.c @@ -86,7 +86,7 @@ typedef struct BufferAccessStrategyData /* Prototypes for internal functions */ static BufferDesc *GetBufferFromRing(BufferAccessStrategy strategy, - uint32 *buf_state); + uint64 *buf_state); static void AddBufferToRing(BufferAccessStrategy strategy, BufferDesc *buf); @@ -171,7 +171,7 @@ ClockSweepTick(void) * before returning. */ BufferDesc * -StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_ring) +StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_ring) { BufferDesc *buf; int bgwprocno; @@ -230,8 +230,8 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r trycounter = NBuffers; for (;;) { - uint32 old_buf_state; - uint32 local_buf_state; + uint64 old_buf_state; + uint64 local_buf_state; buf = GetBufferDescriptor(ClockSweepTick()); @@ -239,7 +239,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r * Check whether the buffer can be used and pin it if so. Do this * using a CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -277,7 +277,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r { local_buf_state -= BUF_USAGECOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { trycounter = NBuffers; @@ -289,7 +289,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { /* Found a usable buffer */ @@ -655,12 +655,12 @@ FreeAccessStrategy(BufferAccessStrategy strategy) * returning. */ static BufferDesc * -GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) +GetBufferFromRing(BufferAccessStrategy strategy, uint64 *buf_state) { BufferDesc *buf; Buffer bufnum; - uint32 old_buf_state; - uint32 local_buf_state; /* to avoid repeated (de-)referencing */ + uint64 old_buf_state; + uint64 local_buf_state; /* to avoid repeated (de-)referencing */ /* Advance to next ring slot */ @@ -682,7 +682,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) * Check whether the buffer can be used and pin it if so. Do this using a * CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -710,7 +710,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { *buf_state = local_buf_state; diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index 15aac7d1c9f..a41a5facd3a 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -148,7 +148,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, } else { - uint32 buf_state; + uint64 buf_state; victim_buffer = GetLocalVictimBuffer(); bufid = -victim_buffer - 1; @@ -165,10 +165,10 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, */ bufHdr->tag = newTag; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); buf_state &= ~(BUF_FLAG_MASK | BUF_USAGECOUNT_MASK); buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); *foundPtr = false; } @@ -245,12 +245,12 @@ GetLocalVictimBuffer(void) if (LocalRefCount[victim_bufid] == 0) { - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0) { buf_state -= BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); trycounter = NLocBuffer; } else if (BUF_STATE_GET_REFCOUNT(buf_state) > 0) @@ -286,13 +286,13 @@ GetLocalVictimBuffer(void) * this buffer is not referenced but it might still be dirty. if that's * the case, write it out before reusing it! */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY) FlushLocalBuffer(bufHdr, NULL); /* * Remove the victim buffer from the hashtable and mark as invalid. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID) + if (pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID) { InvalidateLocalBuffer(bufHdr, false); @@ -417,7 +417,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, if (found) { BufferDesc *existing_hdr; - uint32 buf_state; + uint64 buf_state; UnpinLocalBuffer(BufferDescriptorGetBuffer(victim_buf_hdr)); @@ -428,18 +428,18 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, /* * Clear the BM_VALID bit, do StartLocalBufferIO() and proceed. */ - buf_state = pg_atomic_read_u32(&existing_hdr->state); + buf_state = pg_atomic_read_u64(&existing_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_DIRTY)); buf_state &= ~BM_VALID; - pg_atomic_unlocked_write_u32(&existing_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&existing_hdr->state, buf_state); /* no need to loop for local buffers */ StartLocalBufferIO(existing_hdr, true, false); } else { - uint32 buf_state = pg_atomic_read_u32(&victim_buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&victim_buf_hdr->state); Assert(!(buf_state & (BM_VALID | BM_TAG_VALID | BM_DIRTY | BM_JUST_DIRTIED))); @@ -447,7 +447,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&victim_buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&victim_buf_hdr->state, buf_state); hresult->id = victim_buf_id; @@ -467,13 +467,13 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, { Buffer buf = buffers[i]; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); buf_state |= BM_VALID; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } *extended_by = extend_by; @@ -492,7 +492,7 @@ MarkLocalBufferDirty(Buffer buffer) { int bufid; BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsLocal(buffer)); @@ -506,14 +506,14 @@ MarkLocalBufferDirty(Buffer buffer) bufHdr = GetLocalBufferDescriptor(bufid); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_DIRTY)) pgBufferUsage.local_blks_dirtied++; buf_state |= BM_DIRTY; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -522,7 +522,7 @@ MarkLocalBufferDirty(Buffer buffer) bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; /* * With AIO the buffer could have IO in progress, e.g. when there are two @@ -542,7 +542,7 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) /* Once we get here, there is definitely no I/O active on this buffer */ /* Check if someone else already did the I/O */ - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (forInput ? (buf_state & BM_VALID) : !(buf_state & BM_DIRTY)) { return false; @@ -559,11 +559,11 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) * Like TerminateBufferIO, but for local buffers */ void -TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bits, +TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint64 set_flag_bits, bool release_aio) { /* Only need to adjust flags */ - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); /* BM_IO_IN_PROGRESS isn't currently used for local buffers */ @@ -582,7 +582,7 @@ TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bit } buf_state |= set_flag_bits; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); /* local buffers don't track IO using resowners */ @@ -606,7 +606,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) { Buffer buffer = BufferDescriptorGetBuffer(bufHdr); int bufid = -buffer - 1; - uint32 buf_state; + uint64 buf_state; LocalBufferLookupEnt *hresult; /* @@ -622,7 +622,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) Assert(!pgaio_wref_valid(&bufHdr->io_wref)); } - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* * We need to test not just LocalRefCount[bufid] but also the BufferDesc @@ -647,7 +647,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) ClearBufferTag(&bufHdr->tag); buf_state &= ~BUF_FLAG_MASK; buf_state &= ~BUF_USAGECOUNT_MASK; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -671,9 +671,9 @@ DropRelationLocalBuffers(RelFileLocator rlocator, ForkNumber *forkNum, for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_TAG_VALID) || !BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -706,9 +706,9 @@ DropRelationAllLocalBuffers(RelFileLocator rlocator) for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if ((buf_state & BM_TAG_VALID) && BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -804,11 +804,11 @@ InitLocalBuffers(void) bool PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { - uint32 buf_state; + uint64 buf_state; Buffer buffer = BufferDescriptorGetBuffer(buf_hdr); int bufid = -buffer - 1; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); if (LocalRefCount[bufid] == 0) { @@ -819,7 +819,7 @@ PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { buf_state += BUF_USAGECOUNT_ONE; } - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* * See comment in PinBuffer(). @@ -856,14 +856,14 @@ UnpinLocalBufferNoOwner(Buffer buffer) if (--LocalRefCount[buffid] == 0) { BufferDesc *buf_hdr = GetLocalBufferDescriptor(buffid); - uint32 buf_state; + uint64 buf_state; NLocalPinnedBuffers--; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state -= BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* see comment in UnpinBufferNoOwner */ VALGRIND_MAKE_MEM_NOACCESS(LocalBufHdrGetBlock(buf_hdr), BLCKSZ); diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index 0c58e4b265c..529803346ce 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -199,7 +199,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) for (i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -615,7 +615,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -626,7 +626,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) * noticeably increase the cost of the function. */ bufHdr = GetBufferDescriptor(i); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (buf_state & BM_VALID) { @@ -676,7 +676,7 @@ pg_buffercache_usage_counts(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); int usage_count; CHECK_FOR_INTERRUPTS(); diff --git a/src/test/modules/test_aio/test_aio.c b/src/test/modules/test_aio/test_aio.c index d7eadeab256..488d98e7e66 100644 --- a/src/test/modules/test_aio/test_aio.c +++ b/src/test/modules/test_aio/test_aio.c @@ -308,9 +308,9 @@ create_toy_buffer(Relation rel, BlockNumber blkno) { Buffer buf; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; bool was_pinned = false; - uint32 unset_bits = 0; + uint64 unset_bits = 0; /* place buffer in shared buffers without erroring out */ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO_AND_LOCK, NULL); @@ -319,7 +319,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); } else { @@ -340,7 +340,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_state &= ~unset_bits; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else { @@ -489,7 +489,7 @@ invalidate_rel_block(PG_FUNCTION_ARGS) LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); - if (pg_atomic_read_u32(&buf_hdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&buf_hdr->state) & BM_DIRTY) { if (BufferIsLocal(buf)) FlushLocalBuffer(buf_hdr, NULL); @@ -572,7 +572,7 @@ buffer_call_terminate_io(PG_FUNCTION_ARGS) bool io_error = PG_GETARG_BOOL(3); bool release_aio = PG_GETARG_BOOL(4); bool clear_dirty = false; - uint32 set_flag_bits = 0; + uint64 set_flag_bits = 0; if (io_error) set_flag_bits |= BM_IO_ERROR; -- 2.48.1.76.g4e746b1a31.dirty --lbbj3oq7cjvyhmbk Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v8-0007-bufmgr-Implement-buffer-content-locks-independent.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v9 06/10] bufmgr: Change BufferDesc.state to be a 64bit atomic @ 2026-01-07 22:26 Andres Freund <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Andres Freund @ 2026-01-07 22:26 UTC (permalink / raw) This is motivated by wanting to merge buffer content locks into BufferDesc.state in a future commit, rather than having a separate lwlock (see commit c75ebc657ff more details). As this change is rather mechanical, it seems to make sense to split it out into a separate commit, for easier review. Reviewed-by: Melanie Plageman <[email protected]> Discussion: https://postgr.es/m/fvfmkr5kk4nyex56ejgxj3uzi63isfxovp2biecb4bspbjrze7@az2pljabhnff --- src/include/storage/buf_internals.h | 51 +++--- src/include/storage/procnumber.h | 14 +- src/backend/storage/buffer/buf_init.c | 2 +- src/backend/storage/buffer/bufmgr.c | 170 +++++++++--------- src/backend/storage/buffer/freelist.c | 24 +-- src/backend/storage/buffer/localbuf.c | 72 ++++---- contrib/pg_buffercache/pg_buffercache_pages.c | 8 +- src/test/modules/test_aio/test_aio.c | 12 +- 8 files changed, 178 insertions(+), 175 deletions(-) diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index 2f607ea2ac5..a4d36e9ca01 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -30,7 +30,7 @@ #include "utils/resowner.h" /* - * Buffer state is a single 32-bit variable where following data is combined. + * Buffer state is a single 64-bit variable where following data is combined. * * State of the buffer itself (in order): * - 18 bits refcount @@ -40,6 +40,9 @@ * Combining these values allows to perform some operations without locking * the buffer header, by modifying them together with a CAS loop. * + * NB: A future commit will use a significant portion of the remaining bits to + * implement buffer locking as part of the state variable. + * * The definition of buffer state components is below. */ #define BUF_REFCOUNT_BITS 18 @@ -52,27 +55,27 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, /* refcount related definitions */ #define BUF_REFCOUNT_ONE 1 #define BUF_REFCOUNT_MASK \ - ((1U << BUF_REFCOUNT_BITS) - 1) + ((UINT64CONST(1) << BUF_REFCOUNT_BITS) - 1) /* usage count related definitions */ #define BUF_USAGECOUNT_SHIFT \ BUF_REFCOUNT_BITS #define BUF_USAGECOUNT_MASK \ - (((1U << BUF_USAGECOUNT_BITS) - 1) << (BUF_USAGECOUNT_SHIFT)) + (((UINT64CONST(1) << BUF_USAGECOUNT_BITS) - 1) << (BUF_USAGECOUNT_SHIFT)) #define BUF_USAGECOUNT_ONE \ - (1U << BUF_REFCOUNT_BITS) + (UINT64CONST(1) << BUF_REFCOUNT_BITS) /* flags related definitions */ #define BUF_FLAG_SHIFT \ (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS) #define BUF_FLAG_MASK \ - (((1U << BUF_FLAG_BITS) - 1) << BUF_FLAG_SHIFT) + (((UINT64CONST(1) << BUF_FLAG_BITS) - 1) << BUF_FLAG_SHIFT) /* Get refcount and usagecount from buffer state */ #define BUF_STATE_GET_REFCOUNT(state) \ - ((state) & BUF_REFCOUNT_MASK) + ((uint32)((state) & BUF_REFCOUNT_MASK)) #define BUF_STATE_GET_USAGECOUNT(state) \ - (((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT) + ((uint32)(((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT)) /* * Flags for buffer descriptors @@ -82,7 +85,7 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, */ #define BUF_DEFINE_FLAG(flagno) \ - (1U << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + (flagno))) + (UINT64CONST(1) << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + (flagno))) /* buffer header is locked */ #define BM_LOCKED BUF_DEFINE_FLAG( 0) @@ -115,7 +118,7 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, */ #define BM_MAX_USAGE_COUNT 5 -StaticAssertDecl(BM_MAX_USAGE_COUNT < (1 << BUF_USAGECOUNT_BITS), +StaticAssertDecl(BM_MAX_USAGE_COUNT < (UINT64CONST(1) << BUF_USAGECOUNT_BITS), "BM_MAX_USAGE_COUNT doesn't fit in BUF_USAGECOUNT_BITS bits"); StaticAssertDecl(MAX_BACKENDS_BITS <= BUF_REFCOUNT_BITS, "MAX_BACKENDS_BITS needs to be <= BUF_REFCOUNT_BITS"); @@ -280,8 +283,8 @@ BufMappingPartitionLockByIndex(uint32 index) * We use this same struct for local buffer headers, but the locks are not * used and not all of the flag bits are useful either. To avoid unnecessary * overhead, manipulations of the state field should be done without actual - * atomic operations (i.e. only pg_atomic_read_u32() and - * pg_atomic_unlocked_write_u32()). + * atomic operations (i.e. only pg_atomic_read_u64() and + * pg_atomic_unlocked_write_u64()). * * Be careful to avoid increasing the size of the struct when adding or * reordering members. Keeping it below 64 bytes (the most common CPU @@ -309,7 +312,7 @@ typedef struct BufferDesc * State of the buffer, containing flags, refcount and usagecount. See * BUF_* and BM_* defines at the top of this file. */ - pg_atomic_uint32 state; + pg_atomic_uint64 state; /* * Backend of pin-count waiter. The buffer header spinlock needs to be @@ -415,7 +418,7 @@ BufferDescriptorGetContentLock(const BufferDesc *bdesc) * Functions for acquiring/releasing a shared buffer header's spinlock. Do * not apply these to local buffers! */ -extern uint32 LockBufHdr(BufferDesc *desc); +extern uint64 LockBufHdr(BufferDesc *desc); /* * Unlock the buffer header. @@ -426,9 +429,9 @@ extern uint32 LockBufHdr(BufferDesc *desc); static inline void UnlockBufHdr(BufferDesc *desc) { - Assert(pg_atomic_read_u32(&desc->state) & BM_LOCKED); + Assert(pg_atomic_read_u64(&desc->state) & BM_LOCKED); - pg_atomic_fetch_sub_u32(&desc->state, BM_LOCKED); + pg_atomic_fetch_sub_u64(&desc->state, BM_LOCKED); } /* @@ -439,14 +442,14 @@ UnlockBufHdr(BufferDesc *desc) * Note that this approach would not work for usagecount, since we need to cap * the usagecount at BM_MAX_USAGE_COUNT. */ -static inline uint32 -UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, - uint32 set_bits, uint32 unset_bits, +static inline uint64 +UnlockBufHdrExt(BufferDesc *desc, uint64 old_buf_state, + uint64 set_bits, uint64 unset_bits, int refcount_change) { for (;;) { - uint32 buf_state = old_buf_state; + uint64 buf_state = old_buf_state; Assert(buf_state & BM_LOCKED); @@ -457,7 +460,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, if (refcount_change != 0) buf_state += BUF_REFCOUNT_ONE * refcount_change; - if (pg_atomic_compare_exchange_u32(&desc->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&desc->state, &old_buf_state, buf_state)) { return old_buf_state; @@ -465,7 +468,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, } } -extern uint32 WaitBufHdrUnlocked(BufferDesc *buf); +extern uint64 WaitBufHdrUnlocked(BufferDesc *buf); /* in bufmgr.c */ @@ -525,14 +528,14 @@ extern void TrackNewBufferPin(Buffer buf); /* solely to make it easier to write tests */ extern bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait); -extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio); /* freelist.c */ extern IOContext IOContextForStrategy(BufferAccessStrategy strategy); extern BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy, - uint32 *buf_state, bool *from_ring); + uint64 *buf_state, bool *from_ring); extern bool StrategyRejectBuffer(BufferAccessStrategy strategy, BufferDesc *buf, bool from_ring); @@ -568,7 +571,7 @@ extern BlockNumber ExtendBufferedRelLocal(BufferManagerRelation bmr, uint32 *extended_by); extern void MarkLocalBufferDirty(Buffer buffer); extern void TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, - uint32 set_flag_bits, bool release_aio); + uint64 set_flag_bits, bool release_aio); extern bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait); extern void FlushLocalBuffer(BufferDesc *bufHdr, SMgrRelation reln); extern void InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced); diff --git a/src/include/storage/procnumber.h b/src/include/storage/procnumber.h index 30c360ad350..bd9cb3891cc 100644 --- a/src/include/storage/procnumber.h +++ b/src/include/storage/procnumber.h @@ -27,13 +27,13 @@ typedef int ProcNumber; /* * Note: MAX_BACKENDS_BITS is 18 as that is the space available for buffer - * refcounts in buf_internals.h. This limitation could be lifted by using a - * 64bit state; but it's unlikely to be worthwhile as 2^18-1 backends exceed - * currently realistic configurations. Even if that limitation were removed, - * we still could not a) exceed 2^23-1 because inval.c stores the ProcNumber - * as a 3-byte signed integer, b) INT_MAX/4 because some places compute - * 4*MaxBackends without any overflow check. We check that the configured - * number of backends does not exceed MAX_BACKENDS in InitializeMaxBackends(). + * refcounts in buf_internals.h. This limitation could be lifted, but it's + * unlikely to be worthwhile as 2^18-1 backends exceed currently realistic + * configurations. Even if that limitation were removed, we still could not a) + * exceed 2^23-1 because inval.c stores the ProcNumber as a 3-byte signed + * integer, b) INT_MAX/4 because some places compute 4*MaxBackends without any + * overflow check. We check that the configured number of backends does not + * exceed MAX_BACKENDS in InitializeMaxBackends(). */ #define MAX_BACKENDS_BITS 18 #define MAX_BACKENDS ((1U << MAX_BACKENDS_BITS)-1) diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index 9a312bcc7b3..7d894522526 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -121,7 +121,7 @@ BufferManagerShmemInit(void) ClearBufferTag(&buf->tag); - pg_atomic_init_u32(&buf->state, 0); + pg_atomic_init_u64(&buf->state, 0); buf->wait_backend_pgprocno = INVALID_PROC_NUMBER; buf->buf_id = i; diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index a036c2aa275..b0de8e45d4d 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -780,7 +780,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN { BufferDesc *bufHdr; BufferTag tag; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(recent_buffer)); @@ -793,7 +793,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN int b = -recent_buffer - 1; bufHdr = GetLocalBufferDescriptor(b); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* Is it still valid and holding the right tag? */ if ((buf_state & BM_VALID) && BufferTagsEqual(&tag, &bufHdr->tag)) @@ -1386,8 +1386,8 @@ StartReadBuffersImpl(ReadBuffersOperation *operation, bufHdr = GetLocalBufferDescriptor(-buffers[i] - 1); else bufHdr = GetBufferDescriptor(buffers[i] - 1); - Assert(pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID); - found = pg_atomic_read_u32(&bufHdr->state) & BM_VALID; + Assert(pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID); + found = pg_atomic_read_u64(&bufHdr->state) & BM_VALID; } else { @@ -1613,10 +1613,10 @@ CheckReadBuffersOperation(ReadBuffersOperation *operation, bool is_complete) GetBufferDescriptor(buffer - 1); Assert(BufferGetBlockNumber(buffer) == operation->blocknum + i); - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_TAG_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_TAG_VALID); if (i < operation->nblocks_done) - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_VALID); } #endif } @@ -2083,8 +2083,8 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, int existing_buf_id; Buffer victim_buffer; BufferDesc *victim_buf_hdr; - uint32 victim_buf_state; - uint32 set_bits = 0; + uint64 victim_buf_state; + uint64 set_bits = 0; /* Make sure we will have room to remember the buffer pin */ ResourceOwnerEnlarge(CurrentResourceOwner); @@ -2251,7 +2251,7 @@ InvalidateBuffer(BufferDesc *buf) uint32 oldHash; /* hash value for oldTag */ LWLock *oldPartitionLock; /* buffer partition lock for it */ uint32 oldFlags; - uint32 buf_state; + uint64 buf_state; /* Save the original buffer tag before dropping the spinlock */ oldTag = buf->tag; @@ -2342,7 +2342,7 @@ retry: static bool InvalidateVictimBuffer(BufferDesc *buf_hdr) { - uint32 buf_state; + uint64 buf_state; uint32 hash; LWLock *partition_lock; BufferTag tag; @@ -2402,10 +2402,10 @@ InvalidateVictimBuffer(BufferDesc *buf_hdr) LWLockRelease(partition_lock); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(!(buf_state & (BM_DIRTY | BM_VALID | BM_TAG_VALID))); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); - Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u32(&buf_hdr->state)) > 0); + Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u64(&buf_hdr->state)) > 0); return true; } @@ -2415,7 +2415,7 @@ GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context) { BufferDesc *buf_hdr; Buffer buf; - uint32 buf_state; + uint64 buf_state; bool from_ring; /* @@ -2548,7 +2548,7 @@ again: /* a final set of sanity checks */ #ifdef USE_ASSERT_CHECKING - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) == 1); Assert(!(buf_state & (BM_TAG_VALID | BM_VALID | BM_DIRTY))); @@ -2839,13 +2839,13 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, */ do { - pg_atomic_fetch_and_u32(&existing_hdr->state, ~BM_VALID); + pg_atomic_fetch_and_u64(&existing_hdr->state, ~BM_VALID); } while (!StartBufferIO(existing_hdr, true, false)); } else { - uint32 buf_state; - uint32 set_bits = 0; + uint64 buf_state; + uint64 set_bits = 0; buf_state = LockBufHdr(victim_buf_hdr); @@ -3021,7 +3021,7 @@ BufferIsDirty(Buffer buffer) Assert(BufferIsLockedByMeInMode(buffer, BUFFER_LOCK_EXCLUSIVE)); } - return pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY; + return pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY; } /* @@ -3037,8 +3037,8 @@ void MarkBufferDirty(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; if (!BufferIsValid(buffer)) elog(ERROR, "bad buffer ID: %d", buffer); @@ -3058,7 +3058,7 @@ MarkBufferDirty(Buffer buffer) * NB: We have to wait for the buffer header spinlock to be not held, as * TerminateBufferIO() relies on the spinlock. */ - old_buf_state = pg_atomic_read_u32(&bufHdr->state); + old_buf_state = pg_atomic_read_u64(&bufHdr->state); for (;;) { if (old_buf_state & BM_LOCKED) @@ -3069,7 +3069,7 @@ MarkBufferDirty(Buffer buffer) Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state |= BM_DIRTY | BM_JUST_DIRTIED; - if (pg_atomic_compare_exchange_u32(&bufHdr->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&bufHdr->state, &old_buf_state, buf_state)) break; } @@ -3173,10 +3173,10 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, if (ref == NULL) { - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { if (unlikely(skip_if_not_valid && !(old_buf_state & BM_VALID))) @@ -3210,7 +3210,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, buf_state += BUF_USAGECOUNT_ONE; } - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, buf_state)) { result = (buf_state & BM_VALID) != 0; @@ -3237,7 +3237,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, * that the buffer page is legitimately non-accessible here. We * cannot meddle with that. */ - result = (pg_atomic_read_u32(&buf->state) & BM_VALID) != 0; + result = (pg_atomic_read_u64(&buf->state) & BM_VALID) != 0; Assert(ref->data.refcount > 0); ref->data.refcount++; @@ -3272,7 +3272,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, static void PinBuffer_Locked(BufferDesc *buf) { - uint32 old_buf_state; + uint64 old_buf_state; /* * As explained, We don't expect any preexisting pins. That allows us to @@ -3284,7 +3284,7 @@ PinBuffer_Locked(BufferDesc *buf) * Since we hold the buffer spinlock, we can update the buffer state and * release the lock in one operation. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); UnlockBufHdrExt(buf, old_buf_state, 0, 0, 1); @@ -3314,7 +3314,7 @@ WakePinCountWaiter(BufferDesc *buf) * BM_PIN_COUNT_WAITER if it stops waiting for a reason other than this * backend waking it up. */ - uint32 buf_state = LockBufHdr(buf); + uint64 buf_state = LockBufHdr(buf); if ((buf_state & BM_PIN_COUNT_WAITER) && BUF_STATE_GET_REFCOUNT(buf_state) == 1) @@ -3361,7 +3361,7 @@ UnpinBufferNoOwner(BufferDesc *buf) ref->data.refcount--; if (ref->data.refcount == 0) { - uint32 old_buf_state; + uint64 old_buf_state; /* * Mark buffer non-accessible to Valgrind. @@ -3379,7 +3379,7 @@ UnpinBufferNoOwner(BufferDesc *buf) Assert(!LWLockHeldByMe(BufferDescriptorGetContentLock(buf))); /* decrement the shared reference count */ - old_buf_state = pg_atomic_fetch_sub_u32(&buf->state, BUF_REFCOUNT_ONE); + old_buf_state = pg_atomic_fetch_sub_u64(&buf->state, BUF_REFCOUNT_ONE); /* Support LockBufferForCleanup() */ if (old_buf_state & BM_PIN_COUNT_WAITER) @@ -3436,7 +3436,7 @@ TrackNewBufferPin(Buffer buf) static void BufferSync(int flags) { - uint32 buf_state; + uint64 buf_state; int buf_id; int num_to_scan; int num_spaces; @@ -3446,7 +3446,7 @@ BufferSync(int flags) Oid last_tsid; binaryheap *ts_heap; int i; - uint32 mask = BM_DIRTY; + uint64 mask = BM_DIRTY; WritebackContext wb_context; /* @@ -3478,7 +3478,7 @@ BufferSync(int flags) for (buf_id = 0; buf_id < NBuffers; buf_id++) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); - uint32 set_bits = 0; + uint64 set_bits = 0; /* * Header spinlock is enough to examine BM_DIRTY, see comment in @@ -3645,7 +3645,7 @@ BufferSync(int flags) * write the buffer though we didn't need to. It doesn't seem worth * guarding against this, though. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_CHECKPOINT_NEEDED) + if (pg_atomic_read_u64(&bufHdr->state) & BM_CHECKPOINT_NEEDED) { if (SyncOneBuffer(buf_id, false, &wb_context) & BUF_WRITTEN) { @@ -4015,7 +4015,7 @@ SyncOneBuffer(int buf_id, bool skip_recently_used, WritebackContext *wb_context) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); int result = 0; - uint32 buf_state; + uint64 buf_state; BufferTag tag; /* Make sure we can handle the pin */ @@ -4264,7 +4264,7 @@ DebugPrintBufferRefcount(Buffer buffer) int32 loccount; char *result; ProcNumber backend; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); if (BufferIsLocal(buffer)) @@ -4281,9 +4281,9 @@ DebugPrintBufferRefcount(Buffer buffer) } /* theoretically we should lock the bufHdr here */ - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); - result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%x, refcount=%u %d)", + result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%" PRIx64 ", refcount=%u %d)", buffer, relpathbackend(BufTagGetRelFileLocator(&buf->tag), backend, BufTagGetForkNum(&buf->tag)).str, @@ -4383,7 +4383,7 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object, instr_time io_start; Block bufBlock; char *bufToWrite; - uint32 buf_state; + uint64 buf_state; /* * Try to start an I/O operation. If StartBufferIO returns false, then @@ -4581,7 +4581,7 @@ BufferIsPermanent(Buffer buffer) * not random garbage. */ bufHdr = GetBufferDescriptor(buffer - 1); - return (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT) != 0; + return (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT) != 0; } /* @@ -5044,11 +5044,11 @@ FlushRelationBuffers(Relation rel) { for (i = 0; i < NLocBuffer; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetLocalBufferDescriptor(i); if (BufTagMatchesRelFileLocator(&bufHdr->tag, &rel->rd_locator) && - ((buf_state = pg_atomic_read_u32(&bufHdr->state)) & + ((buf_state = pg_atomic_read_u64(&bufHdr->state)) & (BM_VALID | BM_DIRTY)) == (BM_VALID | BM_DIRTY)) { ErrorContextCallback errcallback; @@ -5084,7 +5084,7 @@ FlushRelationBuffers(Relation rel) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5156,7 +5156,7 @@ FlushRelationsAllBuffers(SMgrRelation *smgrs, int nrels) { SMgrSortArray *srelent = NULL; BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; /* * As in DropRelationBuffers, an unlocked precheck should be safe and @@ -5405,7 +5405,7 @@ FlushDatabaseBuffers(Oid dbid) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5553,13 +5553,13 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * is only intended to be used in cases where failing to write out the * data would be harmless anyway, it doesn't really matter. */ - if ((pg_atomic_read_u32(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != + if ((pg_atomic_read_u64(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != (BM_DIRTY | BM_JUST_DIRTIED)) { XLogRecPtr lsn = InvalidXLogRecPtr; bool dirtied = false; bool delayChkptFlags = false; - uint32 buf_state; + uint64 buf_state; /* * If we need to protect hint bit updates from torn writes, WAL-log a @@ -5571,7 +5571,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * when we call XLogInsert() since the value changes dynamically. */ if (XLogHintBitIsNeeded() && - (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT)) + (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT)) { /* * If we must not write WAL, due to a relfilelocator-specific @@ -5671,8 +5671,8 @@ UnlockBuffers(void) if (buf) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; buf_state = LockBufHdr(buf); @@ -5803,8 +5803,8 @@ LockBufferForCleanup(Buffer buffer) for (;;) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; /* Try to acquire lock */ LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); @@ -5952,7 +5952,7 @@ bool ConditionalLockBufferForCleanup(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state, + uint64 buf_state, refcount; Assert(BufferIsValid(buffer)); @@ -6010,7 +6010,7 @@ bool IsBufferCleanupOK(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); @@ -6066,7 +6066,7 @@ WaitIO(BufferDesc *buf) ConditionVariablePrepareToSleep(cv); for (;;) { - uint32 buf_state; + uint64 buf_state; PgAioWaitRef iow; /* @@ -6140,7 +6140,7 @@ WaitIO(BufferDesc *buf) bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; ResourceOwnerEnlarge(CurrentResourceOwner); @@ -6196,11 +6196,11 @@ StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) * is being released) */ void -TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio) { - uint32 buf_state; - uint32 unset_flag_bits = 0; + uint64 buf_state; + uint64 unset_flag_bits = 0; int refcount_change = 0; buf_state = LockBufHdr(buf); @@ -6261,7 +6261,7 @@ static void AbortBufferIO(Buffer buffer) { BufferDesc *buf_hdr = GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; buf_state = LockBufHdr(buf_hdr); Assert(buf_state & (BM_IO_IN_PROGRESS | BM_TAG_VALID)); @@ -6355,10 +6355,10 @@ rlocator_comparator(const void *p1, const void *p2) /* * Lock buffer header - set BM_LOCKED in buffer state. */ -uint32 +uint64 LockBufHdr(BufferDesc *desc) { - uint32 old_buf_state; + uint64 old_buf_state; Assert(!BufferIsLocal(BufferDescriptorGetBuffer(desc))); @@ -6369,7 +6369,7 @@ LockBufHdr(BufferDesc *desc) * the spin-delay infrastructure. The work necessary for that shows up * in profiles and is rarely necessary. */ - old_buf_state = pg_atomic_fetch_or_u32(&desc->state, BM_LOCKED); + old_buf_state = pg_atomic_fetch_or_u64(&desc->state, BM_LOCKED); if (likely(!(old_buf_state & BM_LOCKED))) break; /* got lock */ @@ -6382,7 +6382,7 @@ LockBufHdr(BufferDesc *desc) while (old_buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - old_buf_state = pg_atomic_read_u32(&desc->state); + old_buf_state = pg_atomic_read_u64(&desc->state); } finish_spin_delay(&delayStatus); } @@ -6403,20 +6403,20 @@ LockBufHdr(BufferDesc *desc) * Obviously the buffer could be locked by the time the value is returned, so * this is primarily useful in CAS style loops. */ -pg_noinline uint32 +pg_noinline uint64 WaitBufHdrUnlocked(BufferDesc *buf) { SpinDelayStatus delayStatus; - uint32 buf_state; + uint64 buf_state; init_local_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); while (buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); } finish_spin_delay(&delayStatus); @@ -6704,12 +6704,12 @@ ResOwnerPrintBufferPin(Datum res) static bool EvictUnpinnedBufferInternal(BufferDesc *desc, bool *buffer_flushed) { - uint32 buf_state; + uint64 buf_state; bool result; *buffer_flushed = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -6803,12 +6803,12 @@ EvictAllUnpinnedBuffers(int32 *buffers_evicted, int32 *buffers_flushed, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_flushed; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -6855,7 +6855,7 @@ EvictRelUnpinnedBuffers(Relation rel, int32 *buffers_evicted, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_flushed; CHECK_FOR_INTERRUPTS(); @@ -6897,12 +6897,12 @@ static bool MarkDirtyUnpinnedBufferInternal(Buffer buf, BufferDesc *desc, bool *buffer_already_dirty) { - uint32 buf_state; + uint64 buf_state; bool result = false; *buffer_already_dirty = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -7000,7 +7000,7 @@ MarkDirtyRelUnpinnedBuffers(Relation rel, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_already_dirty; CHECK_FOR_INTERRUPTS(); @@ -7054,12 +7054,12 @@ MarkDirtyAllUnpinnedBuffers(int32 *buffers_dirtied, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_already_dirty; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -7110,7 +7110,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) BufferDesc *buf_hdr = is_temp ? GetLocalBufferDescriptor(-buffer - 1) : GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; /* * Check that all the buffers are actually ones that could conceivably @@ -7128,7 +7128,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) } if (is_temp) - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); else buf_state = LockBufHdr(buf_hdr); @@ -7166,7 +7166,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) if (is_temp) { buf_state += BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else UnlockBufHdrExt(buf_hdr, buf_state, 0, 0, 1); @@ -7352,13 +7352,13 @@ buffer_readv_complete_one(PgAioTargetData *td, uint8 buf_off, Buffer buffer, : GetBufferDescriptor(buffer - 1); BufferTag tag = buf_hdr->tag; char *bufdata = BufferGetBlock(buffer); - uint32 set_flag_bits; + uint64 set_flag_bits; int piv_flags; /* check that the buffer is in the expected state for a read */ #ifdef USE_ASSERT_CHECKING { - uint32 buf_state = pg_atomic_read_u32(&buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_VALID)); diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c index 9a93fb335fc..b7687836188 100644 --- a/src/backend/storage/buffer/freelist.c +++ b/src/backend/storage/buffer/freelist.c @@ -86,7 +86,7 @@ typedef struct BufferAccessStrategyData /* Prototypes for internal functions */ static BufferDesc *GetBufferFromRing(BufferAccessStrategy strategy, - uint32 *buf_state); + uint64 *buf_state); static void AddBufferToRing(BufferAccessStrategy strategy, BufferDesc *buf); @@ -171,7 +171,7 @@ ClockSweepTick(void) * before returning. */ BufferDesc * -StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_ring) +StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_ring) { BufferDesc *buf; int bgwprocno; @@ -230,8 +230,8 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r trycounter = NBuffers; for (;;) { - uint32 old_buf_state; - uint32 local_buf_state; + uint64 old_buf_state; + uint64 local_buf_state; buf = GetBufferDescriptor(ClockSweepTick()); @@ -239,7 +239,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r * Check whether the buffer can be used and pin it if so. Do this * using a CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -277,7 +277,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r { local_buf_state -= BUF_USAGECOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { trycounter = NBuffers; @@ -289,7 +289,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { /* Found a usable buffer */ @@ -655,12 +655,12 @@ FreeAccessStrategy(BufferAccessStrategy strategy) * returning. */ static BufferDesc * -GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) +GetBufferFromRing(BufferAccessStrategy strategy, uint64 *buf_state) { BufferDesc *buf; Buffer bufnum; - uint32 old_buf_state; - uint32 local_buf_state; /* to avoid repeated (de-)referencing */ + uint64 old_buf_state; + uint64 local_buf_state; /* to avoid repeated (de-)referencing */ /* Advance to next ring slot */ @@ -682,7 +682,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) * Check whether the buffer can be used and pin it if so. Do this using a * CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -710,7 +710,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { *buf_state = local_buf_state; diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index f6e2b1aa288..04a540379a2 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -148,7 +148,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, } else { - uint32 buf_state; + uint64 buf_state; victim_buffer = GetLocalVictimBuffer(); bufid = -victim_buffer - 1; @@ -165,10 +165,10 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, */ bufHdr->tag = newTag; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); buf_state &= ~(BUF_FLAG_MASK | BUF_USAGECOUNT_MASK); buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); *foundPtr = false; } @@ -245,12 +245,12 @@ GetLocalVictimBuffer(void) if (LocalRefCount[victim_bufid] == 0) { - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0) { buf_state -= BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); trycounter = NLocBuffer; } else if (BUF_STATE_GET_REFCOUNT(buf_state) > 0) @@ -286,13 +286,13 @@ GetLocalVictimBuffer(void) * this buffer is not referenced but it might still be dirty. if that's * the case, write it out before reusing it! */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY) FlushLocalBuffer(bufHdr, NULL); /* * Remove the victim buffer from the hashtable and mark as invalid. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID) + if (pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID) { InvalidateLocalBuffer(bufHdr, false); @@ -417,7 +417,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, if (found) { BufferDesc *existing_hdr; - uint32 buf_state; + uint64 buf_state; UnpinLocalBuffer(BufferDescriptorGetBuffer(victim_buf_hdr)); @@ -428,18 +428,18 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, /* * Clear the BM_VALID bit, do StartLocalBufferIO() and proceed. */ - buf_state = pg_atomic_read_u32(&existing_hdr->state); + buf_state = pg_atomic_read_u64(&existing_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_DIRTY)); buf_state &= ~BM_VALID; - pg_atomic_unlocked_write_u32(&existing_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&existing_hdr->state, buf_state); /* no need to loop for local buffers */ StartLocalBufferIO(existing_hdr, true, false); } else { - uint32 buf_state = pg_atomic_read_u32(&victim_buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&victim_buf_hdr->state); Assert(!(buf_state & (BM_VALID | BM_TAG_VALID | BM_DIRTY | BM_JUST_DIRTIED))); @@ -447,7 +447,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&victim_buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&victim_buf_hdr->state, buf_state); hresult->id = victim_buf_id; @@ -467,13 +467,13 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, { Buffer buf = buffers[i]; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); buf_state |= BM_VALID; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } *extended_by = extend_by; @@ -492,7 +492,7 @@ MarkLocalBufferDirty(Buffer buffer) { int bufid; BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsLocal(buffer)); @@ -506,14 +506,14 @@ MarkLocalBufferDirty(Buffer buffer) bufHdr = GetLocalBufferDescriptor(bufid); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_DIRTY)) pgBufferUsage.local_blks_dirtied++; buf_state |= BM_DIRTY; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -522,7 +522,7 @@ MarkLocalBufferDirty(Buffer buffer) bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; /* * With AIO the buffer could have IO in progress, e.g. when there are two @@ -542,7 +542,7 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) /* Once we get here, there is definitely no I/O active on this buffer */ /* Check if someone else already did the I/O */ - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (forInput ? (buf_state & BM_VALID) : !(buf_state & BM_DIRTY)) { return false; @@ -559,11 +559,11 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) * Like TerminateBufferIO, but for local buffers */ void -TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bits, +TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint64 set_flag_bits, bool release_aio) { /* Only need to adjust flags */ - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); /* BM_IO_IN_PROGRESS isn't currently used for local buffers */ @@ -582,7 +582,7 @@ TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bit } buf_state |= set_flag_bits; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); /* local buffers don't track IO using resowners */ @@ -606,7 +606,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) { Buffer buffer = BufferDescriptorGetBuffer(bufHdr); int bufid = -buffer - 1; - uint32 buf_state; + uint64 buf_state; LocalBufferLookupEnt *hresult; /* @@ -622,7 +622,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) Assert(!pgaio_wref_valid(&bufHdr->io_wref)); } - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* * We need to test not just LocalRefCount[bufid] but also the BufferDesc @@ -647,7 +647,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) ClearBufferTag(&bufHdr->tag); buf_state &= ~BUF_FLAG_MASK; buf_state &= ~BUF_USAGECOUNT_MASK; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -671,9 +671,9 @@ DropRelationLocalBuffers(RelFileLocator rlocator, ForkNumber *forkNum, for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_TAG_VALID) || !BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -706,9 +706,9 @@ DropRelationAllLocalBuffers(RelFileLocator rlocator) for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if ((buf_state & BM_TAG_VALID) && BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -804,11 +804,11 @@ InitLocalBuffers(void) bool PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { - uint32 buf_state; + uint64 buf_state; Buffer buffer = BufferDescriptorGetBuffer(buf_hdr); int bufid = -buffer - 1; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); if (LocalRefCount[bufid] == 0) { @@ -819,7 +819,7 @@ PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { buf_state += BUF_USAGECOUNT_ONE; } - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* * See comment in PinBuffer(). @@ -856,14 +856,14 @@ UnpinLocalBufferNoOwner(Buffer buffer) if (--LocalRefCount[buffid] == 0) { BufferDesc *buf_hdr = GetLocalBufferDescriptor(buffid); - uint32 buf_state; + uint64 buf_state; NLocalPinnedBuffers--; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state -= BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* see comment in UnpinBufferNoOwner */ VALGRIND_MAKE_MEM_NOACCESS(LocalBufHdrGetBlock(buf_hdr), BLCKSZ); diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index 0c58e4b265c..529803346ce 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -199,7 +199,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) for (i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -615,7 +615,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -626,7 +626,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) * noticeably increase the cost of the function. */ bufHdr = GetBufferDescriptor(i); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (buf_state & BM_VALID) { @@ -676,7 +676,7 @@ pg_buffercache_usage_counts(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); int usage_count; CHECK_FOR_INTERRUPTS(); diff --git a/src/test/modules/test_aio/test_aio.c b/src/test/modules/test_aio/test_aio.c index e046b08f3d5..b1aa8af9ec0 100644 --- a/src/test/modules/test_aio/test_aio.c +++ b/src/test/modules/test_aio/test_aio.c @@ -308,9 +308,9 @@ create_toy_buffer(Relation rel, BlockNumber blkno) { Buffer buf; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; bool was_pinned = false; - uint32 unset_bits = 0; + uint64 unset_bits = 0; /* place buffer in shared buffers without erroring out */ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO_AND_LOCK, NULL); @@ -319,7 +319,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); } else { @@ -340,7 +340,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_state &= ~unset_bits; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else { @@ -489,7 +489,7 @@ invalidate_rel_block(PG_FUNCTION_ARGS) LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); - if (pg_atomic_read_u32(&buf_hdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&buf_hdr->state) & BM_DIRTY) { if (BufferIsLocal(buf)) FlushLocalBuffer(buf_hdr, NULL); @@ -572,7 +572,7 @@ buffer_call_terminate_io(PG_FUNCTION_ARGS) bool io_error = PG_GETARG_BOOL(3); bool release_aio = PG_GETARG_BOOL(4); bool clear_dirty = false; - uint32 set_flag_bits = 0; + uint64 set_flag_bits = 0; if (io_error) set_flag_bits |= BM_IO_ERROR; -- 2.48.1.76.g4e746b1a31.dirty --rkiyqpij3ajqn7ww Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v9-0007-bufmgr-Implement-buffer-content-locks-independent.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v10 3/8] bufmgr: Change BufferDesc.state to be a 64-bit atomic @ 2026-01-07 22:26 Andres Freund <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Andres Freund @ 2026-01-07 22:26 UTC (permalink / raw) This is motivated by wanting to merge buffer content locks into BufferDesc.state in a future commit, rather than having a separate lwlock (see commit c75ebc657ff for more details). As this change is rather mechanical, it seems to make sense to split it out into a separate commit, for easier review. Reviewed-by: Melanie Plageman <[email protected]> Discussion: https://postgr.es/m/fvfmkr5kk4nyex56ejgxj3uzi63isfxovp2biecb4bspbjrze7@az2pljabhnff --- src/include/storage/buf_internals.h | 51 +++--- src/include/storage/procnumber.h | 14 +- src/backend/storage/buffer/buf_init.c | 2 +- src/backend/storage/buffer/bufmgr.c | 170 +++++++++--------- src/backend/storage/buffer/freelist.c | 24 +-- src/backend/storage/buffer/localbuf.c | 72 ++++---- contrib/pg_buffercache/pg_buffercache_pages.c | 8 +- src/test/modules/test_aio/test_aio.c | 12 +- 8 files changed, 178 insertions(+), 175 deletions(-) diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index 2f607ea2ac5..a4d36e9ca01 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -30,7 +30,7 @@ #include "utils/resowner.h" /* - * Buffer state is a single 32-bit variable where following data is combined. + * Buffer state is a single 64-bit variable where following data is combined. * * State of the buffer itself (in order): * - 18 bits refcount @@ -40,6 +40,9 @@ * Combining these values allows to perform some operations without locking * the buffer header, by modifying them together with a CAS loop. * + * NB: A future commit will use a significant portion of the remaining bits to + * implement buffer locking as part of the state variable. + * * The definition of buffer state components is below. */ #define BUF_REFCOUNT_BITS 18 @@ -52,27 +55,27 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, /* refcount related definitions */ #define BUF_REFCOUNT_ONE 1 #define BUF_REFCOUNT_MASK \ - ((1U << BUF_REFCOUNT_BITS) - 1) + ((UINT64CONST(1) << BUF_REFCOUNT_BITS) - 1) /* usage count related definitions */ #define BUF_USAGECOUNT_SHIFT \ BUF_REFCOUNT_BITS #define BUF_USAGECOUNT_MASK \ - (((1U << BUF_USAGECOUNT_BITS) - 1) << (BUF_USAGECOUNT_SHIFT)) + (((UINT64CONST(1) << BUF_USAGECOUNT_BITS) - 1) << (BUF_USAGECOUNT_SHIFT)) #define BUF_USAGECOUNT_ONE \ - (1U << BUF_REFCOUNT_BITS) + (UINT64CONST(1) << BUF_REFCOUNT_BITS) /* flags related definitions */ #define BUF_FLAG_SHIFT \ (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS) #define BUF_FLAG_MASK \ - (((1U << BUF_FLAG_BITS) - 1) << BUF_FLAG_SHIFT) + (((UINT64CONST(1) << BUF_FLAG_BITS) - 1) << BUF_FLAG_SHIFT) /* Get refcount and usagecount from buffer state */ #define BUF_STATE_GET_REFCOUNT(state) \ - ((state) & BUF_REFCOUNT_MASK) + ((uint32)((state) & BUF_REFCOUNT_MASK)) #define BUF_STATE_GET_USAGECOUNT(state) \ - (((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT) + ((uint32)(((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT)) /* * Flags for buffer descriptors @@ -82,7 +85,7 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, */ #define BUF_DEFINE_FLAG(flagno) \ - (1U << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + (flagno))) + (UINT64CONST(1) << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + (flagno))) /* buffer header is locked */ #define BM_LOCKED BUF_DEFINE_FLAG( 0) @@ -115,7 +118,7 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, */ #define BM_MAX_USAGE_COUNT 5 -StaticAssertDecl(BM_MAX_USAGE_COUNT < (1 << BUF_USAGECOUNT_BITS), +StaticAssertDecl(BM_MAX_USAGE_COUNT < (UINT64CONST(1) << BUF_USAGECOUNT_BITS), "BM_MAX_USAGE_COUNT doesn't fit in BUF_USAGECOUNT_BITS bits"); StaticAssertDecl(MAX_BACKENDS_BITS <= BUF_REFCOUNT_BITS, "MAX_BACKENDS_BITS needs to be <= BUF_REFCOUNT_BITS"); @@ -280,8 +283,8 @@ BufMappingPartitionLockByIndex(uint32 index) * We use this same struct for local buffer headers, but the locks are not * used and not all of the flag bits are useful either. To avoid unnecessary * overhead, manipulations of the state field should be done without actual - * atomic operations (i.e. only pg_atomic_read_u32() and - * pg_atomic_unlocked_write_u32()). + * atomic operations (i.e. only pg_atomic_read_u64() and + * pg_atomic_unlocked_write_u64()). * * Be careful to avoid increasing the size of the struct when adding or * reordering members. Keeping it below 64 bytes (the most common CPU @@ -309,7 +312,7 @@ typedef struct BufferDesc * State of the buffer, containing flags, refcount and usagecount. See * BUF_* and BM_* defines at the top of this file. */ - pg_atomic_uint32 state; + pg_atomic_uint64 state; /* * Backend of pin-count waiter. The buffer header spinlock needs to be @@ -415,7 +418,7 @@ BufferDescriptorGetContentLock(const BufferDesc *bdesc) * Functions for acquiring/releasing a shared buffer header's spinlock. Do * not apply these to local buffers! */ -extern uint32 LockBufHdr(BufferDesc *desc); +extern uint64 LockBufHdr(BufferDesc *desc); /* * Unlock the buffer header. @@ -426,9 +429,9 @@ extern uint32 LockBufHdr(BufferDesc *desc); static inline void UnlockBufHdr(BufferDesc *desc) { - Assert(pg_atomic_read_u32(&desc->state) & BM_LOCKED); + Assert(pg_atomic_read_u64(&desc->state) & BM_LOCKED); - pg_atomic_fetch_sub_u32(&desc->state, BM_LOCKED); + pg_atomic_fetch_sub_u64(&desc->state, BM_LOCKED); } /* @@ -439,14 +442,14 @@ UnlockBufHdr(BufferDesc *desc) * Note that this approach would not work for usagecount, since we need to cap * the usagecount at BM_MAX_USAGE_COUNT. */ -static inline uint32 -UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, - uint32 set_bits, uint32 unset_bits, +static inline uint64 +UnlockBufHdrExt(BufferDesc *desc, uint64 old_buf_state, + uint64 set_bits, uint64 unset_bits, int refcount_change) { for (;;) { - uint32 buf_state = old_buf_state; + uint64 buf_state = old_buf_state; Assert(buf_state & BM_LOCKED); @@ -457,7 +460,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, if (refcount_change != 0) buf_state += BUF_REFCOUNT_ONE * refcount_change; - if (pg_atomic_compare_exchange_u32(&desc->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&desc->state, &old_buf_state, buf_state)) { return old_buf_state; @@ -465,7 +468,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, } } -extern uint32 WaitBufHdrUnlocked(BufferDesc *buf); +extern uint64 WaitBufHdrUnlocked(BufferDesc *buf); /* in bufmgr.c */ @@ -525,14 +528,14 @@ extern void TrackNewBufferPin(Buffer buf); /* solely to make it easier to write tests */ extern bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait); -extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio); /* freelist.c */ extern IOContext IOContextForStrategy(BufferAccessStrategy strategy); extern BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy, - uint32 *buf_state, bool *from_ring); + uint64 *buf_state, bool *from_ring); extern bool StrategyRejectBuffer(BufferAccessStrategy strategy, BufferDesc *buf, bool from_ring); @@ -568,7 +571,7 @@ extern BlockNumber ExtendBufferedRelLocal(BufferManagerRelation bmr, uint32 *extended_by); extern void MarkLocalBufferDirty(Buffer buffer); extern void TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, - uint32 set_flag_bits, bool release_aio); + uint64 set_flag_bits, bool release_aio); extern bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait); extern void FlushLocalBuffer(BufferDesc *bufHdr, SMgrRelation reln); extern void InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced); diff --git a/src/include/storage/procnumber.h b/src/include/storage/procnumber.h index 30c360ad350..bd9cb3891cc 100644 --- a/src/include/storage/procnumber.h +++ b/src/include/storage/procnumber.h @@ -27,13 +27,13 @@ typedef int ProcNumber; /* * Note: MAX_BACKENDS_BITS is 18 as that is the space available for buffer - * refcounts in buf_internals.h. This limitation could be lifted by using a - * 64bit state; but it's unlikely to be worthwhile as 2^18-1 backends exceed - * currently realistic configurations. Even if that limitation were removed, - * we still could not a) exceed 2^23-1 because inval.c stores the ProcNumber - * as a 3-byte signed integer, b) INT_MAX/4 because some places compute - * 4*MaxBackends without any overflow check. We check that the configured - * number of backends does not exceed MAX_BACKENDS in InitializeMaxBackends(). + * refcounts in buf_internals.h. This limitation could be lifted, but it's + * unlikely to be worthwhile as 2^18-1 backends exceed currently realistic + * configurations. Even if that limitation were removed, we still could not a) + * exceed 2^23-1 because inval.c stores the ProcNumber as a 3-byte signed + * integer, b) INT_MAX/4 because some places compute 4*MaxBackends without any + * overflow check. We check that the configured number of backends does not + * exceed MAX_BACKENDS in InitializeMaxBackends(). */ #define MAX_BACKENDS_BITS 18 #define MAX_BACKENDS ((1U << MAX_BACKENDS_BITS)-1) diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index 9a312bcc7b3..7d894522526 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -121,7 +121,7 @@ BufferManagerShmemInit(void) ClearBufferTag(&buf->tag); - pg_atomic_init_u32(&buf->state, 0); + pg_atomic_init_u64(&buf->state, 0); buf->wait_backend_pgprocno = INVALID_PROC_NUMBER; buf->buf_id = i; diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index a036c2aa275..b0de8e45d4d 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -780,7 +780,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN { BufferDesc *bufHdr; BufferTag tag; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(recent_buffer)); @@ -793,7 +793,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN int b = -recent_buffer - 1; bufHdr = GetLocalBufferDescriptor(b); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* Is it still valid and holding the right tag? */ if ((buf_state & BM_VALID) && BufferTagsEqual(&tag, &bufHdr->tag)) @@ -1386,8 +1386,8 @@ StartReadBuffersImpl(ReadBuffersOperation *operation, bufHdr = GetLocalBufferDescriptor(-buffers[i] - 1); else bufHdr = GetBufferDescriptor(buffers[i] - 1); - Assert(pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID); - found = pg_atomic_read_u32(&bufHdr->state) & BM_VALID; + Assert(pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID); + found = pg_atomic_read_u64(&bufHdr->state) & BM_VALID; } else { @@ -1613,10 +1613,10 @@ CheckReadBuffersOperation(ReadBuffersOperation *operation, bool is_complete) GetBufferDescriptor(buffer - 1); Assert(BufferGetBlockNumber(buffer) == operation->blocknum + i); - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_TAG_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_TAG_VALID); if (i < operation->nblocks_done) - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_VALID); } #endif } @@ -2083,8 +2083,8 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, int existing_buf_id; Buffer victim_buffer; BufferDesc *victim_buf_hdr; - uint32 victim_buf_state; - uint32 set_bits = 0; + uint64 victim_buf_state; + uint64 set_bits = 0; /* Make sure we will have room to remember the buffer pin */ ResourceOwnerEnlarge(CurrentResourceOwner); @@ -2251,7 +2251,7 @@ InvalidateBuffer(BufferDesc *buf) uint32 oldHash; /* hash value for oldTag */ LWLock *oldPartitionLock; /* buffer partition lock for it */ uint32 oldFlags; - uint32 buf_state; + uint64 buf_state; /* Save the original buffer tag before dropping the spinlock */ oldTag = buf->tag; @@ -2342,7 +2342,7 @@ retry: static bool InvalidateVictimBuffer(BufferDesc *buf_hdr) { - uint32 buf_state; + uint64 buf_state; uint32 hash; LWLock *partition_lock; BufferTag tag; @@ -2402,10 +2402,10 @@ InvalidateVictimBuffer(BufferDesc *buf_hdr) LWLockRelease(partition_lock); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(!(buf_state & (BM_DIRTY | BM_VALID | BM_TAG_VALID))); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); - Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u32(&buf_hdr->state)) > 0); + Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u64(&buf_hdr->state)) > 0); return true; } @@ -2415,7 +2415,7 @@ GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context) { BufferDesc *buf_hdr; Buffer buf; - uint32 buf_state; + uint64 buf_state; bool from_ring; /* @@ -2548,7 +2548,7 @@ again: /* a final set of sanity checks */ #ifdef USE_ASSERT_CHECKING - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) == 1); Assert(!(buf_state & (BM_TAG_VALID | BM_VALID | BM_DIRTY))); @@ -2839,13 +2839,13 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, */ do { - pg_atomic_fetch_and_u32(&existing_hdr->state, ~BM_VALID); + pg_atomic_fetch_and_u64(&existing_hdr->state, ~BM_VALID); } while (!StartBufferIO(existing_hdr, true, false)); } else { - uint32 buf_state; - uint32 set_bits = 0; + uint64 buf_state; + uint64 set_bits = 0; buf_state = LockBufHdr(victim_buf_hdr); @@ -3021,7 +3021,7 @@ BufferIsDirty(Buffer buffer) Assert(BufferIsLockedByMeInMode(buffer, BUFFER_LOCK_EXCLUSIVE)); } - return pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY; + return pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY; } /* @@ -3037,8 +3037,8 @@ void MarkBufferDirty(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; if (!BufferIsValid(buffer)) elog(ERROR, "bad buffer ID: %d", buffer); @@ -3058,7 +3058,7 @@ MarkBufferDirty(Buffer buffer) * NB: We have to wait for the buffer header spinlock to be not held, as * TerminateBufferIO() relies on the spinlock. */ - old_buf_state = pg_atomic_read_u32(&bufHdr->state); + old_buf_state = pg_atomic_read_u64(&bufHdr->state); for (;;) { if (old_buf_state & BM_LOCKED) @@ -3069,7 +3069,7 @@ MarkBufferDirty(Buffer buffer) Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state |= BM_DIRTY | BM_JUST_DIRTIED; - if (pg_atomic_compare_exchange_u32(&bufHdr->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&bufHdr->state, &old_buf_state, buf_state)) break; } @@ -3173,10 +3173,10 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, if (ref == NULL) { - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { if (unlikely(skip_if_not_valid && !(old_buf_state & BM_VALID))) @@ -3210,7 +3210,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, buf_state += BUF_USAGECOUNT_ONE; } - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, buf_state)) { result = (buf_state & BM_VALID) != 0; @@ -3237,7 +3237,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, * that the buffer page is legitimately non-accessible here. We * cannot meddle with that. */ - result = (pg_atomic_read_u32(&buf->state) & BM_VALID) != 0; + result = (pg_atomic_read_u64(&buf->state) & BM_VALID) != 0; Assert(ref->data.refcount > 0); ref->data.refcount++; @@ -3272,7 +3272,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, static void PinBuffer_Locked(BufferDesc *buf) { - uint32 old_buf_state; + uint64 old_buf_state; /* * As explained, We don't expect any preexisting pins. That allows us to @@ -3284,7 +3284,7 @@ PinBuffer_Locked(BufferDesc *buf) * Since we hold the buffer spinlock, we can update the buffer state and * release the lock in one operation. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); UnlockBufHdrExt(buf, old_buf_state, 0, 0, 1); @@ -3314,7 +3314,7 @@ WakePinCountWaiter(BufferDesc *buf) * BM_PIN_COUNT_WAITER if it stops waiting for a reason other than this * backend waking it up. */ - uint32 buf_state = LockBufHdr(buf); + uint64 buf_state = LockBufHdr(buf); if ((buf_state & BM_PIN_COUNT_WAITER) && BUF_STATE_GET_REFCOUNT(buf_state) == 1) @@ -3361,7 +3361,7 @@ UnpinBufferNoOwner(BufferDesc *buf) ref->data.refcount--; if (ref->data.refcount == 0) { - uint32 old_buf_state; + uint64 old_buf_state; /* * Mark buffer non-accessible to Valgrind. @@ -3379,7 +3379,7 @@ UnpinBufferNoOwner(BufferDesc *buf) Assert(!LWLockHeldByMe(BufferDescriptorGetContentLock(buf))); /* decrement the shared reference count */ - old_buf_state = pg_atomic_fetch_sub_u32(&buf->state, BUF_REFCOUNT_ONE); + old_buf_state = pg_atomic_fetch_sub_u64(&buf->state, BUF_REFCOUNT_ONE); /* Support LockBufferForCleanup() */ if (old_buf_state & BM_PIN_COUNT_WAITER) @@ -3436,7 +3436,7 @@ TrackNewBufferPin(Buffer buf) static void BufferSync(int flags) { - uint32 buf_state; + uint64 buf_state; int buf_id; int num_to_scan; int num_spaces; @@ -3446,7 +3446,7 @@ BufferSync(int flags) Oid last_tsid; binaryheap *ts_heap; int i; - uint32 mask = BM_DIRTY; + uint64 mask = BM_DIRTY; WritebackContext wb_context; /* @@ -3478,7 +3478,7 @@ BufferSync(int flags) for (buf_id = 0; buf_id < NBuffers; buf_id++) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); - uint32 set_bits = 0; + uint64 set_bits = 0; /* * Header spinlock is enough to examine BM_DIRTY, see comment in @@ -3645,7 +3645,7 @@ BufferSync(int flags) * write the buffer though we didn't need to. It doesn't seem worth * guarding against this, though. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_CHECKPOINT_NEEDED) + if (pg_atomic_read_u64(&bufHdr->state) & BM_CHECKPOINT_NEEDED) { if (SyncOneBuffer(buf_id, false, &wb_context) & BUF_WRITTEN) { @@ -4015,7 +4015,7 @@ SyncOneBuffer(int buf_id, bool skip_recently_used, WritebackContext *wb_context) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); int result = 0; - uint32 buf_state; + uint64 buf_state; BufferTag tag; /* Make sure we can handle the pin */ @@ -4264,7 +4264,7 @@ DebugPrintBufferRefcount(Buffer buffer) int32 loccount; char *result; ProcNumber backend; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); if (BufferIsLocal(buffer)) @@ -4281,9 +4281,9 @@ DebugPrintBufferRefcount(Buffer buffer) } /* theoretically we should lock the bufHdr here */ - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); - result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%x, refcount=%u %d)", + result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%" PRIx64 ", refcount=%u %d)", buffer, relpathbackend(BufTagGetRelFileLocator(&buf->tag), backend, BufTagGetForkNum(&buf->tag)).str, @@ -4383,7 +4383,7 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object, instr_time io_start; Block bufBlock; char *bufToWrite; - uint32 buf_state; + uint64 buf_state; /* * Try to start an I/O operation. If StartBufferIO returns false, then @@ -4581,7 +4581,7 @@ BufferIsPermanent(Buffer buffer) * not random garbage. */ bufHdr = GetBufferDescriptor(buffer - 1); - return (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT) != 0; + return (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT) != 0; } /* @@ -5044,11 +5044,11 @@ FlushRelationBuffers(Relation rel) { for (i = 0; i < NLocBuffer; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetLocalBufferDescriptor(i); if (BufTagMatchesRelFileLocator(&bufHdr->tag, &rel->rd_locator) && - ((buf_state = pg_atomic_read_u32(&bufHdr->state)) & + ((buf_state = pg_atomic_read_u64(&bufHdr->state)) & (BM_VALID | BM_DIRTY)) == (BM_VALID | BM_DIRTY)) { ErrorContextCallback errcallback; @@ -5084,7 +5084,7 @@ FlushRelationBuffers(Relation rel) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5156,7 +5156,7 @@ FlushRelationsAllBuffers(SMgrRelation *smgrs, int nrels) { SMgrSortArray *srelent = NULL; BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; /* * As in DropRelationBuffers, an unlocked precheck should be safe and @@ -5405,7 +5405,7 @@ FlushDatabaseBuffers(Oid dbid) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5553,13 +5553,13 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * is only intended to be used in cases where failing to write out the * data would be harmless anyway, it doesn't really matter. */ - if ((pg_atomic_read_u32(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != + if ((pg_atomic_read_u64(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != (BM_DIRTY | BM_JUST_DIRTIED)) { XLogRecPtr lsn = InvalidXLogRecPtr; bool dirtied = false; bool delayChkptFlags = false; - uint32 buf_state; + uint64 buf_state; /* * If we need to protect hint bit updates from torn writes, WAL-log a @@ -5571,7 +5571,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * when we call XLogInsert() since the value changes dynamically. */ if (XLogHintBitIsNeeded() && - (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT)) + (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT)) { /* * If we must not write WAL, due to a relfilelocator-specific @@ -5671,8 +5671,8 @@ UnlockBuffers(void) if (buf) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; buf_state = LockBufHdr(buf); @@ -5803,8 +5803,8 @@ LockBufferForCleanup(Buffer buffer) for (;;) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; /* Try to acquire lock */ LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); @@ -5952,7 +5952,7 @@ bool ConditionalLockBufferForCleanup(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state, + uint64 buf_state, refcount; Assert(BufferIsValid(buffer)); @@ -6010,7 +6010,7 @@ bool IsBufferCleanupOK(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); @@ -6066,7 +6066,7 @@ WaitIO(BufferDesc *buf) ConditionVariablePrepareToSleep(cv); for (;;) { - uint32 buf_state; + uint64 buf_state; PgAioWaitRef iow; /* @@ -6140,7 +6140,7 @@ WaitIO(BufferDesc *buf) bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; ResourceOwnerEnlarge(CurrentResourceOwner); @@ -6196,11 +6196,11 @@ StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) * is being released) */ void -TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio) { - uint32 buf_state; - uint32 unset_flag_bits = 0; + uint64 buf_state; + uint64 unset_flag_bits = 0; int refcount_change = 0; buf_state = LockBufHdr(buf); @@ -6261,7 +6261,7 @@ static void AbortBufferIO(Buffer buffer) { BufferDesc *buf_hdr = GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; buf_state = LockBufHdr(buf_hdr); Assert(buf_state & (BM_IO_IN_PROGRESS | BM_TAG_VALID)); @@ -6355,10 +6355,10 @@ rlocator_comparator(const void *p1, const void *p2) /* * Lock buffer header - set BM_LOCKED in buffer state. */ -uint32 +uint64 LockBufHdr(BufferDesc *desc) { - uint32 old_buf_state; + uint64 old_buf_state; Assert(!BufferIsLocal(BufferDescriptorGetBuffer(desc))); @@ -6369,7 +6369,7 @@ LockBufHdr(BufferDesc *desc) * the spin-delay infrastructure. The work necessary for that shows up * in profiles and is rarely necessary. */ - old_buf_state = pg_atomic_fetch_or_u32(&desc->state, BM_LOCKED); + old_buf_state = pg_atomic_fetch_or_u64(&desc->state, BM_LOCKED); if (likely(!(old_buf_state & BM_LOCKED))) break; /* got lock */ @@ -6382,7 +6382,7 @@ LockBufHdr(BufferDesc *desc) while (old_buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - old_buf_state = pg_atomic_read_u32(&desc->state); + old_buf_state = pg_atomic_read_u64(&desc->state); } finish_spin_delay(&delayStatus); } @@ -6403,20 +6403,20 @@ LockBufHdr(BufferDesc *desc) * Obviously the buffer could be locked by the time the value is returned, so * this is primarily useful in CAS style loops. */ -pg_noinline uint32 +pg_noinline uint64 WaitBufHdrUnlocked(BufferDesc *buf) { SpinDelayStatus delayStatus; - uint32 buf_state; + uint64 buf_state; init_local_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); while (buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); } finish_spin_delay(&delayStatus); @@ -6704,12 +6704,12 @@ ResOwnerPrintBufferPin(Datum res) static bool EvictUnpinnedBufferInternal(BufferDesc *desc, bool *buffer_flushed) { - uint32 buf_state; + uint64 buf_state; bool result; *buffer_flushed = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -6803,12 +6803,12 @@ EvictAllUnpinnedBuffers(int32 *buffers_evicted, int32 *buffers_flushed, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_flushed; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -6855,7 +6855,7 @@ EvictRelUnpinnedBuffers(Relation rel, int32 *buffers_evicted, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_flushed; CHECK_FOR_INTERRUPTS(); @@ -6897,12 +6897,12 @@ static bool MarkDirtyUnpinnedBufferInternal(Buffer buf, BufferDesc *desc, bool *buffer_already_dirty) { - uint32 buf_state; + uint64 buf_state; bool result = false; *buffer_already_dirty = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -7000,7 +7000,7 @@ MarkDirtyRelUnpinnedBuffers(Relation rel, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_already_dirty; CHECK_FOR_INTERRUPTS(); @@ -7054,12 +7054,12 @@ MarkDirtyAllUnpinnedBuffers(int32 *buffers_dirtied, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_already_dirty; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -7110,7 +7110,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) BufferDesc *buf_hdr = is_temp ? GetLocalBufferDescriptor(-buffer - 1) : GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; /* * Check that all the buffers are actually ones that could conceivably @@ -7128,7 +7128,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) } if (is_temp) - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); else buf_state = LockBufHdr(buf_hdr); @@ -7166,7 +7166,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) if (is_temp) { buf_state += BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else UnlockBufHdrExt(buf_hdr, buf_state, 0, 0, 1); @@ -7352,13 +7352,13 @@ buffer_readv_complete_one(PgAioTargetData *td, uint8 buf_off, Buffer buffer, : GetBufferDescriptor(buffer - 1); BufferTag tag = buf_hdr->tag; char *bufdata = BufferGetBlock(buffer); - uint32 set_flag_bits; + uint64 set_flag_bits; int piv_flags; /* check that the buffer is in the expected state for a read */ #ifdef USE_ASSERT_CHECKING { - uint32 buf_state = pg_atomic_read_u32(&buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_VALID)); diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c index 9a93fb335fc..b7687836188 100644 --- a/src/backend/storage/buffer/freelist.c +++ b/src/backend/storage/buffer/freelist.c @@ -86,7 +86,7 @@ typedef struct BufferAccessStrategyData /* Prototypes for internal functions */ static BufferDesc *GetBufferFromRing(BufferAccessStrategy strategy, - uint32 *buf_state); + uint64 *buf_state); static void AddBufferToRing(BufferAccessStrategy strategy, BufferDesc *buf); @@ -171,7 +171,7 @@ ClockSweepTick(void) * before returning. */ BufferDesc * -StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_ring) +StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_ring) { BufferDesc *buf; int bgwprocno; @@ -230,8 +230,8 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r trycounter = NBuffers; for (;;) { - uint32 old_buf_state; - uint32 local_buf_state; + uint64 old_buf_state; + uint64 local_buf_state; buf = GetBufferDescriptor(ClockSweepTick()); @@ -239,7 +239,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r * Check whether the buffer can be used and pin it if so. Do this * using a CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -277,7 +277,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r { local_buf_state -= BUF_USAGECOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { trycounter = NBuffers; @@ -289,7 +289,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { /* Found a usable buffer */ @@ -655,12 +655,12 @@ FreeAccessStrategy(BufferAccessStrategy strategy) * returning. */ static BufferDesc * -GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) +GetBufferFromRing(BufferAccessStrategy strategy, uint64 *buf_state) { BufferDesc *buf; Buffer bufnum; - uint32 old_buf_state; - uint32 local_buf_state; /* to avoid repeated (de-)referencing */ + uint64 old_buf_state; + uint64 local_buf_state; /* to avoid repeated (de-)referencing */ /* Advance to next ring slot */ @@ -682,7 +682,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) * Check whether the buffer can be used and pin it if so. Do this using a * CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -710,7 +710,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { *buf_state = local_buf_state; diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index f6e2b1aa288..04a540379a2 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -148,7 +148,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, } else { - uint32 buf_state; + uint64 buf_state; victim_buffer = GetLocalVictimBuffer(); bufid = -victim_buffer - 1; @@ -165,10 +165,10 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, */ bufHdr->tag = newTag; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); buf_state &= ~(BUF_FLAG_MASK | BUF_USAGECOUNT_MASK); buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); *foundPtr = false; } @@ -245,12 +245,12 @@ GetLocalVictimBuffer(void) if (LocalRefCount[victim_bufid] == 0) { - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0) { buf_state -= BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); trycounter = NLocBuffer; } else if (BUF_STATE_GET_REFCOUNT(buf_state) > 0) @@ -286,13 +286,13 @@ GetLocalVictimBuffer(void) * this buffer is not referenced but it might still be dirty. if that's * the case, write it out before reusing it! */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY) FlushLocalBuffer(bufHdr, NULL); /* * Remove the victim buffer from the hashtable and mark as invalid. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID) + if (pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID) { InvalidateLocalBuffer(bufHdr, false); @@ -417,7 +417,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, if (found) { BufferDesc *existing_hdr; - uint32 buf_state; + uint64 buf_state; UnpinLocalBuffer(BufferDescriptorGetBuffer(victim_buf_hdr)); @@ -428,18 +428,18 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, /* * Clear the BM_VALID bit, do StartLocalBufferIO() and proceed. */ - buf_state = pg_atomic_read_u32(&existing_hdr->state); + buf_state = pg_atomic_read_u64(&existing_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_DIRTY)); buf_state &= ~BM_VALID; - pg_atomic_unlocked_write_u32(&existing_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&existing_hdr->state, buf_state); /* no need to loop for local buffers */ StartLocalBufferIO(existing_hdr, true, false); } else { - uint32 buf_state = pg_atomic_read_u32(&victim_buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&victim_buf_hdr->state); Assert(!(buf_state & (BM_VALID | BM_TAG_VALID | BM_DIRTY | BM_JUST_DIRTIED))); @@ -447,7 +447,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&victim_buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&victim_buf_hdr->state, buf_state); hresult->id = victim_buf_id; @@ -467,13 +467,13 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, { Buffer buf = buffers[i]; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); buf_state |= BM_VALID; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } *extended_by = extend_by; @@ -492,7 +492,7 @@ MarkLocalBufferDirty(Buffer buffer) { int bufid; BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsLocal(buffer)); @@ -506,14 +506,14 @@ MarkLocalBufferDirty(Buffer buffer) bufHdr = GetLocalBufferDescriptor(bufid); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_DIRTY)) pgBufferUsage.local_blks_dirtied++; buf_state |= BM_DIRTY; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -522,7 +522,7 @@ MarkLocalBufferDirty(Buffer buffer) bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; /* * With AIO the buffer could have IO in progress, e.g. when there are two @@ -542,7 +542,7 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) /* Once we get here, there is definitely no I/O active on this buffer */ /* Check if someone else already did the I/O */ - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (forInput ? (buf_state & BM_VALID) : !(buf_state & BM_DIRTY)) { return false; @@ -559,11 +559,11 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) * Like TerminateBufferIO, but for local buffers */ void -TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bits, +TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint64 set_flag_bits, bool release_aio) { /* Only need to adjust flags */ - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); /* BM_IO_IN_PROGRESS isn't currently used for local buffers */ @@ -582,7 +582,7 @@ TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bit } buf_state |= set_flag_bits; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); /* local buffers don't track IO using resowners */ @@ -606,7 +606,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) { Buffer buffer = BufferDescriptorGetBuffer(bufHdr); int bufid = -buffer - 1; - uint32 buf_state; + uint64 buf_state; LocalBufferLookupEnt *hresult; /* @@ -622,7 +622,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) Assert(!pgaio_wref_valid(&bufHdr->io_wref)); } - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* * We need to test not just LocalRefCount[bufid] but also the BufferDesc @@ -647,7 +647,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) ClearBufferTag(&bufHdr->tag); buf_state &= ~BUF_FLAG_MASK; buf_state &= ~BUF_USAGECOUNT_MASK; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -671,9 +671,9 @@ DropRelationLocalBuffers(RelFileLocator rlocator, ForkNumber *forkNum, for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_TAG_VALID) || !BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -706,9 +706,9 @@ DropRelationAllLocalBuffers(RelFileLocator rlocator) for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if ((buf_state & BM_TAG_VALID) && BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -804,11 +804,11 @@ InitLocalBuffers(void) bool PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { - uint32 buf_state; + uint64 buf_state; Buffer buffer = BufferDescriptorGetBuffer(buf_hdr); int bufid = -buffer - 1; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); if (LocalRefCount[bufid] == 0) { @@ -819,7 +819,7 @@ PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { buf_state += BUF_USAGECOUNT_ONE; } - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* * See comment in PinBuffer(). @@ -856,14 +856,14 @@ UnpinLocalBufferNoOwner(Buffer buffer) if (--LocalRefCount[buffid] == 0) { BufferDesc *buf_hdr = GetLocalBufferDescriptor(buffid); - uint32 buf_state; + uint64 buf_state; NLocalPinnedBuffers--; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state -= BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* see comment in UnpinBufferNoOwner */ VALGRIND_MAKE_MEM_NOACCESS(LocalBufHdrGetBlock(buf_hdr), BLCKSZ); diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index 0c58e4b265c..529803346ce 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -199,7 +199,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) for (i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -615,7 +615,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -626,7 +626,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) * noticeably increase the cost of the function. */ bufHdr = GetBufferDescriptor(i); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (buf_state & BM_VALID) { @@ -676,7 +676,7 @@ pg_buffercache_usage_counts(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); int usage_count; CHECK_FOR_INTERRUPTS(); diff --git a/src/test/modules/test_aio/test_aio.c b/src/test/modules/test_aio/test_aio.c index e046b08f3d5..b1aa8af9ec0 100644 --- a/src/test/modules/test_aio/test_aio.c +++ b/src/test/modules/test_aio/test_aio.c @@ -308,9 +308,9 @@ create_toy_buffer(Relation rel, BlockNumber blkno) { Buffer buf; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; bool was_pinned = false; - uint32 unset_bits = 0; + uint64 unset_bits = 0; /* place buffer in shared buffers without erroring out */ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO_AND_LOCK, NULL); @@ -319,7 +319,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); } else { @@ -340,7 +340,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_state &= ~unset_bits; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else { @@ -489,7 +489,7 @@ invalidate_rel_block(PG_FUNCTION_ARGS) LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); - if (pg_atomic_read_u32(&buf_hdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&buf_hdr->state) & BM_DIRTY) { if (BufferIsLocal(buf)) FlushLocalBuffer(buf_hdr, NULL); @@ -572,7 +572,7 @@ buffer_call_terminate_io(PG_FUNCTION_ARGS) bool io_error = PG_GETARG_BOOL(3); bool release_aio = PG_GETARG_BOOL(4); bool clear_dirty = false; - uint32 set_flag_bits = 0; + uint64 set_flag_bits = 0; if (io_error) set_flag_bits |= BM_IO_ERROR; -- 2.48.1.76.g4e746b1a31.dirty --jmawlk4t5yqwiemy Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v10-0004-bufmgr-Implement-buffer-content-locks-independen.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v9 06/10] bufmgr: Change BufferDesc.state to be a 64bit atomic @ 2026-01-07 22:26 Andres Freund <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Andres Freund @ 2026-01-07 22:26 UTC (permalink / raw) This is motivated by wanting to merge buffer content locks into BufferDesc.state in a future commit, rather than having a separate lwlock (see commit c75ebc657ff more details). As this change is rather mechanical, it seems to make sense to split it out into a separate commit, for easier review. Reviewed-by: Melanie Plageman <[email protected]> Discussion: https://postgr.es/m/fvfmkr5kk4nyex56ejgxj3uzi63isfxovp2biecb4bspbjrze7@az2pljabhnff --- src/include/storage/buf_internals.h | 51 +++--- src/include/storage/procnumber.h | 14 +- src/backend/storage/buffer/buf_init.c | 2 +- src/backend/storage/buffer/bufmgr.c | 170 +++++++++--------- src/backend/storage/buffer/freelist.c | 24 +-- src/backend/storage/buffer/localbuf.c | 72 ++++---- contrib/pg_buffercache/pg_buffercache_pages.c | 8 +- src/test/modules/test_aio/test_aio.c | 12 +- 8 files changed, 178 insertions(+), 175 deletions(-) diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index 2f607ea2ac5..a4d36e9ca01 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -30,7 +30,7 @@ #include "utils/resowner.h" /* - * Buffer state is a single 32-bit variable where following data is combined. + * Buffer state is a single 64-bit variable where following data is combined. * * State of the buffer itself (in order): * - 18 bits refcount @@ -40,6 +40,9 @@ * Combining these values allows to perform some operations without locking * the buffer header, by modifying them together with a CAS loop. * + * NB: A future commit will use a significant portion of the remaining bits to + * implement buffer locking as part of the state variable. + * * The definition of buffer state components is below. */ #define BUF_REFCOUNT_BITS 18 @@ -52,27 +55,27 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, /* refcount related definitions */ #define BUF_REFCOUNT_ONE 1 #define BUF_REFCOUNT_MASK \ - ((1U << BUF_REFCOUNT_BITS) - 1) + ((UINT64CONST(1) << BUF_REFCOUNT_BITS) - 1) /* usage count related definitions */ #define BUF_USAGECOUNT_SHIFT \ BUF_REFCOUNT_BITS #define BUF_USAGECOUNT_MASK \ - (((1U << BUF_USAGECOUNT_BITS) - 1) << (BUF_USAGECOUNT_SHIFT)) + (((UINT64CONST(1) << BUF_USAGECOUNT_BITS) - 1) << (BUF_USAGECOUNT_SHIFT)) #define BUF_USAGECOUNT_ONE \ - (1U << BUF_REFCOUNT_BITS) + (UINT64CONST(1) << BUF_REFCOUNT_BITS) /* flags related definitions */ #define BUF_FLAG_SHIFT \ (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS) #define BUF_FLAG_MASK \ - (((1U << BUF_FLAG_BITS) - 1) << BUF_FLAG_SHIFT) + (((UINT64CONST(1) << BUF_FLAG_BITS) - 1) << BUF_FLAG_SHIFT) /* Get refcount and usagecount from buffer state */ #define BUF_STATE_GET_REFCOUNT(state) \ - ((state) & BUF_REFCOUNT_MASK) + ((uint32)((state) & BUF_REFCOUNT_MASK)) #define BUF_STATE_GET_USAGECOUNT(state) \ - (((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT) + ((uint32)(((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT)) /* * Flags for buffer descriptors @@ -82,7 +85,7 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, */ #define BUF_DEFINE_FLAG(flagno) \ - (1U << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + (flagno))) + (UINT64CONST(1) << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + (flagno))) /* buffer header is locked */ #define BM_LOCKED BUF_DEFINE_FLAG( 0) @@ -115,7 +118,7 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, */ #define BM_MAX_USAGE_COUNT 5 -StaticAssertDecl(BM_MAX_USAGE_COUNT < (1 << BUF_USAGECOUNT_BITS), +StaticAssertDecl(BM_MAX_USAGE_COUNT < (UINT64CONST(1) << BUF_USAGECOUNT_BITS), "BM_MAX_USAGE_COUNT doesn't fit in BUF_USAGECOUNT_BITS bits"); StaticAssertDecl(MAX_BACKENDS_BITS <= BUF_REFCOUNT_BITS, "MAX_BACKENDS_BITS needs to be <= BUF_REFCOUNT_BITS"); @@ -280,8 +283,8 @@ BufMappingPartitionLockByIndex(uint32 index) * We use this same struct for local buffer headers, but the locks are not * used and not all of the flag bits are useful either. To avoid unnecessary * overhead, manipulations of the state field should be done without actual - * atomic operations (i.e. only pg_atomic_read_u32() and - * pg_atomic_unlocked_write_u32()). + * atomic operations (i.e. only pg_atomic_read_u64() and + * pg_atomic_unlocked_write_u64()). * * Be careful to avoid increasing the size of the struct when adding or * reordering members. Keeping it below 64 bytes (the most common CPU @@ -309,7 +312,7 @@ typedef struct BufferDesc * State of the buffer, containing flags, refcount and usagecount. See * BUF_* and BM_* defines at the top of this file. */ - pg_atomic_uint32 state; + pg_atomic_uint64 state; /* * Backend of pin-count waiter. The buffer header spinlock needs to be @@ -415,7 +418,7 @@ BufferDescriptorGetContentLock(const BufferDesc *bdesc) * Functions for acquiring/releasing a shared buffer header's spinlock. Do * not apply these to local buffers! */ -extern uint32 LockBufHdr(BufferDesc *desc); +extern uint64 LockBufHdr(BufferDesc *desc); /* * Unlock the buffer header. @@ -426,9 +429,9 @@ extern uint32 LockBufHdr(BufferDesc *desc); static inline void UnlockBufHdr(BufferDesc *desc) { - Assert(pg_atomic_read_u32(&desc->state) & BM_LOCKED); + Assert(pg_atomic_read_u64(&desc->state) & BM_LOCKED); - pg_atomic_fetch_sub_u32(&desc->state, BM_LOCKED); + pg_atomic_fetch_sub_u64(&desc->state, BM_LOCKED); } /* @@ -439,14 +442,14 @@ UnlockBufHdr(BufferDesc *desc) * Note that this approach would not work for usagecount, since we need to cap * the usagecount at BM_MAX_USAGE_COUNT. */ -static inline uint32 -UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, - uint32 set_bits, uint32 unset_bits, +static inline uint64 +UnlockBufHdrExt(BufferDesc *desc, uint64 old_buf_state, + uint64 set_bits, uint64 unset_bits, int refcount_change) { for (;;) { - uint32 buf_state = old_buf_state; + uint64 buf_state = old_buf_state; Assert(buf_state & BM_LOCKED); @@ -457,7 +460,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, if (refcount_change != 0) buf_state += BUF_REFCOUNT_ONE * refcount_change; - if (pg_atomic_compare_exchange_u32(&desc->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&desc->state, &old_buf_state, buf_state)) { return old_buf_state; @@ -465,7 +468,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, } } -extern uint32 WaitBufHdrUnlocked(BufferDesc *buf); +extern uint64 WaitBufHdrUnlocked(BufferDesc *buf); /* in bufmgr.c */ @@ -525,14 +528,14 @@ extern void TrackNewBufferPin(Buffer buf); /* solely to make it easier to write tests */ extern bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait); -extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio); /* freelist.c */ extern IOContext IOContextForStrategy(BufferAccessStrategy strategy); extern BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy, - uint32 *buf_state, bool *from_ring); + uint64 *buf_state, bool *from_ring); extern bool StrategyRejectBuffer(BufferAccessStrategy strategy, BufferDesc *buf, bool from_ring); @@ -568,7 +571,7 @@ extern BlockNumber ExtendBufferedRelLocal(BufferManagerRelation bmr, uint32 *extended_by); extern void MarkLocalBufferDirty(Buffer buffer); extern void TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, - uint32 set_flag_bits, bool release_aio); + uint64 set_flag_bits, bool release_aio); extern bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait); extern void FlushLocalBuffer(BufferDesc *bufHdr, SMgrRelation reln); extern void InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced); diff --git a/src/include/storage/procnumber.h b/src/include/storage/procnumber.h index 30c360ad350..bd9cb3891cc 100644 --- a/src/include/storage/procnumber.h +++ b/src/include/storage/procnumber.h @@ -27,13 +27,13 @@ typedef int ProcNumber; /* * Note: MAX_BACKENDS_BITS is 18 as that is the space available for buffer - * refcounts in buf_internals.h. This limitation could be lifted by using a - * 64bit state; but it's unlikely to be worthwhile as 2^18-1 backends exceed - * currently realistic configurations. Even if that limitation were removed, - * we still could not a) exceed 2^23-1 because inval.c stores the ProcNumber - * as a 3-byte signed integer, b) INT_MAX/4 because some places compute - * 4*MaxBackends without any overflow check. We check that the configured - * number of backends does not exceed MAX_BACKENDS in InitializeMaxBackends(). + * refcounts in buf_internals.h. This limitation could be lifted, but it's + * unlikely to be worthwhile as 2^18-1 backends exceed currently realistic + * configurations. Even if that limitation were removed, we still could not a) + * exceed 2^23-1 because inval.c stores the ProcNumber as a 3-byte signed + * integer, b) INT_MAX/4 because some places compute 4*MaxBackends without any + * overflow check. We check that the configured number of backends does not + * exceed MAX_BACKENDS in InitializeMaxBackends(). */ #define MAX_BACKENDS_BITS 18 #define MAX_BACKENDS ((1U << MAX_BACKENDS_BITS)-1) diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index 9a312bcc7b3..7d894522526 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -121,7 +121,7 @@ BufferManagerShmemInit(void) ClearBufferTag(&buf->tag); - pg_atomic_init_u32(&buf->state, 0); + pg_atomic_init_u64(&buf->state, 0); buf->wait_backend_pgprocno = INVALID_PROC_NUMBER; buf->buf_id = i; diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index a036c2aa275..b0de8e45d4d 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -780,7 +780,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN { BufferDesc *bufHdr; BufferTag tag; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(recent_buffer)); @@ -793,7 +793,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN int b = -recent_buffer - 1; bufHdr = GetLocalBufferDescriptor(b); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* Is it still valid and holding the right tag? */ if ((buf_state & BM_VALID) && BufferTagsEqual(&tag, &bufHdr->tag)) @@ -1386,8 +1386,8 @@ StartReadBuffersImpl(ReadBuffersOperation *operation, bufHdr = GetLocalBufferDescriptor(-buffers[i] - 1); else bufHdr = GetBufferDescriptor(buffers[i] - 1); - Assert(pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID); - found = pg_atomic_read_u32(&bufHdr->state) & BM_VALID; + Assert(pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID); + found = pg_atomic_read_u64(&bufHdr->state) & BM_VALID; } else { @@ -1613,10 +1613,10 @@ CheckReadBuffersOperation(ReadBuffersOperation *operation, bool is_complete) GetBufferDescriptor(buffer - 1); Assert(BufferGetBlockNumber(buffer) == operation->blocknum + i); - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_TAG_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_TAG_VALID); if (i < operation->nblocks_done) - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_VALID); } #endif } @@ -2083,8 +2083,8 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, int existing_buf_id; Buffer victim_buffer; BufferDesc *victim_buf_hdr; - uint32 victim_buf_state; - uint32 set_bits = 0; + uint64 victim_buf_state; + uint64 set_bits = 0; /* Make sure we will have room to remember the buffer pin */ ResourceOwnerEnlarge(CurrentResourceOwner); @@ -2251,7 +2251,7 @@ InvalidateBuffer(BufferDesc *buf) uint32 oldHash; /* hash value for oldTag */ LWLock *oldPartitionLock; /* buffer partition lock for it */ uint32 oldFlags; - uint32 buf_state; + uint64 buf_state; /* Save the original buffer tag before dropping the spinlock */ oldTag = buf->tag; @@ -2342,7 +2342,7 @@ retry: static bool InvalidateVictimBuffer(BufferDesc *buf_hdr) { - uint32 buf_state; + uint64 buf_state; uint32 hash; LWLock *partition_lock; BufferTag tag; @@ -2402,10 +2402,10 @@ InvalidateVictimBuffer(BufferDesc *buf_hdr) LWLockRelease(partition_lock); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(!(buf_state & (BM_DIRTY | BM_VALID | BM_TAG_VALID))); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); - Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u32(&buf_hdr->state)) > 0); + Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u64(&buf_hdr->state)) > 0); return true; } @@ -2415,7 +2415,7 @@ GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context) { BufferDesc *buf_hdr; Buffer buf; - uint32 buf_state; + uint64 buf_state; bool from_ring; /* @@ -2548,7 +2548,7 @@ again: /* a final set of sanity checks */ #ifdef USE_ASSERT_CHECKING - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) == 1); Assert(!(buf_state & (BM_TAG_VALID | BM_VALID | BM_DIRTY))); @@ -2839,13 +2839,13 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, */ do { - pg_atomic_fetch_and_u32(&existing_hdr->state, ~BM_VALID); + pg_atomic_fetch_and_u64(&existing_hdr->state, ~BM_VALID); } while (!StartBufferIO(existing_hdr, true, false)); } else { - uint32 buf_state; - uint32 set_bits = 0; + uint64 buf_state; + uint64 set_bits = 0; buf_state = LockBufHdr(victim_buf_hdr); @@ -3021,7 +3021,7 @@ BufferIsDirty(Buffer buffer) Assert(BufferIsLockedByMeInMode(buffer, BUFFER_LOCK_EXCLUSIVE)); } - return pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY; + return pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY; } /* @@ -3037,8 +3037,8 @@ void MarkBufferDirty(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; if (!BufferIsValid(buffer)) elog(ERROR, "bad buffer ID: %d", buffer); @@ -3058,7 +3058,7 @@ MarkBufferDirty(Buffer buffer) * NB: We have to wait for the buffer header spinlock to be not held, as * TerminateBufferIO() relies on the spinlock. */ - old_buf_state = pg_atomic_read_u32(&bufHdr->state); + old_buf_state = pg_atomic_read_u64(&bufHdr->state); for (;;) { if (old_buf_state & BM_LOCKED) @@ -3069,7 +3069,7 @@ MarkBufferDirty(Buffer buffer) Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state |= BM_DIRTY | BM_JUST_DIRTIED; - if (pg_atomic_compare_exchange_u32(&bufHdr->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&bufHdr->state, &old_buf_state, buf_state)) break; } @@ -3173,10 +3173,10 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, if (ref == NULL) { - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { if (unlikely(skip_if_not_valid && !(old_buf_state & BM_VALID))) @@ -3210,7 +3210,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, buf_state += BUF_USAGECOUNT_ONE; } - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, buf_state)) { result = (buf_state & BM_VALID) != 0; @@ -3237,7 +3237,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, * that the buffer page is legitimately non-accessible here. We * cannot meddle with that. */ - result = (pg_atomic_read_u32(&buf->state) & BM_VALID) != 0; + result = (pg_atomic_read_u64(&buf->state) & BM_VALID) != 0; Assert(ref->data.refcount > 0); ref->data.refcount++; @@ -3272,7 +3272,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, static void PinBuffer_Locked(BufferDesc *buf) { - uint32 old_buf_state; + uint64 old_buf_state; /* * As explained, We don't expect any preexisting pins. That allows us to @@ -3284,7 +3284,7 @@ PinBuffer_Locked(BufferDesc *buf) * Since we hold the buffer spinlock, we can update the buffer state and * release the lock in one operation. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); UnlockBufHdrExt(buf, old_buf_state, 0, 0, 1); @@ -3314,7 +3314,7 @@ WakePinCountWaiter(BufferDesc *buf) * BM_PIN_COUNT_WAITER if it stops waiting for a reason other than this * backend waking it up. */ - uint32 buf_state = LockBufHdr(buf); + uint64 buf_state = LockBufHdr(buf); if ((buf_state & BM_PIN_COUNT_WAITER) && BUF_STATE_GET_REFCOUNT(buf_state) == 1) @@ -3361,7 +3361,7 @@ UnpinBufferNoOwner(BufferDesc *buf) ref->data.refcount--; if (ref->data.refcount == 0) { - uint32 old_buf_state; + uint64 old_buf_state; /* * Mark buffer non-accessible to Valgrind. @@ -3379,7 +3379,7 @@ UnpinBufferNoOwner(BufferDesc *buf) Assert(!LWLockHeldByMe(BufferDescriptorGetContentLock(buf))); /* decrement the shared reference count */ - old_buf_state = pg_atomic_fetch_sub_u32(&buf->state, BUF_REFCOUNT_ONE); + old_buf_state = pg_atomic_fetch_sub_u64(&buf->state, BUF_REFCOUNT_ONE); /* Support LockBufferForCleanup() */ if (old_buf_state & BM_PIN_COUNT_WAITER) @@ -3436,7 +3436,7 @@ TrackNewBufferPin(Buffer buf) static void BufferSync(int flags) { - uint32 buf_state; + uint64 buf_state; int buf_id; int num_to_scan; int num_spaces; @@ -3446,7 +3446,7 @@ BufferSync(int flags) Oid last_tsid; binaryheap *ts_heap; int i; - uint32 mask = BM_DIRTY; + uint64 mask = BM_DIRTY; WritebackContext wb_context; /* @@ -3478,7 +3478,7 @@ BufferSync(int flags) for (buf_id = 0; buf_id < NBuffers; buf_id++) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); - uint32 set_bits = 0; + uint64 set_bits = 0; /* * Header spinlock is enough to examine BM_DIRTY, see comment in @@ -3645,7 +3645,7 @@ BufferSync(int flags) * write the buffer though we didn't need to. It doesn't seem worth * guarding against this, though. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_CHECKPOINT_NEEDED) + if (pg_atomic_read_u64(&bufHdr->state) & BM_CHECKPOINT_NEEDED) { if (SyncOneBuffer(buf_id, false, &wb_context) & BUF_WRITTEN) { @@ -4015,7 +4015,7 @@ SyncOneBuffer(int buf_id, bool skip_recently_used, WritebackContext *wb_context) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); int result = 0; - uint32 buf_state; + uint64 buf_state; BufferTag tag; /* Make sure we can handle the pin */ @@ -4264,7 +4264,7 @@ DebugPrintBufferRefcount(Buffer buffer) int32 loccount; char *result; ProcNumber backend; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); if (BufferIsLocal(buffer)) @@ -4281,9 +4281,9 @@ DebugPrintBufferRefcount(Buffer buffer) } /* theoretically we should lock the bufHdr here */ - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); - result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%x, refcount=%u %d)", + result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%" PRIx64 ", refcount=%u %d)", buffer, relpathbackend(BufTagGetRelFileLocator(&buf->tag), backend, BufTagGetForkNum(&buf->tag)).str, @@ -4383,7 +4383,7 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object, instr_time io_start; Block bufBlock; char *bufToWrite; - uint32 buf_state; + uint64 buf_state; /* * Try to start an I/O operation. If StartBufferIO returns false, then @@ -4581,7 +4581,7 @@ BufferIsPermanent(Buffer buffer) * not random garbage. */ bufHdr = GetBufferDescriptor(buffer - 1); - return (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT) != 0; + return (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT) != 0; } /* @@ -5044,11 +5044,11 @@ FlushRelationBuffers(Relation rel) { for (i = 0; i < NLocBuffer; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetLocalBufferDescriptor(i); if (BufTagMatchesRelFileLocator(&bufHdr->tag, &rel->rd_locator) && - ((buf_state = pg_atomic_read_u32(&bufHdr->state)) & + ((buf_state = pg_atomic_read_u64(&bufHdr->state)) & (BM_VALID | BM_DIRTY)) == (BM_VALID | BM_DIRTY)) { ErrorContextCallback errcallback; @@ -5084,7 +5084,7 @@ FlushRelationBuffers(Relation rel) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5156,7 +5156,7 @@ FlushRelationsAllBuffers(SMgrRelation *smgrs, int nrels) { SMgrSortArray *srelent = NULL; BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; /* * As in DropRelationBuffers, an unlocked precheck should be safe and @@ -5405,7 +5405,7 @@ FlushDatabaseBuffers(Oid dbid) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5553,13 +5553,13 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * is only intended to be used in cases where failing to write out the * data would be harmless anyway, it doesn't really matter. */ - if ((pg_atomic_read_u32(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != + if ((pg_atomic_read_u64(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != (BM_DIRTY | BM_JUST_DIRTIED)) { XLogRecPtr lsn = InvalidXLogRecPtr; bool dirtied = false; bool delayChkptFlags = false; - uint32 buf_state; + uint64 buf_state; /* * If we need to protect hint bit updates from torn writes, WAL-log a @@ -5571,7 +5571,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * when we call XLogInsert() since the value changes dynamically. */ if (XLogHintBitIsNeeded() && - (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT)) + (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT)) { /* * If we must not write WAL, due to a relfilelocator-specific @@ -5671,8 +5671,8 @@ UnlockBuffers(void) if (buf) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; buf_state = LockBufHdr(buf); @@ -5803,8 +5803,8 @@ LockBufferForCleanup(Buffer buffer) for (;;) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; /* Try to acquire lock */ LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); @@ -5952,7 +5952,7 @@ bool ConditionalLockBufferForCleanup(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state, + uint64 buf_state, refcount; Assert(BufferIsValid(buffer)); @@ -6010,7 +6010,7 @@ bool IsBufferCleanupOK(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); @@ -6066,7 +6066,7 @@ WaitIO(BufferDesc *buf) ConditionVariablePrepareToSleep(cv); for (;;) { - uint32 buf_state; + uint64 buf_state; PgAioWaitRef iow; /* @@ -6140,7 +6140,7 @@ WaitIO(BufferDesc *buf) bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; ResourceOwnerEnlarge(CurrentResourceOwner); @@ -6196,11 +6196,11 @@ StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) * is being released) */ void -TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio) { - uint32 buf_state; - uint32 unset_flag_bits = 0; + uint64 buf_state; + uint64 unset_flag_bits = 0; int refcount_change = 0; buf_state = LockBufHdr(buf); @@ -6261,7 +6261,7 @@ static void AbortBufferIO(Buffer buffer) { BufferDesc *buf_hdr = GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; buf_state = LockBufHdr(buf_hdr); Assert(buf_state & (BM_IO_IN_PROGRESS | BM_TAG_VALID)); @@ -6355,10 +6355,10 @@ rlocator_comparator(const void *p1, const void *p2) /* * Lock buffer header - set BM_LOCKED in buffer state. */ -uint32 +uint64 LockBufHdr(BufferDesc *desc) { - uint32 old_buf_state; + uint64 old_buf_state; Assert(!BufferIsLocal(BufferDescriptorGetBuffer(desc))); @@ -6369,7 +6369,7 @@ LockBufHdr(BufferDesc *desc) * the spin-delay infrastructure. The work necessary for that shows up * in profiles and is rarely necessary. */ - old_buf_state = pg_atomic_fetch_or_u32(&desc->state, BM_LOCKED); + old_buf_state = pg_atomic_fetch_or_u64(&desc->state, BM_LOCKED); if (likely(!(old_buf_state & BM_LOCKED))) break; /* got lock */ @@ -6382,7 +6382,7 @@ LockBufHdr(BufferDesc *desc) while (old_buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - old_buf_state = pg_atomic_read_u32(&desc->state); + old_buf_state = pg_atomic_read_u64(&desc->state); } finish_spin_delay(&delayStatus); } @@ -6403,20 +6403,20 @@ LockBufHdr(BufferDesc *desc) * Obviously the buffer could be locked by the time the value is returned, so * this is primarily useful in CAS style loops. */ -pg_noinline uint32 +pg_noinline uint64 WaitBufHdrUnlocked(BufferDesc *buf) { SpinDelayStatus delayStatus; - uint32 buf_state; + uint64 buf_state; init_local_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); while (buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); } finish_spin_delay(&delayStatus); @@ -6704,12 +6704,12 @@ ResOwnerPrintBufferPin(Datum res) static bool EvictUnpinnedBufferInternal(BufferDesc *desc, bool *buffer_flushed) { - uint32 buf_state; + uint64 buf_state; bool result; *buffer_flushed = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -6803,12 +6803,12 @@ EvictAllUnpinnedBuffers(int32 *buffers_evicted, int32 *buffers_flushed, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_flushed; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -6855,7 +6855,7 @@ EvictRelUnpinnedBuffers(Relation rel, int32 *buffers_evicted, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_flushed; CHECK_FOR_INTERRUPTS(); @@ -6897,12 +6897,12 @@ static bool MarkDirtyUnpinnedBufferInternal(Buffer buf, BufferDesc *desc, bool *buffer_already_dirty) { - uint32 buf_state; + uint64 buf_state; bool result = false; *buffer_already_dirty = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -7000,7 +7000,7 @@ MarkDirtyRelUnpinnedBuffers(Relation rel, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_already_dirty; CHECK_FOR_INTERRUPTS(); @@ -7054,12 +7054,12 @@ MarkDirtyAllUnpinnedBuffers(int32 *buffers_dirtied, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_already_dirty; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -7110,7 +7110,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) BufferDesc *buf_hdr = is_temp ? GetLocalBufferDescriptor(-buffer - 1) : GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; /* * Check that all the buffers are actually ones that could conceivably @@ -7128,7 +7128,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) } if (is_temp) - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); else buf_state = LockBufHdr(buf_hdr); @@ -7166,7 +7166,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) if (is_temp) { buf_state += BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else UnlockBufHdrExt(buf_hdr, buf_state, 0, 0, 1); @@ -7352,13 +7352,13 @@ buffer_readv_complete_one(PgAioTargetData *td, uint8 buf_off, Buffer buffer, : GetBufferDescriptor(buffer - 1); BufferTag tag = buf_hdr->tag; char *bufdata = BufferGetBlock(buffer); - uint32 set_flag_bits; + uint64 set_flag_bits; int piv_flags; /* check that the buffer is in the expected state for a read */ #ifdef USE_ASSERT_CHECKING { - uint32 buf_state = pg_atomic_read_u32(&buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_VALID)); diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c index 9a93fb335fc..b7687836188 100644 --- a/src/backend/storage/buffer/freelist.c +++ b/src/backend/storage/buffer/freelist.c @@ -86,7 +86,7 @@ typedef struct BufferAccessStrategyData /* Prototypes for internal functions */ static BufferDesc *GetBufferFromRing(BufferAccessStrategy strategy, - uint32 *buf_state); + uint64 *buf_state); static void AddBufferToRing(BufferAccessStrategy strategy, BufferDesc *buf); @@ -171,7 +171,7 @@ ClockSweepTick(void) * before returning. */ BufferDesc * -StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_ring) +StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_ring) { BufferDesc *buf; int bgwprocno; @@ -230,8 +230,8 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r trycounter = NBuffers; for (;;) { - uint32 old_buf_state; - uint32 local_buf_state; + uint64 old_buf_state; + uint64 local_buf_state; buf = GetBufferDescriptor(ClockSweepTick()); @@ -239,7 +239,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r * Check whether the buffer can be used and pin it if so. Do this * using a CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -277,7 +277,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r { local_buf_state -= BUF_USAGECOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { trycounter = NBuffers; @@ -289,7 +289,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { /* Found a usable buffer */ @@ -655,12 +655,12 @@ FreeAccessStrategy(BufferAccessStrategy strategy) * returning. */ static BufferDesc * -GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) +GetBufferFromRing(BufferAccessStrategy strategy, uint64 *buf_state) { BufferDesc *buf; Buffer bufnum; - uint32 old_buf_state; - uint32 local_buf_state; /* to avoid repeated (de-)referencing */ + uint64 old_buf_state; + uint64 local_buf_state; /* to avoid repeated (de-)referencing */ /* Advance to next ring slot */ @@ -682,7 +682,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) * Check whether the buffer can be used and pin it if so. Do this using a * CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -710,7 +710,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { *buf_state = local_buf_state; diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index f6e2b1aa288..04a540379a2 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -148,7 +148,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, } else { - uint32 buf_state; + uint64 buf_state; victim_buffer = GetLocalVictimBuffer(); bufid = -victim_buffer - 1; @@ -165,10 +165,10 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, */ bufHdr->tag = newTag; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); buf_state &= ~(BUF_FLAG_MASK | BUF_USAGECOUNT_MASK); buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); *foundPtr = false; } @@ -245,12 +245,12 @@ GetLocalVictimBuffer(void) if (LocalRefCount[victim_bufid] == 0) { - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0) { buf_state -= BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); trycounter = NLocBuffer; } else if (BUF_STATE_GET_REFCOUNT(buf_state) > 0) @@ -286,13 +286,13 @@ GetLocalVictimBuffer(void) * this buffer is not referenced but it might still be dirty. if that's * the case, write it out before reusing it! */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY) FlushLocalBuffer(bufHdr, NULL); /* * Remove the victim buffer from the hashtable and mark as invalid. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID) + if (pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID) { InvalidateLocalBuffer(bufHdr, false); @@ -417,7 +417,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, if (found) { BufferDesc *existing_hdr; - uint32 buf_state; + uint64 buf_state; UnpinLocalBuffer(BufferDescriptorGetBuffer(victim_buf_hdr)); @@ -428,18 +428,18 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, /* * Clear the BM_VALID bit, do StartLocalBufferIO() and proceed. */ - buf_state = pg_atomic_read_u32(&existing_hdr->state); + buf_state = pg_atomic_read_u64(&existing_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_DIRTY)); buf_state &= ~BM_VALID; - pg_atomic_unlocked_write_u32(&existing_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&existing_hdr->state, buf_state); /* no need to loop for local buffers */ StartLocalBufferIO(existing_hdr, true, false); } else { - uint32 buf_state = pg_atomic_read_u32(&victim_buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&victim_buf_hdr->state); Assert(!(buf_state & (BM_VALID | BM_TAG_VALID | BM_DIRTY | BM_JUST_DIRTIED))); @@ -447,7 +447,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&victim_buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&victim_buf_hdr->state, buf_state); hresult->id = victim_buf_id; @@ -467,13 +467,13 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, { Buffer buf = buffers[i]; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); buf_state |= BM_VALID; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } *extended_by = extend_by; @@ -492,7 +492,7 @@ MarkLocalBufferDirty(Buffer buffer) { int bufid; BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsLocal(buffer)); @@ -506,14 +506,14 @@ MarkLocalBufferDirty(Buffer buffer) bufHdr = GetLocalBufferDescriptor(bufid); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_DIRTY)) pgBufferUsage.local_blks_dirtied++; buf_state |= BM_DIRTY; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -522,7 +522,7 @@ MarkLocalBufferDirty(Buffer buffer) bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; /* * With AIO the buffer could have IO in progress, e.g. when there are two @@ -542,7 +542,7 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) /* Once we get here, there is definitely no I/O active on this buffer */ /* Check if someone else already did the I/O */ - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (forInput ? (buf_state & BM_VALID) : !(buf_state & BM_DIRTY)) { return false; @@ -559,11 +559,11 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) * Like TerminateBufferIO, but for local buffers */ void -TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bits, +TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint64 set_flag_bits, bool release_aio) { /* Only need to adjust flags */ - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); /* BM_IO_IN_PROGRESS isn't currently used for local buffers */ @@ -582,7 +582,7 @@ TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bit } buf_state |= set_flag_bits; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); /* local buffers don't track IO using resowners */ @@ -606,7 +606,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) { Buffer buffer = BufferDescriptorGetBuffer(bufHdr); int bufid = -buffer - 1; - uint32 buf_state; + uint64 buf_state; LocalBufferLookupEnt *hresult; /* @@ -622,7 +622,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) Assert(!pgaio_wref_valid(&bufHdr->io_wref)); } - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* * We need to test not just LocalRefCount[bufid] but also the BufferDesc @@ -647,7 +647,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) ClearBufferTag(&bufHdr->tag); buf_state &= ~BUF_FLAG_MASK; buf_state &= ~BUF_USAGECOUNT_MASK; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -671,9 +671,9 @@ DropRelationLocalBuffers(RelFileLocator rlocator, ForkNumber *forkNum, for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_TAG_VALID) || !BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -706,9 +706,9 @@ DropRelationAllLocalBuffers(RelFileLocator rlocator) for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if ((buf_state & BM_TAG_VALID) && BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -804,11 +804,11 @@ InitLocalBuffers(void) bool PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { - uint32 buf_state; + uint64 buf_state; Buffer buffer = BufferDescriptorGetBuffer(buf_hdr); int bufid = -buffer - 1; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); if (LocalRefCount[bufid] == 0) { @@ -819,7 +819,7 @@ PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { buf_state += BUF_USAGECOUNT_ONE; } - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* * See comment in PinBuffer(). @@ -856,14 +856,14 @@ UnpinLocalBufferNoOwner(Buffer buffer) if (--LocalRefCount[buffid] == 0) { BufferDesc *buf_hdr = GetLocalBufferDescriptor(buffid); - uint32 buf_state; + uint64 buf_state; NLocalPinnedBuffers--; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state -= BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* see comment in UnpinBufferNoOwner */ VALGRIND_MAKE_MEM_NOACCESS(LocalBufHdrGetBlock(buf_hdr), BLCKSZ); diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index 0c58e4b265c..529803346ce 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -199,7 +199,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) for (i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -615,7 +615,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -626,7 +626,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) * noticeably increase the cost of the function. */ bufHdr = GetBufferDescriptor(i); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (buf_state & BM_VALID) { @@ -676,7 +676,7 @@ pg_buffercache_usage_counts(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); int usage_count; CHECK_FOR_INTERRUPTS(); diff --git a/src/test/modules/test_aio/test_aio.c b/src/test/modules/test_aio/test_aio.c index e046b08f3d5..b1aa8af9ec0 100644 --- a/src/test/modules/test_aio/test_aio.c +++ b/src/test/modules/test_aio/test_aio.c @@ -308,9 +308,9 @@ create_toy_buffer(Relation rel, BlockNumber blkno) { Buffer buf; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; bool was_pinned = false; - uint32 unset_bits = 0; + uint64 unset_bits = 0; /* place buffer in shared buffers without erroring out */ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO_AND_LOCK, NULL); @@ -319,7 +319,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); } else { @@ -340,7 +340,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_state &= ~unset_bits; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else { @@ -489,7 +489,7 @@ invalidate_rel_block(PG_FUNCTION_ARGS) LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); - if (pg_atomic_read_u32(&buf_hdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&buf_hdr->state) & BM_DIRTY) { if (BufferIsLocal(buf)) FlushLocalBuffer(buf_hdr, NULL); @@ -572,7 +572,7 @@ buffer_call_terminate_io(PG_FUNCTION_ARGS) bool io_error = PG_GETARG_BOOL(3); bool release_aio = PG_GETARG_BOOL(4); bool clear_dirty = false; - uint32 set_flag_bits = 0; + uint64 set_flag_bits = 0; if (io_error) set_flag_bits |= BM_IO_ERROR; -- 2.48.1.76.g4e746b1a31.dirty --rkiyqpij3ajqn7ww Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v9-0007-bufmgr-Implement-buffer-content-locks-independent.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v10 3/8] bufmgr: Change BufferDesc.state to be a 64-bit atomic @ 2026-01-07 22:26 Andres Freund <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Andres Freund @ 2026-01-07 22:26 UTC (permalink / raw) This is motivated by wanting to merge buffer content locks into BufferDesc.state in a future commit, rather than having a separate lwlock (see commit c75ebc657ff for more details). As this change is rather mechanical, it seems to make sense to split it out into a separate commit, for easier review. Reviewed-by: Melanie Plageman <[email protected]> Discussion: https://postgr.es/m/fvfmkr5kk4nyex56ejgxj3uzi63isfxovp2biecb4bspbjrze7@az2pljabhnff --- src/include/storage/buf_internals.h | 51 +++--- src/include/storage/procnumber.h | 14 +- src/backend/storage/buffer/buf_init.c | 2 +- src/backend/storage/buffer/bufmgr.c | 170 +++++++++--------- src/backend/storage/buffer/freelist.c | 24 +-- src/backend/storage/buffer/localbuf.c | 72 ++++---- contrib/pg_buffercache/pg_buffercache_pages.c | 8 +- src/test/modules/test_aio/test_aio.c | 12 +- 8 files changed, 178 insertions(+), 175 deletions(-) diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index 2f607ea2ac5..a4d36e9ca01 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -30,7 +30,7 @@ #include "utils/resowner.h" /* - * Buffer state is a single 32-bit variable where following data is combined. + * Buffer state is a single 64-bit variable where following data is combined. * * State of the buffer itself (in order): * - 18 bits refcount @@ -40,6 +40,9 @@ * Combining these values allows to perform some operations without locking * the buffer header, by modifying them together with a CAS loop. * + * NB: A future commit will use a significant portion of the remaining bits to + * implement buffer locking as part of the state variable. + * * The definition of buffer state components is below. */ #define BUF_REFCOUNT_BITS 18 @@ -52,27 +55,27 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, /* refcount related definitions */ #define BUF_REFCOUNT_ONE 1 #define BUF_REFCOUNT_MASK \ - ((1U << BUF_REFCOUNT_BITS) - 1) + ((UINT64CONST(1) << BUF_REFCOUNT_BITS) - 1) /* usage count related definitions */ #define BUF_USAGECOUNT_SHIFT \ BUF_REFCOUNT_BITS #define BUF_USAGECOUNT_MASK \ - (((1U << BUF_USAGECOUNT_BITS) - 1) << (BUF_USAGECOUNT_SHIFT)) + (((UINT64CONST(1) << BUF_USAGECOUNT_BITS) - 1) << (BUF_USAGECOUNT_SHIFT)) #define BUF_USAGECOUNT_ONE \ - (1U << BUF_REFCOUNT_BITS) + (UINT64CONST(1) << BUF_REFCOUNT_BITS) /* flags related definitions */ #define BUF_FLAG_SHIFT \ (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS) #define BUF_FLAG_MASK \ - (((1U << BUF_FLAG_BITS) - 1) << BUF_FLAG_SHIFT) + (((UINT64CONST(1) << BUF_FLAG_BITS) - 1) << BUF_FLAG_SHIFT) /* Get refcount and usagecount from buffer state */ #define BUF_STATE_GET_REFCOUNT(state) \ - ((state) & BUF_REFCOUNT_MASK) + ((uint32)((state) & BUF_REFCOUNT_MASK)) #define BUF_STATE_GET_USAGECOUNT(state) \ - (((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT) + ((uint32)(((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT)) /* * Flags for buffer descriptors @@ -82,7 +85,7 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, */ #define BUF_DEFINE_FLAG(flagno) \ - (1U << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + (flagno))) + (UINT64CONST(1) << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + (flagno))) /* buffer header is locked */ #define BM_LOCKED BUF_DEFINE_FLAG( 0) @@ -115,7 +118,7 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, */ #define BM_MAX_USAGE_COUNT 5 -StaticAssertDecl(BM_MAX_USAGE_COUNT < (1 << BUF_USAGECOUNT_BITS), +StaticAssertDecl(BM_MAX_USAGE_COUNT < (UINT64CONST(1) << BUF_USAGECOUNT_BITS), "BM_MAX_USAGE_COUNT doesn't fit in BUF_USAGECOUNT_BITS bits"); StaticAssertDecl(MAX_BACKENDS_BITS <= BUF_REFCOUNT_BITS, "MAX_BACKENDS_BITS needs to be <= BUF_REFCOUNT_BITS"); @@ -280,8 +283,8 @@ BufMappingPartitionLockByIndex(uint32 index) * We use this same struct for local buffer headers, but the locks are not * used and not all of the flag bits are useful either. To avoid unnecessary * overhead, manipulations of the state field should be done without actual - * atomic operations (i.e. only pg_atomic_read_u32() and - * pg_atomic_unlocked_write_u32()). + * atomic operations (i.e. only pg_atomic_read_u64() and + * pg_atomic_unlocked_write_u64()). * * Be careful to avoid increasing the size of the struct when adding or * reordering members. Keeping it below 64 bytes (the most common CPU @@ -309,7 +312,7 @@ typedef struct BufferDesc * State of the buffer, containing flags, refcount and usagecount. See * BUF_* and BM_* defines at the top of this file. */ - pg_atomic_uint32 state; + pg_atomic_uint64 state; /* * Backend of pin-count waiter. The buffer header spinlock needs to be @@ -415,7 +418,7 @@ BufferDescriptorGetContentLock(const BufferDesc *bdesc) * Functions for acquiring/releasing a shared buffer header's spinlock. Do * not apply these to local buffers! */ -extern uint32 LockBufHdr(BufferDesc *desc); +extern uint64 LockBufHdr(BufferDesc *desc); /* * Unlock the buffer header. @@ -426,9 +429,9 @@ extern uint32 LockBufHdr(BufferDesc *desc); static inline void UnlockBufHdr(BufferDesc *desc) { - Assert(pg_atomic_read_u32(&desc->state) & BM_LOCKED); + Assert(pg_atomic_read_u64(&desc->state) & BM_LOCKED); - pg_atomic_fetch_sub_u32(&desc->state, BM_LOCKED); + pg_atomic_fetch_sub_u64(&desc->state, BM_LOCKED); } /* @@ -439,14 +442,14 @@ UnlockBufHdr(BufferDesc *desc) * Note that this approach would not work for usagecount, since we need to cap * the usagecount at BM_MAX_USAGE_COUNT. */ -static inline uint32 -UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, - uint32 set_bits, uint32 unset_bits, +static inline uint64 +UnlockBufHdrExt(BufferDesc *desc, uint64 old_buf_state, + uint64 set_bits, uint64 unset_bits, int refcount_change) { for (;;) { - uint32 buf_state = old_buf_state; + uint64 buf_state = old_buf_state; Assert(buf_state & BM_LOCKED); @@ -457,7 +460,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, if (refcount_change != 0) buf_state += BUF_REFCOUNT_ONE * refcount_change; - if (pg_atomic_compare_exchange_u32(&desc->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&desc->state, &old_buf_state, buf_state)) { return old_buf_state; @@ -465,7 +468,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, } } -extern uint32 WaitBufHdrUnlocked(BufferDesc *buf); +extern uint64 WaitBufHdrUnlocked(BufferDesc *buf); /* in bufmgr.c */ @@ -525,14 +528,14 @@ extern void TrackNewBufferPin(Buffer buf); /* solely to make it easier to write tests */ extern bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait); -extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio); /* freelist.c */ extern IOContext IOContextForStrategy(BufferAccessStrategy strategy); extern BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy, - uint32 *buf_state, bool *from_ring); + uint64 *buf_state, bool *from_ring); extern bool StrategyRejectBuffer(BufferAccessStrategy strategy, BufferDesc *buf, bool from_ring); @@ -568,7 +571,7 @@ extern BlockNumber ExtendBufferedRelLocal(BufferManagerRelation bmr, uint32 *extended_by); extern void MarkLocalBufferDirty(Buffer buffer); extern void TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, - uint32 set_flag_bits, bool release_aio); + uint64 set_flag_bits, bool release_aio); extern bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait); extern void FlushLocalBuffer(BufferDesc *bufHdr, SMgrRelation reln); extern void InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced); diff --git a/src/include/storage/procnumber.h b/src/include/storage/procnumber.h index 30c360ad350..bd9cb3891cc 100644 --- a/src/include/storage/procnumber.h +++ b/src/include/storage/procnumber.h @@ -27,13 +27,13 @@ typedef int ProcNumber; /* * Note: MAX_BACKENDS_BITS is 18 as that is the space available for buffer - * refcounts in buf_internals.h. This limitation could be lifted by using a - * 64bit state; but it's unlikely to be worthwhile as 2^18-1 backends exceed - * currently realistic configurations. Even if that limitation were removed, - * we still could not a) exceed 2^23-1 because inval.c stores the ProcNumber - * as a 3-byte signed integer, b) INT_MAX/4 because some places compute - * 4*MaxBackends without any overflow check. We check that the configured - * number of backends does not exceed MAX_BACKENDS in InitializeMaxBackends(). + * refcounts in buf_internals.h. This limitation could be lifted, but it's + * unlikely to be worthwhile as 2^18-1 backends exceed currently realistic + * configurations. Even if that limitation were removed, we still could not a) + * exceed 2^23-1 because inval.c stores the ProcNumber as a 3-byte signed + * integer, b) INT_MAX/4 because some places compute 4*MaxBackends without any + * overflow check. We check that the configured number of backends does not + * exceed MAX_BACKENDS in InitializeMaxBackends(). */ #define MAX_BACKENDS_BITS 18 #define MAX_BACKENDS ((1U << MAX_BACKENDS_BITS)-1) diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index 9a312bcc7b3..7d894522526 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -121,7 +121,7 @@ BufferManagerShmemInit(void) ClearBufferTag(&buf->tag); - pg_atomic_init_u32(&buf->state, 0); + pg_atomic_init_u64(&buf->state, 0); buf->wait_backend_pgprocno = INVALID_PROC_NUMBER; buf->buf_id = i; diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index a036c2aa275..b0de8e45d4d 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -780,7 +780,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN { BufferDesc *bufHdr; BufferTag tag; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(recent_buffer)); @@ -793,7 +793,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN int b = -recent_buffer - 1; bufHdr = GetLocalBufferDescriptor(b); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* Is it still valid and holding the right tag? */ if ((buf_state & BM_VALID) && BufferTagsEqual(&tag, &bufHdr->tag)) @@ -1386,8 +1386,8 @@ StartReadBuffersImpl(ReadBuffersOperation *operation, bufHdr = GetLocalBufferDescriptor(-buffers[i] - 1); else bufHdr = GetBufferDescriptor(buffers[i] - 1); - Assert(pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID); - found = pg_atomic_read_u32(&bufHdr->state) & BM_VALID; + Assert(pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID); + found = pg_atomic_read_u64(&bufHdr->state) & BM_VALID; } else { @@ -1613,10 +1613,10 @@ CheckReadBuffersOperation(ReadBuffersOperation *operation, bool is_complete) GetBufferDescriptor(buffer - 1); Assert(BufferGetBlockNumber(buffer) == operation->blocknum + i); - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_TAG_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_TAG_VALID); if (i < operation->nblocks_done) - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_VALID); } #endif } @@ -2083,8 +2083,8 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, int existing_buf_id; Buffer victim_buffer; BufferDesc *victim_buf_hdr; - uint32 victim_buf_state; - uint32 set_bits = 0; + uint64 victim_buf_state; + uint64 set_bits = 0; /* Make sure we will have room to remember the buffer pin */ ResourceOwnerEnlarge(CurrentResourceOwner); @@ -2251,7 +2251,7 @@ InvalidateBuffer(BufferDesc *buf) uint32 oldHash; /* hash value for oldTag */ LWLock *oldPartitionLock; /* buffer partition lock for it */ uint32 oldFlags; - uint32 buf_state; + uint64 buf_state; /* Save the original buffer tag before dropping the spinlock */ oldTag = buf->tag; @@ -2342,7 +2342,7 @@ retry: static bool InvalidateVictimBuffer(BufferDesc *buf_hdr) { - uint32 buf_state; + uint64 buf_state; uint32 hash; LWLock *partition_lock; BufferTag tag; @@ -2402,10 +2402,10 @@ InvalidateVictimBuffer(BufferDesc *buf_hdr) LWLockRelease(partition_lock); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(!(buf_state & (BM_DIRTY | BM_VALID | BM_TAG_VALID))); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); - Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u32(&buf_hdr->state)) > 0); + Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u64(&buf_hdr->state)) > 0); return true; } @@ -2415,7 +2415,7 @@ GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context) { BufferDesc *buf_hdr; Buffer buf; - uint32 buf_state; + uint64 buf_state; bool from_ring; /* @@ -2548,7 +2548,7 @@ again: /* a final set of sanity checks */ #ifdef USE_ASSERT_CHECKING - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) == 1); Assert(!(buf_state & (BM_TAG_VALID | BM_VALID | BM_DIRTY))); @@ -2839,13 +2839,13 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, */ do { - pg_atomic_fetch_and_u32(&existing_hdr->state, ~BM_VALID); + pg_atomic_fetch_and_u64(&existing_hdr->state, ~BM_VALID); } while (!StartBufferIO(existing_hdr, true, false)); } else { - uint32 buf_state; - uint32 set_bits = 0; + uint64 buf_state; + uint64 set_bits = 0; buf_state = LockBufHdr(victim_buf_hdr); @@ -3021,7 +3021,7 @@ BufferIsDirty(Buffer buffer) Assert(BufferIsLockedByMeInMode(buffer, BUFFER_LOCK_EXCLUSIVE)); } - return pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY; + return pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY; } /* @@ -3037,8 +3037,8 @@ void MarkBufferDirty(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; if (!BufferIsValid(buffer)) elog(ERROR, "bad buffer ID: %d", buffer); @@ -3058,7 +3058,7 @@ MarkBufferDirty(Buffer buffer) * NB: We have to wait for the buffer header spinlock to be not held, as * TerminateBufferIO() relies on the spinlock. */ - old_buf_state = pg_atomic_read_u32(&bufHdr->state); + old_buf_state = pg_atomic_read_u64(&bufHdr->state); for (;;) { if (old_buf_state & BM_LOCKED) @@ -3069,7 +3069,7 @@ MarkBufferDirty(Buffer buffer) Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state |= BM_DIRTY | BM_JUST_DIRTIED; - if (pg_atomic_compare_exchange_u32(&bufHdr->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&bufHdr->state, &old_buf_state, buf_state)) break; } @@ -3173,10 +3173,10 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, if (ref == NULL) { - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { if (unlikely(skip_if_not_valid && !(old_buf_state & BM_VALID))) @@ -3210,7 +3210,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, buf_state += BUF_USAGECOUNT_ONE; } - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, buf_state)) { result = (buf_state & BM_VALID) != 0; @@ -3237,7 +3237,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, * that the buffer page is legitimately non-accessible here. We * cannot meddle with that. */ - result = (pg_atomic_read_u32(&buf->state) & BM_VALID) != 0; + result = (pg_atomic_read_u64(&buf->state) & BM_VALID) != 0; Assert(ref->data.refcount > 0); ref->data.refcount++; @@ -3272,7 +3272,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, static void PinBuffer_Locked(BufferDesc *buf) { - uint32 old_buf_state; + uint64 old_buf_state; /* * As explained, We don't expect any preexisting pins. That allows us to @@ -3284,7 +3284,7 @@ PinBuffer_Locked(BufferDesc *buf) * Since we hold the buffer spinlock, we can update the buffer state and * release the lock in one operation. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); UnlockBufHdrExt(buf, old_buf_state, 0, 0, 1); @@ -3314,7 +3314,7 @@ WakePinCountWaiter(BufferDesc *buf) * BM_PIN_COUNT_WAITER if it stops waiting for a reason other than this * backend waking it up. */ - uint32 buf_state = LockBufHdr(buf); + uint64 buf_state = LockBufHdr(buf); if ((buf_state & BM_PIN_COUNT_WAITER) && BUF_STATE_GET_REFCOUNT(buf_state) == 1) @@ -3361,7 +3361,7 @@ UnpinBufferNoOwner(BufferDesc *buf) ref->data.refcount--; if (ref->data.refcount == 0) { - uint32 old_buf_state; + uint64 old_buf_state; /* * Mark buffer non-accessible to Valgrind. @@ -3379,7 +3379,7 @@ UnpinBufferNoOwner(BufferDesc *buf) Assert(!LWLockHeldByMe(BufferDescriptorGetContentLock(buf))); /* decrement the shared reference count */ - old_buf_state = pg_atomic_fetch_sub_u32(&buf->state, BUF_REFCOUNT_ONE); + old_buf_state = pg_atomic_fetch_sub_u64(&buf->state, BUF_REFCOUNT_ONE); /* Support LockBufferForCleanup() */ if (old_buf_state & BM_PIN_COUNT_WAITER) @@ -3436,7 +3436,7 @@ TrackNewBufferPin(Buffer buf) static void BufferSync(int flags) { - uint32 buf_state; + uint64 buf_state; int buf_id; int num_to_scan; int num_spaces; @@ -3446,7 +3446,7 @@ BufferSync(int flags) Oid last_tsid; binaryheap *ts_heap; int i; - uint32 mask = BM_DIRTY; + uint64 mask = BM_DIRTY; WritebackContext wb_context; /* @@ -3478,7 +3478,7 @@ BufferSync(int flags) for (buf_id = 0; buf_id < NBuffers; buf_id++) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); - uint32 set_bits = 0; + uint64 set_bits = 0; /* * Header spinlock is enough to examine BM_DIRTY, see comment in @@ -3645,7 +3645,7 @@ BufferSync(int flags) * write the buffer though we didn't need to. It doesn't seem worth * guarding against this, though. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_CHECKPOINT_NEEDED) + if (pg_atomic_read_u64(&bufHdr->state) & BM_CHECKPOINT_NEEDED) { if (SyncOneBuffer(buf_id, false, &wb_context) & BUF_WRITTEN) { @@ -4015,7 +4015,7 @@ SyncOneBuffer(int buf_id, bool skip_recently_used, WritebackContext *wb_context) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); int result = 0; - uint32 buf_state; + uint64 buf_state; BufferTag tag; /* Make sure we can handle the pin */ @@ -4264,7 +4264,7 @@ DebugPrintBufferRefcount(Buffer buffer) int32 loccount; char *result; ProcNumber backend; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); if (BufferIsLocal(buffer)) @@ -4281,9 +4281,9 @@ DebugPrintBufferRefcount(Buffer buffer) } /* theoretically we should lock the bufHdr here */ - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); - result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%x, refcount=%u %d)", + result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%" PRIx64 ", refcount=%u %d)", buffer, relpathbackend(BufTagGetRelFileLocator(&buf->tag), backend, BufTagGetForkNum(&buf->tag)).str, @@ -4383,7 +4383,7 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object, instr_time io_start; Block bufBlock; char *bufToWrite; - uint32 buf_state; + uint64 buf_state; /* * Try to start an I/O operation. If StartBufferIO returns false, then @@ -4581,7 +4581,7 @@ BufferIsPermanent(Buffer buffer) * not random garbage. */ bufHdr = GetBufferDescriptor(buffer - 1); - return (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT) != 0; + return (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT) != 0; } /* @@ -5044,11 +5044,11 @@ FlushRelationBuffers(Relation rel) { for (i = 0; i < NLocBuffer; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetLocalBufferDescriptor(i); if (BufTagMatchesRelFileLocator(&bufHdr->tag, &rel->rd_locator) && - ((buf_state = pg_atomic_read_u32(&bufHdr->state)) & + ((buf_state = pg_atomic_read_u64(&bufHdr->state)) & (BM_VALID | BM_DIRTY)) == (BM_VALID | BM_DIRTY)) { ErrorContextCallback errcallback; @@ -5084,7 +5084,7 @@ FlushRelationBuffers(Relation rel) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5156,7 +5156,7 @@ FlushRelationsAllBuffers(SMgrRelation *smgrs, int nrels) { SMgrSortArray *srelent = NULL; BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; /* * As in DropRelationBuffers, an unlocked precheck should be safe and @@ -5405,7 +5405,7 @@ FlushDatabaseBuffers(Oid dbid) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5553,13 +5553,13 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * is only intended to be used in cases where failing to write out the * data would be harmless anyway, it doesn't really matter. */ - if ((pg_atomic_read_u32(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != + if ((pg_atomic_read_u64(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != (BM_DIRTY | BM_JUST_DIRTIED)) { XLogRecPtr lsn = InvalidXLogRecPtr; bool dirtied = false; bool delayChkptFlags = false; - uint32 buf_state; + uint64 buf_state; /* * If we need to protect hint bit updates from torn writes, WAL-log a @@ -5571,7 +5571,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * when we call XLogInsert() since the value changes dynamically. */ if (XLogHintBitIsNeeded() && - (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT)) + (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT)) { /* * If we must not write WAL, due to a relfilelocator-specific @@ -5671,8 +5671,8 @@ UnlockBuffers(void) if (buf) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; buf_state = LockBufHdr(buf); @@ -5803,8 +5803,8 @@ LockBufferForCleanup(Buffer buffer) for (;;) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; /* Try to acquire lock */ LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); @@ -5952,7 +5952,7 @@ bool ConditionalLockBufferForCleanup(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state, + uint64 buf_state, refcount; Assert(BufferIsValid(buffer)); @@ -6010,7 +6010,7 @@ bool IsBufferCleanupOK(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); @@ -6066,7 +6066,7 @@ WaitIO(BufferDesc *buf) ConditionVariablePrepareToSleep(cv); for (;;) { - uint32 buf_state; + uint64 buf_state; PgAioWaitRef iow; /* @@ -6140,7 +6140,7 @@ WaitIO(BufferDesc *buf) bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; ResourceOwnerEnlarge(CurrentResourceOwner); @@ -6196,11 +6196,11 @@ StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) * is being released) */ void -TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio) { - uint32 buf_state; - uint32 unset_flag_bits = 0; + uint64 buf_state; + uint64 unset_flag_bits = 0; int refcount_change = 0; buf_state = LockBufHdr(buf); @@ -6261,7 +6261,7 @@ static void AbortBufferIO(Buffer buffer) { BufferDesc *buf_hdr = GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; buf_state = LockBufHdr(buf_hdr); Assert(buf_state & (BM_IO_IN_PROGRESS | BM_TAG_VALID)); @@ -6355,10 +6355,10 @@ rlocator_comparator(const void *p1, const void *p2) /* * Lock buffer header - set BM_LOCKED in buffer state. */ -uint32 +uint64 LockBufHdr(BufferDesc *desc) { - uint32 old_buf_state; + uint64 old_buf_state; Assert(!BufferIsLocal(BufferDescriptorGetBuffer(desc))); @@ -6369,7 +6369,7 @@ LockBufHdr(BufferDesc *desc) * the spin-delay infrastructure. The work necessary for that shows up * in profiles and is rarely necessary. */ - old_buf_state = pg_atomic_fetch_or_u32(&desc->state, BM_LOCKED); + old_buf_state = pg_atomic_fetch_or_u64(&desc->state, BM_LOCKED); if (likely(!(old_buf_state & BM_LOCKED))) break; /* got lock */ @@ -6382,7 +6382,7 @@ LockBufHdr(BufferDesc *desc) while (old_buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - old_buf_state = pg_atomic_read_u32(&desc->state); + old_buf_state = pg_atomic_read_u64(&desc->state); } finish_spin_delay(&delayStatus); } @@ -6403,20 +6403,20 @@ LockBufHdr(BufferDesc *desc) * Obviously the buffer could be locked by the time the value is returned, so * this is primarily useful in CAS style loops. */ -pg_noinline uint32 +pg_noinline uint64 WaitBufHdrUnlocked(BufferDesc *buf) { SpinDelayStatus delayStatus; - uint32 buf_state; + uint64 buf_state; init_local_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); while (buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); } finish_spin_delay(&delayStatus); @@ -6704,12 +6704,12 @@ ResOwnerPrintBufferPin(Datum res) static bool EvictUnpinnedBufferInternal(BufferDesc *desc, bool *buffer_flushed) { - uint32 buf_state; + uint64 buf_state; bool result; *buffer_flushed = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -6803,12 +6803,12 @@ EvictAllUnpinnedBuffers(int32 *buffers_evicted, int32 *buffers_flushed, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_flushed; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -6855,7 +6855,7 @@ EvictRelUnpinnedBuffers(Relation rel, int32 *buffers_evicted, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_flushed; CHECK_FOR_INTERRUPTS(); @@ -6897,12 +6897,12 @@ static bool MarkDirtyUnpinnedBufferInternal(Buffer buf, BufferDesc *desc, bool *buffer_already_dirty) { - uint32 buf_state; + uint64 buf_state; bool result = false; *buffer_already_dirty = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -7000,7 +7000,7 @@ MarkDirtyRelUnpinnedBuffers(Relation rel, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_already_dirty; CHECK_FOR_INTERRUPTS(); @@ -7054,12 +7054,12 @@ MarkDirtyAllUnpinnedBuffers(int32 *buffers_dirtied, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_already_dirty; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -7110,7 +7110,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) BufferDesc *buf_hdr = is_temp ? GetLocalBufferDescriptor(-buffer - 1) : GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; /* * Check that all the buffers are actually ones that could conceivably @@ -7128,7 +7128,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) } if (is_temp) - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); else buf_state = LockBufHdr(buf_hdr); @@ -7166,7 +7166,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) if (is_temp) { buf_state += BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else UnlockBufHdrExt(buf_hdr, buf_state, 0, 0, 1); @@ -7352,13 +7352,13 @@ buffer_readv_complete_one(PgAioTargetData *td, uint8 buf_off, Buffer buffer, : GetBufferDescriptor(buffer - 1); BufferTag tag = buf_hdr->tag; char *bufdata = BufferGetBlock(buffer); - uint32 set_flag_bits; + uint64 set_flag_bits; int piv_flags; /* check that the buffer is in the expected state for a read */ #ifdef USE_ASSERT_CHECKING { - uint32 buf_state = pg_atomic_read_u32(&buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_VALID)); diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c index 9a93fb335fc..b7687836188 100644 --- a/src/backend/storage/buffer/freelist.c +++ b/src/backend/storage/buffer/freelist.c @@ -86,7 +86,7 @@ typedef struct BufferAccessStrategyData /* Prototypes for internal functions */ static BufferDesc *GetBufferFromRing(BufferAccessStrategy strategy, - uint32 *buf_state); + uint64 *buf_state); static void AddBufferToRing(BufferAccessStrategy strategy, BufferDesc *buf); @@ -171,7 +171,7 @@ ClockSweepTick(void) * before returning. */ BufferDesc * -StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_ring) +StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_ring) { BufferDesc *buf; int bgwprocno; @@ -230,8 +230,8 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r trycounter = NBuffers; for (;;) { - uint32 old_buf_state; - uint32 local_buf_state; + uint64 old_buf_state; + uint64 local_buf_state; buf = GetBufferDescriptor(ClockSweepTick()); @@ -239,7 +239,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r * Check whether the buffer can be used and pin it if so. Do this * using a CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -277,7 +277,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r { local_buf_state -= BUF_USAGECOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { trycounter = NBuffers; @@ -289,7 +289,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { /* Found a usable buffer */ @@ -655,12 +655,12 @@ FreeAccessStrategy(BufferAccessStrategy strategy) * returning. */ static BufferDesc * -GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) +GetBufferFromRing(BufferAccessStrategy strategy, uint64 *buf_state) { BufferDesc *buf; Buffer bufnum; - uint32 old_buf_state; - uint32 local_buf_state; /* to avoid repeated (de-)referencing */ + uint64 old_buf_state; + uint64 local_buf_state; /* to avoid repeated (de-)referencing */ /* Advance to next ring slot */ @@ -682,7 +682,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) * Check whether the buffer can be used and pin it if so. Do this using a * CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -710,7 +710,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { *buf_state = local_buf_state; diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index f6e2b1aa288..04a540379a2 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -148,7 +148,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, } else { - uint32 buf_state; + uint64 buf_state; victim_buffer = GetLocalVictimBuffer(); bufid = -victim_buffer - 1; @@ -165,10 +165,10 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, */ bufHdr->tag = newTag; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); buf_state &= ~(BUF_FLAG_MASK | BUF_USAGECOUNT_MASK); buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); *foundPtr = false; } @@ -245,12 +245,12 @@ GetLocalVictimBuffer(void) if (LocalRefCount[victim_bufid] == 0) { - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0) { buf_state -= BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); trycounter = NLocBuffer; } else if (BUF_STATE_GET_REFCOUNT(buf_state) > 0) @@ -286,13 +286,13 @@ GetLocalVictimBuffer(void) * this buffer is not referenced but it might still be dirty. if that's * the case, write it out before reusing it! */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY) FlushLocalBuffer(bufHdr, NULL); /* * Remove the victim buffer from the hashtable and mark as invalid. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID) + if (pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID) { InvalidateLocalBuffer(bufHdr, false); @@ -417,7 +417,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, if (found) { BufferDesc *existing_hdr; - uint32 buf_state; + uint64 buf_state; UnpinLocalBuffer(BufferDescriptorGetBuffer(victim_buf_hdr)); @@ -428,18 +428,18 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, /* * Clear the BM_VALID bit, do StartLocalBufferIO() and proceed. */ - buf_state = pg_atomic_read_u32(&existing_hdr->state); + buf_state = pg_atomic_read_u64(&existing_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_DIRTY)); buf_state &= ~BM_VALID; - pg_atomic_unlocked_write_u32(&existing_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&existing_hdr->state, buf_state); /* no need to loop for local buffers */ StartLocalBufferIO(existing_hdr, true, false); } else { - uint32 buf_state = pg_atomic_read_u32(&victim_buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&victim_buf_hdr->state); Assert(!(buf_state & (BM_VALID | BM_TAG_VALID | BM_DIRTY | BM_JUST_DIRTIED))); @@ -447,7 +447,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&victim_buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&victim_buf_hdr->state, buf_state); hresult->id = victim_buf_id; @@ -467,13 +467,13 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, { Buffer buf = buffers[i]; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); buf_state |= BM_VALID; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } *extended_by = extend_by; @@ -492,7 +492,7 @@ MarkLocalBufferDirty(Buffer buffer) { int bufid; BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsLocal(buffer)); @@ -506,14 +506,14 @@ MarkLocalBufferDirty(Buffer buffer) bufHdr = GetLocalBufferDescriptor(bufid); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_DIRTY)) pgBufferUsage.local_blks_dirtied++; buf_state |= BM_DIRTY; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -522,7 +522,7 @@ MarkLocalBufferDirty(Buffer buffer) bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; /* * With AIO the buffer could have IO in progress, e.g. when there are two @@ -542,7 +542,7 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) /* Once we get here, there is definitely no I/O active on this buffer */ /* Check if someone else already did the I/O */ - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (forInput ? (buf_state & BM_VALID) : !(buf_state & BM_DIRTY)) { return false; @@ -559,11 +559,11 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) * Like TerminateBufferIO, but for local buffers */ void -TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bits, +TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint64 set_flag_bits, bool release_aio) { /* Only need to adjust flags */ - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); /* BM_IO_IN_PROGRESS isn't currently used for local buffers */ @@ -582,7 +582,7 @@ TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bit } buf_state |= set_flag_bits; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); /* local buffers don't track IO using resowners */ @@ -606,7 +606,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) { Buffer buffer = BufferDescriptorGetBuffer(bufHdr); int bufid = -buffer - 1; - uint32 buf_state; + uint64 buf_state; LocalBufferLookupEnt *hresult; /* @@ -622,7 +622,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) Assert(!pgaio_wref_valid(&bufHdr->io_wref)); } - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* * We need to test not just LocalRefCount[bufid] but also the BufferDesc @@ -647,7 +647,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) ClearBufferTag(&bufHdr->tag); buf_state &= ~BUF_FLAG_MASK; buf_state &= ~BUF_USAGECOUNT_MASK; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -671,9 +671,9 @@ DropRelationLocalBuffers(RelFileLocator rlocator, ForkNumber *forkNum, for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_TAG_VALID) || !BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -706,9 +706,9 @@ DropRelationAllLocalBuffers(RelFileLocator rlocator) for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if ((buf_state & BM_TAG_VALID) && BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -804,11 +804,11 @@ InitLocalBuffers(void) bool PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { - uint32 buf_state; + uint64 buf_state; Buffer buffer = BufferDescriptorGetBuffer(buf_hdr); int bufid = -buffer - 1; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); if (LocalRefCount[bufid] == 0) { @@ -819,7 +819,7 @@ PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { buf_state += BUF_USAGECOUNT_ONE; } - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* * See comment in PinBuffer(). @@ -856,14 +856,14 @@ UnpinLocalBufferNoOwner(Buffer buffer) if (--LocalRefCount[buffid] == 0) { BufferDesc *buf_hdr = GetLocalBufferDescriptor(buffid); - uint32 buf_state; + uint64 buf_state; NLocalPinnedBuffers--; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state -= BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* see comment in UnpinBufferNoOwner */ VALGRIND_MAKE_MEM_NOACCESS(LocalBufHdrGetBlock(buf_hdr), BLCKSZ); diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index 0c58e4b265c..529803346ce 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -199,7 +199,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) for (i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -615,7 +615,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -626,7 +626,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) * noticeably increase the cost of the function. */ bufHdr = GetBufferDescriptor(i); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (buf_state & BM_VALID) { @@ -676,7 +676,7 @@ pg_buffercache_usage_counts(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); int usage_count; CHECK_FOR_INTERRUPTS(); diff --git a/src/test/modules/test_aio/test_aio.c b/src/test/modules/test_aio/test_aio.c index e046b08f3d5..b1aa8af9ec0 100644 --- a/src/test/modules/test_aio/test_aio.c +++ b/src/test/modules/test_aio/test_aio.c @@ -308,9 +308,9 @@ create_toy_buffer(Relation rel, BlockNumber blkno) { Buffer buf; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; bool was_pinned = false; - uint32 unset_bits = 0; + uint64 unset_bits = 0; /* place buffer in shared buffers without erroring out */ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO_AND_LOCK, NULL); @@ -319,7 +319,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); } else { @@ -340,7 +340,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_state &= ~unset_bits; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else { @@ -489,7 +489,7 @@ invalidate_rel_block(PG_FUNCTION_ARGS) LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); - if (pg_atomic_read_u32(&buf_hdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&buf_hdr->state) & BM_DIRTY) { if (BufferIsLocal(buf)) FlushLocalBuffer(buf_hdr, NULL); @@ -572,7 +572,7 @@ buffer_call_terminate_io(PG_FUNCTION_ARGS) bool io_error = PG_GETARG_BOOL(3); bool release_aio = PG_GETARG_BOOL(4); bool clear_dirty = false; - uint32 set_flag_bits = 0; + uint64 set_flag_bits = 0; if (io_error) set_flag_bits |= BM_IO_ERROR; -- 2.48.1.76.g4e746b1a31.dirty --jmawlk4t5yqwiemy Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v10-0004-bufmgr-Implement-buffer-content-locks-independen.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v11 1/7] bufmgr: Change BufferDesc.state to be a 64-bit atomic @ 2026-01-14 01:10 Andres Freund <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Andres Freund @ 2026-01-14 01:10 UTC (permalink / raw) This is motivated by wanting to merge buffer content locks into BufferDesc.state in a future commit, rather than having a separate lwlock (see commit c75ebc657ff for more details). As this change is rather mechanical, it seems to make sense to split it out into a separate commit, for easier review. Reviewed-by: Melanie Plageman <[email protected]> Discussion: https://postgr.es/m/fvfmkr5kk4nyex56ejgxj3uzi63isfxovp2biecb4bspbjrze7@az2pljabhnff --- src/include/storage/buf_internals.h | 51 +++--- src/include/storage/procnumber.h | 14 +- src/backend/storage/buffer/buf_init.c | 2 +- src/backend/storage/buffer/bufmgr.c | 170 +++++++++--------- src/backend/storage/buffer/freelist.c | 24 +-- src/backend/storage/buffer/localbuf.c | 72 ++++---- contrib/pg_buffercache/pg_buffercache_pages.c | 8 +- contrib/pg_prewarm/autoprewarm.c | 2 +- src/test/modules/test_aio/test_aio.c | 12 +- 9 files changed, 179 insertions(+), 176 deletions(-) diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index 2f607ea2ac5..e6e788224f5 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -30,7 +30,7 @@ #include "utils/resowner.h" /* - * Buffer state is a single 32-bit variable where following data is combined. + * Buffer state is a single 64-bit variable where following data is combined. * * State of the buffer itself (in order): * - 18 bits refcount @@ -40,6 +40,9 @@ * Combining these values allows to perform some operations without locking * the buffer header, by modifying them together with a CAS loop. * + * NB: A future commit will use a significant portion of the remaining bits to + * implement buffer locking as part of the state variable. + * * The definition of buffer state components is below. */ #define BUF_REFCOUNT_BITS 18 @@ -52,27 +55,27 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, /* refcount related definitions */ #define BUF_REFCOUNT_ONE 1 #define BUF_REFCOUNT_MASK \ - ((1U << BUF_REFCOUNT_BITS) - 1) + ((UINT64CONST(1) << BUF_REFCOUNT_BITS) - 1) /* usage count related definitions */ #define BUF_USAGECOUNT_SHIFT \ BUF_REFCOUNT_BITS #define BUF_USAGECOUNT_MASK \ - (((1U << BUF_USAGECOUNT_BITS) - 1) << (BUF_USAGECOUNT_SHIFT)) + (((UINT64CONST(1) << BUF_USAGECOUNT_BITS) - 1) << (BUF_USAGECOUNT_SHIFT)) #define BUF_USAGECOUNT_ONE \ - (1U << BUF_REFCOUNT_BITS) + (UINT64CONST(1) << BUF_REFCOUNT_BITS) /* flags related definitions */ #define BUF_FLAG_SHIFT \ (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS) #define BUF_FLAG_MASK \ - (((1U << BUF_FLAG_BITS) - 1) << BUF_FLAG_SHIFT) + (((UINT64CONST(1) << BUF_FLAG_BITS) - 1) << BUF_FLAG_SHIFT) /* Get refcount and usagecount from buffer state */ #define BUF_STATE_GET_REFCOUNT(state) \ - ((state) & BUF_REFCOUNT_MASK) + ((uint32)((state) & BUF_REFCOUNT_MASK)) #define BUF_STATE_GET_USAGECOUNT(state) \ - (((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT) + ((uint32)(((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT)) /* * Flags for buffer descriptors @@ -82,7 +85,7 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, */ #define BUF_DEFINE_FLAG(flagno) \ - (1U << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + (flagno))) + (UINT64CONST(1) << (BUF_FLAG_SHIFT + (flagno))) /* buffer header is locked */ #define BM_LOCKED BUF_DEFINE_FLAG( 0) @@ -115,7 +118,7 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, */ #define BM_MAX_USAGE_COUNT 5 -StaticAssertDecl(BM_MAX_USAGE_COUNT < (1 << BUF_USAGECOUNT_BITS), +StaticAssertDecl(BM_MAX_USAGE_COUNT < (UINT64CONST(1) << BUF_USAGECOUNT_BITS), "BM_MAX_USAGE_COUNT doesn't fit in BUF_USAGECOUNT_BITS bits"); StaticAssertDecl(MAX_BACKENDS_BITS <= BUF_REFCOUNT_BITS, "MAX_BACKENDS_BITS needs to be <= BUF_REFCOUNT_BITS"); @@ -280,8 +283,8 @@ BufMappingPartitionLockByIndex(uint32 index) * We use this same struct for local buffer headers, but the locks are not * used and not all of the flag bits are useful either. To avoid unnecessary * overhead, manipulations of the state field should be done without actual - * atomic operations (i.e. only pg_atomic_read_u32() and - * pg_atomic_unlocked_write_u32()). + * atomic operations (i.e. only pg_atomic_read_u64() and + * pg_atomic_unlocked_write_u64()). * * Be careful to avoid increasing the size of the struct when adding or * reordering members. Keeping it below 64 bytes (the most common CPU @@ -309,7 +312,7 @@ typedef struct BufferDesc * State of the buffer, containing flags, refcount and usagecount. See * BUF_* and BM_* defines at the top of this file. */ - pg_atomic_uint32 state; + pg_atomic_uint64 state; /* * Backend of pin-count waiter. The buffer header spinlock needs to be @@ -415,7 +418,7 @@ BufferDescriptorGetContentLock(const BufferDesc *bdesc) * Functions for acquiring/releasing a shared buffer header's spinlock. Do * not apply these to local buffers! */ -extern uint32 LockBufHdr(BufferDesc *desc); +extern uint64 LockBufHdr(BufferDesc *desc); /* * Unlock the buffer header. @@ -426,9 +429,9 @@ extern uint32 LockBufHdr(BufferDesc *desc); static inline void UnlockBufHdr(BufferDesc *desc) { - Assert(pg_atomic_read_u32(&desc->state) & BM_LOCKED); + Assert(pg_atomic_read_u64(&desc->state) & BM_LOCKED); - pg_atomic_fetch_sub_u32(&desc->state, BM_LOCKED); + pg_atomic_fetch_sub_u64(&desc->state, BM_LOCKED); } /* @@ -439,14 +442,14 @@ UnlockBufHdr(BufferDesc *desc) * Note that this approach would not work for usagecount, since we need to cap * the usagecount at BM_MAX_USAGE_COUNT. */ -static inline uint32 -UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, - uint32 set_bits, uint32 unset_bits, +static inline uint64 +UnlockBufHdrExt(BufferDesc *desc, uint64 old_buf_state, + uint64 set_bits, uint64 unset_bits, int refcount_change) { for (;;) { - uint32 buf_state = old_buf_state; + uint64 buf_state = old_buf_state; Assert(buf_state & BM_LOCKED); @@ -457,7 +460,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, if (refcount_change != 0) buf_state += BUF_REFCOUNT_ONE * refcount_change; - if (pg_atomic_compare_exchange_u32(&desc->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&desc->state, &old_buf_state, buf_state)) { return old_buf_state; @@ -465,7 +468,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, } } -extern uint32 WaitBufHdrUnlocked(BufferDesc *buf); +extern uint64 WaitBufHdrUnlocked(BufferDesc *buf); /* in bufmgr.c */ @@ -525,14 +528,14 @@ extern void TrackNewBufferPin(Buffer buf); /* solely to make it easier to write tests */ extern bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait); -extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio); /* freelist.c */ extern IOContext IOContextForStrategy(BufferAccessStrategy strategy); extern BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy, - uint32 *buf_state, bool *from_ring); + uint64 *buf_state, bool *from_ring); extern bool StrategyRejectBuffer(BufferAccessStrategy strategy, BufferDesc *buf, bool from_ring); @@ -568,7 +571,7 @@ extern BlockNumber ExtendBufferedRelLocal(BufferManagerRelation bmr, uint32 *extended_by); extern void MarkLocalBufferDirty(Buffer buffer); extern void TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, - uint32 set_flag_bits, bool release_aio); + uint64 set_flag_bits, bool release_aio); extern bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait); extern void FlushLocalBuffer(BufferDesc *bufHdr, SMgrRelation reln); extern void InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced); diff --git a/src/include/storage/procnumber.h b/src/include/storage/procnumber.h index 30c360ad350..bd9cb3891cc 100644 --- a/src/include/storage/procnumber.h +++ b/src/include/storage/procnumber.h @@ -27,13 +27,13 @@ typedef int ProcNumber; /* * Note: MAX_BACKENDS_BITS is 18 as that is the space available for buffer - * refcounts in buf_internals.h. This limitation could be lifted by using a - * 64bit state; but it's unlikely to be worthwhile as 2^18-1 backends exceed - * currently realistic configurations. Even if that limitation were removed, - * we still could not a) exceed 2^23-1 because inval.c stores the ProcNumber - * as a 3-byte signed integer, b) INT_MAX/4 because some places compute - * 4*MaxBackends without any overflow check. We check that the configured - * number of backends does not exceed MAX_BACKENDS in InitializeMaxBackends(). + * refcounts in buf_internals.h. This limitation could be lifted, but it's + * unlikely to be worthwhile as 2^18-1 backends exceed currently realistic + * configurations. Even if that limitation were removed, we still could not a) + * exceed 2^23-1 because inval.c stores the ProcNumber as a 3-byte signed + * integer, b) INT_MAX/4 because some places compute 4*MaxBackends without any + * overflow check. We check that the configured number of backends does not + * exceed MAX_BACKENDS in InitializeMaxBackends(). */ #define MAX_BACKENDS_BITS 18 #define MAX_BACKENDS ((1U << MAX_BACKENDS_BITS)-1) diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index 9a312bcc7b3..7d894522526 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -121,7 +121,7 @@ BufferManagerShmemInit(void) ClearBufferTag(&buf->tag); - pg_atomic_init_u32(&buf->state, 0); + pg_atomic_init_u64(&buf->state, 0); buf->wait_backend_pgprocno = INVALID_PROC_NUMBER; buf->buf_id = i; diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index a036c2aa275..b0de8e45d4d 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -780,7 +780,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN { BufferDesc *bufHdr; BufferTag tag; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(recent_buffer)); @@ -793,7 +793,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN int b = -recent_buffer - 1; bufHdr = GetLocalBufferDescriptor(b); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* Is it still valid and holding the right tag? */ if ((buf_state & BM_VALID) && BufferTagsEqual(&tag, &bufHdr->tag)) @@ -1386,8 +1386,8 @@ StartReadBuffersImpl(ReadBuffersOperation *operation, bufHdr = GetLocalBufferDescriptor(-buffers[i] - 1); else bufHdr = GetBufferDescriptor(buffers[i] - 1); - Assert(pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID); - found = pg_atomic_read_u32(&bufHdr->state) & BM_VALID; + Assert(pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID); + found = pg_atomic_read_u64(&bufHdr->state) & BM_VALID; } else { @@ -1613,10 +1613,10 @@ CheckReadBuffersOperation(ReadBuffersOperation *operation, bool is_complete) GetBufferDescriptor(buffer - 1); Assert(BufferGetBlockNumber(buffer) == operation->blocknum + i); - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_TAG_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_TAG_VALID); if (i < operation->nblocks_done) - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_VALID); } #endif } @@ -2083,8 +2083,8 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, int existing_buf_id; Buffer victim_buffer; BufferDesc *victim_buf_hdr; - uint32 victim_buf_state; - uint32 set_bits = 0; + uint64 victim_buf_state; + uint64 set_bits = 0; /* Make sure we will have room to remember the buffer pin */ ResourceOwnerEnlarge(CurrentResourceOwner); @@ -2251,7 +2251,7 @@ InvalidateBuffer(BufferDesc *buf) uint32 oldHash; /* hash value for oldTag */ LWLock *oldPartitionLock; /* buffer partition lock for it */ uint32 oldFlags; - uint32 buf_state; + uint64 buf_state; /* Save the original buffer tag before dropping the spinlock */ oldTag = buf->tag; @@ -2342,7 +2342,7 @@ retry: static bool InvalidateVictimBuffer(BufferDesc *buf_hdr) { - uint32 buf_state; + uint64 buf_state; uint32 hash; LWLock *partition_lock; BufferTag tag; @@ -2402,10 +2402,10 @@ InvalidateVictimBuffer(BufferDesc *buf_hdr) LWLockRelease(partition_lock); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(!(buf_state & (BM_DIRTY | BM_VALID | BM_TAG_VALID))); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); - Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u32(&buf_hdr->state)) > 0); + Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u64(&buf_hdr->state)) > 0); return true; } @@ -2415,7 +2415,7 @@ GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context) { BufferDesc *buf_hdr; Buffer buf; - uint32 buf_state; + uint64 buf_state; bool from_ring; /* @@ -2548,7 +2548,7 @@ again: /* a final set of sanity checks */ #ifdef USE_ASSERT_CHECKING - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) == 1); Assert(!(buf_state & (BM_TAG_VALID | BM_VALID | BM_DIRTY))); @@ -2839,13 +2839,13 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, */ do { - pg_atomic_fetch_and_u32(&existing_hdr->state, ~BM_VALID); + pg_atomic_fetch_and_u64(&existing_hdr->state, ~BM_VALID); } while (!StartBufferIO(existing_hdr, true, false)); } else { - uint32 buf_state; - uint32 set_bits = 0; + uint64 buf_state; + uint64 set_bits = 0; buf_state = LockBufHdr(victim_buf_hdr); @@ -3021,7 +3021,7 @@ BufferIsDirty(Buffer buffer) Assert(BufferIsLockedByMeInMode(buffer, BUFFER_LOCK_EXCLUSIVE)); } - return pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY; + return pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY; } /* @@ -3037,8 +3037,8 @@ void MarkBufferDirty(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; if (!BufferIsValid(buffer)) elog(ERROR, "bad buffer ID: %d", buffer); @@ -3058,7 +3058,7 @@ MarkBufferDirty(Buffer buffer) * NB: We have to wait for the buffer header spinlock to be not held, as * TerminateBufferIO() relies on the spinlock. */ - old_buf_state = pg_atomic_read_u32(&bufHdr->state); + old_buf_state = pg_atomic_read_u64(&bufHdr->state); for (;;) { if (old_buf_state & BM_LOCKED) @@ -3069,7 +3069,7 @@ MarkBufferDirty(Buffer buffer) Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state |= BM_DIRTY | BM_JUST_DIRTIED; - if (pg_atomic_compare_exchange_u32(&bufHdr->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&bufHdr->state, &old_buf_state, buf_state)) break; } @@ -3173,10 +3173,10 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, if (ref == NULL) { - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { if (unlikely(skip_if_not_valid && !(old_buf_state & BM_VALID))) @@ -3210,7 +3210,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, buf_state += BUF_USAGECOUNT_ONE; } - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, buf_state)) { result = (buf_state & BM_VALID) != 0; @@ -3237,7 +3237,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, * that the buffer page is legitimately non-accessible here. We * cannot meddle with that. */ - result = (pg_atomic_read_u32(&buf->state) & BM_VALID) != 0; + result = (pg_atomic_read_u64(&buf->state) & BM_VALID) != 0; Assert(ref->data.refcount > 0); ref->data.refcount++; @@ -3272,7 +3272,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, static void PinBuffer_Locked(BufferDesc *buf) { - uint32 old_buf_state; + uint64 old_buf_state; /* * As explained, We don't expect any preexisting pins. That allows us to @@ -3284,7 +3284,7 @@ PinBuffer_Locked(BufferDesc *buf) * Since we hold the buffer spinlock, we can update the buffer state and * release the lock in one operation. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); UnlockBufHdrExt(buf, old_buf_state, 0, 0, 1); @@ -3314,7 +3314,7 @@ WakePinCountWaiter(BufferDesc *buf) * BM_PIN_COUNT_WAITER if it stops waiting for a reason other than this * backend waking it up. */ - uint32 buf_state = LockBufHdr(buf); + uint64 buf_state = LockBufHdr(buf); if ((buf_state & BM_PIN_COUNT_WAITER) && BUF_STATE_GET_REFCOUNT(buf_state) == 1) @@ -3361,7 +3361,7 @@ UnpinBufferNoOwner(BufferDesc *buf) ref->data.refcount--; if (ref->data.refcount == 0) { - uint32 old_buf_state; + uint64 old_buf_state; /* * Mark buffer non-accessible to Valgrind. @@ -3379,7 +3379,7 @@ UnpinBufferNoOwner(BufferDesc *buf) Assert(!LWLockHeldByMe(BufferDescriptorGetContentLock(buf))); /* decrement the shared reference count */ - old_buf_state = pg_atomic_fetch_sub_u32(&buf->state, BUF_REFCOUNT_ONE); + old_buf_state = pg_atomic_fetch_sub_u64(&buf->state, BUF_REFCOUNT_ONE); /* Support LockBufferForCleanup() */ if (old_buf_state & BM_PIN_COUNT_WAITER) @@ -3436,7 +3436,7 @@ TrackNewBufferPin(Buffer buf) static void BufferSync(int flags) { - uint32 buf_state; + uint64 buf_state; int buf_id; int num_to_scan; int num_spaces; @@ -3446,7 +3446,7 @@ BufferSync(int flags) Oid last_tsid; binaryheap *ts_heap; int i; - uint32 mask = BM_DIRTY; + uint64 mask = BM_DIRTY; WritebackContext wb_context; /* @@ -3478,7 +3478,7 @@ BufferSync(int flags) for (buf_id = 0; buf_id < NBuffers; buf_id++) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); - uint32 set_bits = 0; + uint64 set_bits = 0; /* * Header spinlock is enough to examine BM_DIRTY, see comment in @@ -3645,7 +3645,7 @@ BufferSync(int flags) * write the buffer though we didn't need to. It doesn't seem worth * guarding against this, though. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_CHECKPOINT_NEEDED) + if (pg_atomic_read_u64(&bufHdr->state) & BM_CHECKPOINT_NEEDED) { if (SyncOneBuffer(buf_id, false, &wb_context) & BUF_WRITTEN) { @@ -4015,7 +4015,7 @@ SyncOneBuffer(int buf_id, bool skip_recently_used, WritebackContext *wb_context) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); int result = 0; - uint32 buf_state; + uint64 buf_state; BufferTag tag; /* Make sure we can handle the pin */ @@ -4264,7 +4264,7 @@ DebugPrintBufferRefcount(Buffer buffer) int32 loccount; char *result; ProcNumber backend; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); if (BufferIsLocal(buffer)) @@ -4281,9 +4281,9 @@ DebugPrintBufferRefcount(Buffer buffer) } /* theoretically we should lock the bufHdr here */ - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); - result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%x, refcount=%u %d)", + result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%" PRIx64 ", refcount=%u %d)", buffer, relpathbackend(BufTagGetRelFileLocator(&buf->tag), backend, BufTagGetForkNum(&buf->tag)).str, @@ -4383,7 +4383,7 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object, instr_time io_start; Block bufBlock; char *bufToWrite; - uint32 buf_state; + uint64 buf_state; /* * Try to start an I/O operation. If StartBufferIO returns false, then @@ -4581,7 +4581,7 @@ BufferIsPermanent(Buffer buffer) * not random garbage. */ bufHdr = GetBufferDescriptor(buffer - 1); - return (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT) != 0; + return (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT) != 0; } /* @@ -5044,11 +5044,11 @@ FlushRelationBuffers(Relation rel) { for (i = 0; i < NLocBuffer; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetLocalBufferDescriptor(i); if (BufTagMatchesRelFileLocator(&bufHdr->tag, &rel->rd_locator) && - ((buf_state = pg_atomic_read_u32(&bufHdr->state)) & + ((buf_state = pg_atomic_read_u64(&bufHdr->state)) & (BM_VALID | BM_DIRTY)) == (BM_VALID | BM_DIRTY)) { ErrorContextCallback errcallback; @@ -5084,7 +5084,7 @@ FlushRelationBuffers(Relation rel) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5156,7 +5156,7 @@ FlushRelationsAllBuffers(SMgrRelation *smgrs, int nrels) { SMgrSortArray *srelent = NULL; BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; /* * As in DropRelationBuffers, an unlocked precheck should be safe and @@ -5405,7 +5405,7 @@ FlushDatabaseBuffers(Oid dbid) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5553,13 +5553,13 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * is only intended to be used in cases where failing to write out the * data would be harmless anyway, it doesn't really matter. */ - if ((pg_atomic_read_u32(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != + if ((pg_atomic_read_u64(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != (BM_DIRTY | BM_JUST_DIRTIED)) { XLogRecPtr lsn = InvalidXLogRecPtr; bool dirtied = false; bool delayChkptFlags = false; - uint32 buf_state; + uint64 buf_state; /* * If we need to protect hint bit updates from torn writes, WAL-log a @@ -5571,7 +5571,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * when we call XLogInsert() since the value changes dynamically. */ if (XLogHintBitIsNeeded() && - (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT)) + (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT)) { /* * If we must not write WAL, due to a relfilelocator-specific @@ -5671,8 +5671,8 @@ UnlockBuffers(void) if (buf) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; buf_state = LockBufHdr(buf); @@ -5803,8 +5803,8 @@ LockBufferForCleanup(Buffer buffer) for (;;) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; /* Try to acquire lock */ LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); @@ -5952,7 +5952,7 @@ bool ConditionalLockBufferForCleanup(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state, + uint64 buf_state, refcount; Assert(BufferIsValid(buffer)); @@ -6010,7 +6010,7 @@ bool IsBufferCleanupOK(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); @@ -6066,7 +6066,7 @@ WaitIO(BufferDesc *buf) ConditionVariablePrepareToSleep(cv); for (;;) { - uint32 buf_state; + uint64 buf_state; PgAioWaitRef iow; /* @@ -6140,7 +6140,7 @@ WaitIO(BufferDesc *buf) bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; ResourceOwnerEnlarge(CurrentResourceOwner); @@ -6196,11 +6196,11 @@ StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) * is being released) */ void -TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio) { - uint32 buf_state; - uint32 unset_flag_bits = 0; + uint64 buf_state; + uint64 unset_flag_bits = 0; int refcount_change = 0; buf_state = LockBufHdr(buf); @@ -6261,7 +6261,7 @@ static void AbortBufferIO(Buffer buffer) { BufferDesc *buf_hdr = GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; buf_state = LockBufHdr(buf_hdr); Assert(buf_state & (BM_IO_IN_PROGRESS | BM_TAG_VALID)); @@ -6355,10 +6355,10 @@ rlocator_comparator(const void *p1, const void *p2) /* * Lock buffer header - set BM_LOCKED in buffer state. */ -uint32 +uint64 LockBufHdr(BufferDesc *desc) { - uint32 old_buf_state; + uint64 old_buf_state; Assert(!BufferIsLocal(BufferDescriptorGetBuffer(desc))); @@ -6369,7 +6369,7 @@ LockBufHdr(BufferDesc *desc) * the spin-delay infrastructure. The work necessary for that shows up * in profiles and is rarely necessary. */ - old_buf_state = pg_atomic_fetch_or_u32(&desc->state, BM_LOCKED); + old_buf_state = pg_atomic_fetch_or_u64(&desc->state, BM_LOCKED); if (likely(!(old_buf_state & BM_LOCKED))) break; /* got lock */ @@ -6382,7 +6382,7 @@ LockBufHdr(BufferDesc *desc) while (old_buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - old_buf_state = pg_atomic_read_u32(&desc->state); + old_buf_state = pg_atomic_read_u64(&desc->state); } finish_spin_delay(&delayStatus); } @@ -6403,20 +6403,20 @@ LockBufHdr(BufferDesc *desc) * Obviously the buffer could be locked by the time the value is returned, so * this is primarily useful in CAS style loops. */ -pg_noinline uint32 +pg_noinline uint64 WaitBufHdrUnlocked(BufferDesc *buf) { SpinDelayStatus delayStatus; - uint32 buf_state; + uint64 buf_state; init_local_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); while (buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); } finish_spin_delay(&delayStatus); @@ -6704,12 +6704,12 @@ ResOwnerPrintBufferPin(Datum res) static bool EvictUnpinnedBufferInternal(BufferDesc *desc, bool *buffer_flushed) { - uint32 buf_state; + uint64 buf_state; bool result; *buffer_flushed = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -6803,12 +6803,12 @@ EvictAllUnpinnedBuffers(int32 *buffers_evicted, int32 *buffers_flushed, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_flushed; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -6855,7 +6855,7 @@ EvictRelUnpinnedBuffers(Relation rel, int32 *buffers_evicted, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_flushed; CHECK_FOR_INTERRUPTS(); @@ -6897,12 +6897,12 @@ static bool MarkDirtyUnpinnedBufferInternal(Buffer buf, BufferDesc *desc, bool *buffer_already_dirty) { - uint32 buf_state; + uint64 buf_state; bool result = false; *buffer_already_dirty = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -7000,7 +7000,7 @@ MarkDirtyRelUnpinnedBuffers(Relation rel, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_already_dirty; CHECK_FOR_INTERRUPTS(); @@ -7054,12 +7054,12 @@ MarkDirtyAllUnpinnedBuffers(int32 *buffers_dirtied, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_already_dirty; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -7110,7 +7110,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) BufferDesc *buf_hdr = is_temp ? GetLocalBufferDescriptor(-buffer - 1) : GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; /* * Check that all the buffers are actually ones that could conceivably @@ -7128,7 +7128,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) } if (is_temp) - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); else buf_state = LockBufHdr(buf_hdr); @@ -7166,7 +7166,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) if (is_temp) { buf_state += BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else UnlockBufHdrExt(buf_hdr, buf_state, 0, 0, 1); @@ -7352,13 +7352,13 @@ buffer_readv_complete_one(PgAioTargetData *td, uint8 buf_off, Buffer buffer, : GetBufferDescriptor(buffer - 1); BufferTag tag = buf_hdr->tag; char *bufdata = BufferGetBlock(buffer); - uint32 set_flag_bits; + uint64 set_flag_bits; int piv_flags; /* check that the buffer is in the expected state for a read */ #ifdef USE_ASSERT_CHECKING { - uint32 buf_state = pg_atomic_read_u32(&buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_VALID)); diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c index 9a93fb335fc..b7687836188 100644 --- a/src/backend/storage/buffer/freelist.c +++ b/src/backend/storage/buffer/freelist.c @@ -86,7 +86,7 @@ typedef struct BufferAccessStrategyData /* Prototypes for internal functions */ static BufferDesc *GetBufferFromRing(BufferAccessStrategy strategy, - uint32 *buf_state); + uint64 *buf_state); static void AddBufferToRing(BufferAccessStrategy strategy, BufferDesc *buf); @@ -171,7 +171,7 @@ ClockSweepTick(void) * before returning. */ BufferDesc * -StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_ring) +StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_ring) { BufferDesc *buf; int bgwprocno; @@ -230,8 +230,8 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r trycounter = NBuffers; for (;;) { - uint32 old_buf_state; - uint32 local_buf_state; + uint64 old_buf_state; + uint64 local_buf_state; buf = GetBufferDescriptor(ClockSweepTick()); @@ -239,7 +239,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r * Check whether the buffer can be used and pin it if so. Do this * using a CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -277,7 +277,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r { local_buf_state -= BUF_USAGECOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { trycounter = NBuffers; @@ -289,7 +289,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { /* Found a usable buffer */ @@ -655,12 +655,12 @@ FreeAccessStrategy(BufferAccessStrategy strategy) * returning. */ static BufferDesc * -GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) +GetBufferFromRing(BufferAccessStrategy strategy, uint64 *buf_state) { BufferDesc *buf; Buffer bufnum; - uint32 old_buf_state; - uint32 local_buf_state; /* to avoid repeated (de-)referencing */ + uint64 old_buf_state; + uint64 local_buf_state; /* to avoid repeated (de-)referencing */ /* Advance to next ring slot */ @@ -682,7 +682,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) * Check whether the buffer can be used and pin it if so. Do this using a * CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -710,7 +710,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { *buf_state = local_buf_state; diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index f6e2b1aa288..04a540379a2 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -148,7 +148,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, } else { - uint32 buf_state; + uint64 buf_state; victim_buffer = GetLocalVictimBuffer(); bufid = -victim_buffer - 1; @@ -165,10 +165,10 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, */ bufHdr->tag = newTag; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); buf_state &= ~(BUF_FLAG_MASK | BUF_USAGECOUNT_MASK); buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); *foundPtr = false; } @@ -245,12 +245,12 @@ GetLocalVictimBuffer(void) if (LocalRefCount[victim_bufid] == 0) { - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0) { buf_state -= BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); trycounter = NLocBuffer; } else if (BUF_STATE_GET_REFCOUNT(buf_state) > 0) @@ -286,13 +286,13 @@ GetLocalVictimBuffer(void) * this buffer is not referenced but it might still be dirty. if that's * the case, write it out before reusing it! */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY) FlushLocalBuffer(bufHdr, NULL); /* * Remove the victim buffer from the hashtable and mark as invalid. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID) + if (pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID) { InvalidateLocalBuffer(bufHdr, false); @@ -417,7 +417,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, if (found) { BufferDesc *existing_hdr; - uint32 buf_state; + uint64 buf_state; UnpinLocalBuffer(BufferDescriptorGetBuffer(victim_buf_hdr)); @@ -428,18 +428,18 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, /* * Clear the BM_VALID bit, do StartLocalBufferIO() and proceed. */ - buf_state = pg_atomic_read_u32(&existing_hdr->state); + buf_state = pg_atomic_read_u64(&existing_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_DIRTY)); buf_state &= ~BM_VALID; - pg_atomic_unlocked_write_u32(&existing_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&existing_hdr->state, buf_state); /* no need to loop for local buffers */ StartLocalBufferIO(existing_hdr, true, false); } else { - uint32 buf_state = pg_atomic_read_u32(&victim_buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&victim_buf_hdr->state); Assert(!(buf_state & (BM_VALID | BM_TAG_VALID | BM_DIRTY | BM_JUST_DIRTIED))); @@ -447,7 +447,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&victim_buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&victim_buf_hdr->state, buf_state); hresult->id = victim_buf_id; @@ -467,13 +467,13 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, { Buffer buf = buffers[i]; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); buf_state |= BM_VALID; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } *extended_by = extend_by; @@ -492,7 +492,7 @@ MarkLocalBufferDirty(Buffer buffer) { int bufid; BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsLocal(buffer)); @@ -506,14 +506,14 @@ MarkLocalBufferDirty(Buffer buffer) bufHdr = GetLocalBufferDescriptor(bufid); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_DIRTY)) pgBufferUsage.local_blks_dirtied++; buf_state |= BM_DIRTY; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -522,7 +522,7 @@ MarkLocalBufferDirty(Buffer buffer) bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; /* * With AIO the buffer could have IO in progress, e.g. when there are two @@ -542,7 +542,7 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) /* Once we get here, there is definitely no I/O active on this buffer */ /* Check if someone else already did the I/O */ - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (forInput ? (buf_state & BM_VALID) : !(buf_state & BM_DIRTY)) { return false; @@ -559,11 +559,11 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) * Like TerminateBufferIO, but for local buffers */ void -TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bits, +TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint64 set_flag_bits, bool release_aio) { /* Only need to adjust flags */ - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); /* BM_IO_IN_PROGRESS isn't currently used for local buffers */ @@ -582,7 +582,7 @@ TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bit } buf_state |= set_flag_bits; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); /* local buffers don't track IO using resowners */ @@ -606,7 +606,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) { Buffer buffer = BufferDescriptorGetBuffer(bufHdr); int bufid = -buffer - 1; - uint32 buf_state; + uint64 buf_state; LocalBufferLookupEnt *hresult; /* @@ -622,7 +622,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) Assert(!pgaio_wref_valid(&bufHdr->io_wref)); } - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* * We need to test not just LocalRefCount[bufid] but also the BufferDesc @@ -647,7 +647,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) ClearBufferTag(&bufHdr->tag); buf_state &= ~BUF_FLAG_MASK; buf_state &= ~BUF_USAGECOUNT_MASK; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -671,9 +671,9 @@ DropRelationLocalBuffers(RelFileLocator rlocator, ForkNumber *forkNum, for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_TAG_VALID) || !BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -706,9 +706,9 @@ DropRelationAllLocalBuffers(RelFileLocator rlocator) for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if ((buf_state & BM_TAG_VALID) && BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -804,11 +804,11 @@ InitLocalBuffers(void) bool PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { - uint32 buf_state; + uint64 buf_state; Buffer buffer = BufferDescriptorGetBuffer(buf_hdr); int bufid = -buffer - 1; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); if (LocalRefCount[bufid] == 0) { @@ -819,7 +819,7 @@ PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { buf_state += BUF_USAGECOUNT_ONE; } - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* * See comment in PinBuffer(). @@ -856,14 +856,14 @@ UnpinLocalBufferNoOwner(Buffer buffer) if (--LocalRefCount[buffid] == 0) { BufferDesc *buf_hdr = GetLocalBufferDescriptor(buffid); - uint32 buf_state; + uint64 buf_state; NLocalPinnedBuffers--; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state -= BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* see comment in UnpinBufferNoOwner */ VALGRIND_MAKE_MEM_NOACCESS(LocalBufHdrGetBlock(buf_hdr), BLCKSZ); diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index b682dca658b..dcba3fb5473 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -199,7 +199,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) for (i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -615,7 +615,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -626,7 +626,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) * noticeably increase the cost of the function. */ bufHdr = GetBufferDescriptor(i); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (buf_state & BM_VALID) { @@ -676,7 +676,7 @@ pg_buffercache_usage_counts(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); int usage_count; CHECK_FOR_INTERRUPTS(); diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c index 3ca7d2ed772..89e187425cc 100644 --- a/contrib/pg_prewarm/autoprewarm.c +++ b/contrib/pg_prewarm/autoprewarm.c @@ -703,7 +703,7 @@ apw_dump_now(bool is_bgworker, bool dump_unlogged) for (num_blocks = 0, i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); diff --git a/src/test/modules/test_aio/test_aio.c b/src/test/modules/test_aio/test_aio.c index e046b08f3d5..b1aa8af9ec0 100644 --- a/src/test/modules/test_aio/test_aio.c +++ b/src/test/modules/test_aio/test_aio.c @@ -308,9 +308,9 @@ create_toy_buffer(Relation rel, BlockNumber blkno) { Buffer buf; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; bool was_pinned = false; - uint32 unset_bits = 0; + uint64 unset_bits = 0; /* place buffer in shared buffers without erroring out */ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO_AND_LOCK, NULL); @@ -319,7 +319,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); } else { @@ -340,7 +340,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_state &= ~unset_bits; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else { @@ -489,7 +489,7 @@ invalidate_rel_block(PG_FUNCTION_ARGS) LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); - if (pg_atomic_read_u32(&buf_hdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&buf_hdr->state) & BM_DIRTY) { if (BufferIsLocal(buf)) FlushLocalBuffer(buf_hdr, NULL); @@ -572,7 +572,7 @@ buffer_call_terminate_io(PG_FUNCTION_ARGS) bool io_error = PG_GETARG_BOOL(3); bool release_aio = PG_GETARG_BOOL(4); bool clear_dirty = false; - uint32 set_flag_bits = 0; + uint64 set_flag_bits = 0; if (io_error) set_flag_bits |= BM_IO_ERROR; -- 2.48.1.76.g4e746b1a31.dirty --c6wqr3sg4llxfu2u Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v11-0002-bufmgr-Implement-buffer-content-locks-independen.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* [PATCH v11 1/7] bufmgr: Change BufferDesc.state to be a 64-bit atomic @ 2026-01-14 01:10 Andres Freund <[email protected]> 0 siblings, 0 replies; 22+ messages in thread From: Andres Freund @ 2026-01-14 01:10 UTC (permalink / raw) This is motivated by wanting to merge buffer content locks into BufferDesc.state in a future commit, rather than having a separate lwlock (see commit c75ebc657ff for more details). As this change is rather mechanical, it seems to make sense to split it out into a separate commit, for easier review. Reviewed-by: Melanie Plageman <[email protected]> Discussion: https://postgr.es/m/fvfmkr5kk4nyex56ejgxj3uzi63isfxovp2biecb4bspbjrze7@az2pljabhnff --- src/include/storage/buf_internals.h | 51 +++--- src/include/storage/procnumber.h | 14 +- src/backend/storage/buffer/buf_init.c | 2 +- src/backend/storage/buffer/bufmgr.c | 170 +++++++++--------- src/backend/storage/buffer/freelist.c | 24 +-- src/backend/storage/buffer/localbuf.c | 72 ++++---- contrib/pg_buffercache/pg_buffercache_pages.c | 8 +- contrib/pg_prewarm/autoprewarm.c | 2 +- src/test/modules/test_aio/test_aio.c | 12 +- 9 files changed, 179 insertions(+), 176 deletions(-) diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index 2f607ea2ac5..e6e788224f5 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -30,7 +30,7 @@ #include "utils/resowner.h" /* - * Buffer state is a single 32-bit variable where following data is combined. + * Buffer state is a single 64-bit variable where following data is combined. * * State of the buffer itself (in order): * - 18 bits refcount @@ -40,6 +40,9 @@ * Combining these values allows to perform some operations without locking * the buffer header, by modifying them together with a CAS loop. * + * NB: A future commit will use a significant portion of the remaining bits to + * implement buffer locking as part of the state variable. + * * The definition of buffer state components is below. */ #define BUF_REFCOUNT_BITS 18 @@ -52,27 +55,27 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, /* refcount related definitions */ #define BUF_REFCOUNT_ONE 1 #define BUF_REFCOUNT_MASK \ - ((1U << BUF_REFCOUNT_BITS) - 1) + ((UINT64CONST(1) << BUF_REFCOUNT_BITS) - 1) /* usage count related definitions */ #define BUF_USAGECOUNT_SHIFT \ BUF_REFCOUNT_BITS #define BUF_USAGECOUNT_MASK \ - (((1U << BUF_USAGECOUNT_BITS) - 1) << (BUF_USAGECOUNT_SHIFT)) + (((UINT64CONST(1) << BUF_USAGECOUNT_BITS) - 1) << (BUF_USAGECOUNT_SHIFT)) #define BUF_USAGECOUNT_ONE \ - (1U << BUF_REFCOUNT_BITS) + (UINT64CONST(1) << BUF_REFCOUNT_BITS) /* flags related definitions */ #define BUF_FLAG_SHIFT \ (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS) #define BUF_FLAG_MASK \ - (((1U << BUF_FLAG_BITS) - 1) << BUF_FLAG_SHIFT) + (((UINT64CONST(1) << BUF_FLAG_BITS) - 1) << BUF_FLAG_SHIFT) /* Get refcount and usagecount from buffer state */ #define BUF_STATE_GET_REFCOUNT(state) \ - ((state) & BUF_REFCOUNT_MASK) + ((uint32)((state) & BUF_REFCOUNT_MASK)) #define BUF_STATE_GET_USAGECOUNT(state) \ - (((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT) + ((uint32)(((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT)) /* * Flags for buffer descriptors @@ -82,7 +85,7 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, */ #define BUF_DEFINE_FLAG(flagno) \ - (1U << (BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + (flagno))) + (UINT64CONST(1) << (BUF_FLAG_SHIFT + (flagno))) /* buffer header is locked */ #define BM_LOCKED BUF_DEFINE_FLAG( 0) @@ -115,7 +118,7 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS == 32, */ #define BM_MAX_USAGE_COUNT 5 -StaticAssertDecl(BM_MAX_USAGE_COUNT < (1 << BUF_USAGECOUNT_BITS), +StaticAssertDecl(BM_MAX_USAGE_COUNT < (UINT64CONST(1) << BUF_USAGECOUNT_BITS), "BM_MAX_USAGE_COUNT doesn't fit in BUF_USAGECOUNT_BITS bits"); StaticAssertDecl(MAX_BACKENDS_BITS <= BUF_REFCOUNT_BITS, "MAX_BACKENDS_BITS needs to be <= BUF_REFCOUNT_BITS"); @@ -280,8 +283,8 @@ BufMappingPartitionLockByIndex(uint32 index) * We use this same struct for local buffer headers, but the locks are not * used and not all of the flag bits are useful either. To avoid unnecessary * overhead, manipulations of the state field should be done without actual - * atomic operations (i.e. only pg_atomic_read_u32() and - * pg_atomic_unlocked_write_u32()). + * atomic operations (i.e. only pg_atomic_read_u64() and + * pg_atomic_unlocked_write_u64()). * * Be careful to avoid increasing the size of the struct when adding or * reordering members. Keeping it below 64 bytes (the most common CPU @@ -309,7 +312,7 @@ typedef struct BufferDesc * State of the buffer, containing flags, refcount and usagecount. See * BUF_* and BM_* defines at the top of this file. */ - pg_atomic_uint32 state; + pg_atomic_uint64 state; /* * Backend of pin-count waiter. The buffer header spinlock needs to be @@ -415,7 +418,7 @@ BufferDescriptorGetContentLock(const BufferDesc *bdesc) * Functions for acquiring/releasing a shared buffer header's spinlock. Do * not apply these to local buffers! */ -extern uint32 LockBufHdr(BufferDesc *desc); +extern uint64 LockBufHdr(BufferDesc *desc); /* * Unlock the buffer header. @@ -426,9 +429,9 @@ extern uint32 LockBufHdr(BufferDesc *desc); static inline void UnlockBufHdr(BufferDesc *desc) { - Assert(pg_atomic_read_u32(&desc->state) & BM_LOCKED); + Assert(pg_atomic_read_u64(&desc->state) & BM_LOCKED); - pg_atomic_fetch_sub_u32(&desc->state, BM_LOCKED); + pg_atomic_fetch_sub_u64(&desc->state, BM_LOCKED); } /* @@ -439,14 +442,14 @@ UnlockBufHdr(BufferDesc *desc) * Note that this approach would not work for usagecount, since we need to cap * the usagecount at BM_MAX_USAGE_COUNT. */ -static inline uint32 -UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, - uint32 set_bits, uint32 unset_bits, +static inline uint64 +UnlockBufHdrExt(BufferDesc *desc, uint64 old_buf_state, + uint64 set_bits, uint64 unset_bits, int refcount_change) { for (;;) { - uint32 buf_state = old_buf_state; + uint64 buf_state = old_buf_state; Assert(buf_state & BM_LOCKED); @@ -457,7 +460,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, if (refcount_change != 0) buf_state += BUF_REFCOUNT_ONE * refcount_change; - if (pg_atomic_compare_exchange_u32(&desc->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&desc->state, &old_buf_state, buf_state)) { return old_buf_state; @@ -465,7 +468,7 @@ UnlockBufHdrExt(BufferDesc *desc, uint32 old_buf_state, } } -extern uint32 WaitBufHdrUnlocked(BufferDesc *buf); +extern uint64 WaitBufHdrUnlocked(BufferDesc *buf); /* in bufmgr.c */ @@ -525,14 +528,14 @@ extern void TrackNewBufferPin(Buffer buf); /* solely to make it easier to write tests */ extern bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait); -extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio); /* freelist.c */ extern IOContext IOContextForStrategy(BufferAccessStrategy strategy); extern BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy, - uint32 *buf_state, bool *from_ring); + uint64 *buf_state, bool *from_ring); extern bool StrategyRejectBuffer(BufferAccessStrategy strategy, BufferDesc *buf, bool from_ring); @@ -568,7 +571,7 @@ extern BlockNumber ExtendBufferedRelLocal(BufferManagerRelation bmr, uint32 *extended_by); extern void MarkLocalBufferDirty(Buffer buffer); extern void TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, - uint32 set_flag_bits, bool release_aio); + uint64 set_flag_bits, bool release_aio); extern bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait); extern void FlushLocalBuffer(BufferDesc *bufHdr, SMgrRelation reln); extern void InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced); diff --git a/src/include/storage/procnumber.h b/src/include/storage/procnumber.h index 30c360ad350..bd9cb3891cc 100644 --- a/src/include/storage/procnumber.h +++ b/src/include/storage/procnumber.h @@ -27,13 +27,13 @@ typedef int ProcNumber; /* * Note: MAX_BACKENDS_BITS is 18 as that is the space available for buffer - * refcounts in buf_internals.h. This limitation could be lifted by using a - * 64bit state; but it's unlikely to be worthwhile as 2^18-1 backends exceed - * currently realistic configurations. Even if that limitation were removed, - * we still could not a) exceed 2^23-1 because inval.c stores the ProcNumber - * as a 3-byte signed integer, b) INT_MAX/4 because some places compute - * 4*MaxBackends without any overflow check. We check that the configured - * number of backends does not exceed MAX_BACKENDS in InitializeMaxBackends(). + * refcounts in buf_internals.h. This limitation could be lifted, but it's + * unlikely to be worthwhile as 2^18-1 backends exceed currently realistic + * configurations. Even if that limitation were removed, we still could not a) + * exceed 2^23-1 because inval.c stores the ProcNumber as a 3-byte signed + * integer, b) INT_MAX/4 because some places compute 4*MaxBackends without any + * overflow check. We check that the configured number of backends does not + * exceed MAX_BACKENDS in InitializeMaxBackends(). */ #define MAX_BACKENDS_BITS 18 #define MAX_BACKENDS ((1U << MAX_BACKENDS_BITS)-1) diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index 9a312bcc7b3..7d894522526 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -121,7 +121,7 @@ BufferManagerShmemInit(void) ClearBufferTag(&buf->tag); - pg_atomic_init_u32(&buf->state, 0); + pg_atomic_init_u64(&buf->state, 0); buf->wait_backend_pgprocno = INVALID_PROC_NUMBER; buf->buf_id = i; diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index a036c2aa275..b0de8e45d4d 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -780,7 +780,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN { BufferDesc *bufHdr; BufferTag tag; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(recent_buffer)); @@ -793,7 +793,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN int b = -recent_buffer - 1; bufHdr = GetLocalBufferDescriptor(b); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* Is it still valid and holding the right tag? */ if ((buf_state & BM_VALID) && BufferTagsEqual(&tag, &bufHdr->tag)) @@ -1386,8 +1386,8 @@ StartReadBuffersImpl(ReadBuffersOperation *operation, bufHdr = GetLocalBufferDescriptor(-buffers[i] - 1); else bufHdr = GetBufferDescriptor(buffers[i] - 1); - Assert(pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID); - found = pg_atomic_read_u32(&bufHdr->state) & BM_VALID; + Assert(pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID); + found = pg_atomic_read_u64(&bufHdr->state) & BM_VALID; } else { @@ -1613,10 +1613,10 @@ CheckReadBuffersOperation(ReadBuffersOperation *operation, bool is_complete) GetBufferDescriptor(buffer - 1); Assert(BufferGetBlockNumber(buffer) == operation->blocknum + i); - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_TAG_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_TAG_VALID); if (i < operation->nblocks_done) - Assert(pg_atomic_read_u32(&buf_hdr->state) & BM_VALID); + Assert(pg_atomic_read_u64(&buf_hdr->state) & BM_VALID); } #endif } @@ -2083,8 +2083,8 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum, int existing_buf_id; Buffer victim_buffer; BufferDesc *victim_buf_hdr; - uint32 victim_buf_state; - uint32 set_bits = 0; + uint64 victim_buf_state; + uint64 set_bits = 0; /* Make sure we will have room to remember the buffer pin */ ResourceOwnerEnlarge(CurrentResourceOwner); @@ -2251,7 +2251,7 @@ InvalidateBuffer(BufferDesc *buf) uint32 oldHash; /* hash value for oldTag */ LWLock *oldPartitionLock; /* buffer partition lock for it */ uint32 oldFlags; - uint32 buf_state; + uint64 buf_state; /* Save the original buffer tag before dropping the spinlock */ oldTag = buf->tag; @@ -2342,7 +2342,7 @@ retry: static bool InvalidateVictimBuffer(BufferDesc *buf_hdr) { - uint32 buf_state; + uint64 buf_state; uint32 hash; LWLock *partition_lock; BufferTag tag; @@ -2402,10 +2402,10 @@ InvalidateVictimBuffer(BufferDesc *buf_hdr) LWLockRelease(partition_lock); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(!(buf_state & (BM_DIRTY | BM_VALID | BM_TAG_VALID))); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); - Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u32(&buf_hdr->state)) > 0); + Assert(BUF_STATE_GET_REFCOUNT(pg_atomic_read_u64(&buf_hdr->state)) > 0); return true; } @@ -2415,7 +2415,7 @@ GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context) { BufferDesc *buf_hdr; Buffer buf; - uint32 buf_state; + uint64 buf_state; bool from_ring; /* @@ -2548,7 +2548,7 @@ again: /* a final set of sanity checks */ #ifdef USE_ASSERT_CHECKING - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) == 1); Assert(!(buf_state & (BM_TAG_VALID | BM_VALID | BM_DIRTY))); @@ -2839,13 +2839,13 @@ ExtendBufferedRelShared(BufferManagerRelation bmr, */ do { - pg_atomic_fetch_and_u32(&existing_hdr->state, ~BM_VALID); + pg_atomic_fetch_and_u64(&existing_hdr->state, ~BM_VALID); } while (!StartBufferIO(existing_hdr, true, false)); } else { - uint32 buf_state; - uint32 set_bits = 0; + uint64 buf_state; + uint64 set_bits = 0; buf_state = LockBufHdr(victim_buf_hdr); @@ -3021,7 +3021,7 @@ BufferIsDirty(Buffer buffer) Assert(BufferIsLockedByMeInMode(buffer, BUFFER_LOCK_EXCLUSIVE)); } - return pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY; + return pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY; } /* @@ -3037,8 +3037,8 @@ void MarkBufferDirty(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; if (!BufferIsValid(buffer)) elog(ERROR, "bad buffer ID: %d", buffer); @@ -3058,7 +3058,7 @@ MarkBufferDirty(Buffer buffer) * NB: We have to wait for the buffer header spinlock to be not held, as * TerminateBufferIO() relies on the spinlock. */ - old_buf_state = pg_atomic_read_u32(&bufHdr->state); + old_buf_state = pg_atomic_read_u64(&bufHdr->state); for (;;) { if (old_buf_state & BM_LOCKED) @@ -3069,7 +3069,7 @@ MarkBufferDirty(Buffer buffer) Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state |= BM_DIRTY | BM_JUST_DIRTIED; - if (pg_atomic_compare_exchange_u32(&bufHdr->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&bufHdr->state, &old_buf_state, buf_state)) break; } @@ -3173,10 +3173,10 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, if (ref == NULL) { - uint32 buf_state; - uint32 old_buf_state; + uint64 buf_state; + uint64 old_buf_state; - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { if (unlikely(skip_if_not_valid && !(old_buf_state & BM_VALID))) @@ -3210,7 +3210,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, buf_state += BUF_USAGECOUNT_ONE; } - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, buf_state)) { result = (buf_state & BM_VALID) != 0; @@ -3237,7 +3237,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, * that the buffer page is legitimately non-accessible here. We * cannot meddle with that. */ - result = (pg_atomic_read_u32(&buf->state) & BM_VALID) != 0; + result = (pg_atomic_read_u64(&buf->state) & BM_VALID) != 0; Assert(ref->data.refcount > 0); ref->data.refcount++; @@ -3272,7 +3272,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy, static void PinBuffer_Locked(BufferDesc *buf) { - uint32 old_buf_state; + uint64 old_buf_state; /* * As explained, We don't expect any preexisting pins. That allows us to @@ -3284,7 +3284,7 @@ PinBuffer_Locked(BufferDesc *buf) * Since we hold the buffer spinlock, we can update the buffer state and * release the lock in one operation. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); UnlockBufHdrExt(buf, old_buf_state, 0, 0, 1); @@ -3314,7 +3314,7 @@ WakePinCountWaiter(BufferDesc *buf) * BM_PIN_COUNT_WAITER if it stops waiting for a reason other than this * backend waking it up. */ - uint32 buf_state = LockBufHdr(buf); + uint64 buf_state = LockBufHdr(buf); if ((buf_state & BM_PIN_COUNT_WAITER) && BUF_STATE_GET_REFCOUNT(buf_state) == 1) @@ -3361,7 +3361,7 @@ UnpinBufferNoOwner(BufferDesc *buf) ref->data.refcount--; if (ref->data.refcount == 0) { - uint32 old_buf_state; + uint64 old_buf_state; /* * Mark buffer non-accessible to Valgrind. @@ -3379,7 +3379,7 @@ UnpinBufferNoOwner(BufferDesc *buf) Assert(!LWLockHeldByMe(BufferDescriptorGetContentLock(buf))); /* decrement the shared reference count */ - old_buf_state = pg_atomic_fetch_sub_u32(&buf->state, BUF_REFCOUNT_ONE); + old_buf_state = pg_atomic_fetch_sub_u64(&buf->state, BUF_REFCOUNT_ONE); /* Support LockBufferForCleanup() */ if (old_buf_state & BM_PIN_COUNT_WAITER) @@ -3436,7 +3436,7 @@ TrackNewBufferPin(Buffer buf) static void BufferSync(int flags) { - uint32 buf_state; + uint64 buf_state; int buf_id; int num_to_scan; int num_spaces; @@ -3446,7 +3446,7 @@ BufferSync(int flags) Oid last_tsid; binaryheap *ts_heap; int i; - uint32 mask = BM_DIRTY; + uint64 mask = BM_DIRTY; WritebackContext wb_context; /* @@ -3478,7 +3478,7 @@ BufferSync(int flags) for (buf_id = 0; buf_id < NBuffers; buf_id++) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); - uint32 set_bits = 0; + uint64 set_bits = 0; /* * Header spinlock is enough to examine BM_DIRTY, see comment in @@ -3645,7 +3645,7 @@ BufferSync(int flags) * write the buffer though we didn't need to. It doesn't seem worth * guarding against this, though. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_CHECKPOINT_NEEDED) + if (pg_atomic_read_u64(&bufHdr->state) & BM_CHECKPOINT_NEEDED) { if (SyncOneBuffer(buf_id, false, &wb_context) & BUF_WRITTEN) { @@ -4015,7 +4015,7 @@ SyncOneBuffer(int buf_id, bool skip_recently_used, WritebackContext *wb_context) { BufferDesc *bufHdr = GetBufferDescriptor(buf_id); int result = 0; - uint32 buf_state; + uint64 buf_state; BufferTag tag; /* Make sure we can handle the pin */ @@ -4264,7 +4264,7 @@ DebugPrintBufferRefcount(Buffer buffer) int32 loccount; char *result; ProcNumber backend; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); if (BufferIsLocal(buffer)) @@ -4281,9 +4281,9 @@ DebugPrintBufferRefcount(Buffer buffer) } /* theoretically we should lock the bufHdr here */ - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); - result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%x, refcount=%u %d)", + result = psprintf("[%03d] (rel=%s, blockNum=%u, flags=0x%" PRIx64 ", refcount=%u %d)", buffer, relpathbackend(BufTagGetRelFileLocator(&buf->tag), backend, BufTagGetForkNum(&buf->tag)).str, @@ -4383,7 +4383,7 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object, instr_time io_start; Block bufBlock; char *bufToWrite; - uint32 buf_state; + uint64 buf_state; /* * Try to start an I/O operation. If StartBufferIO returns false, then @@ -4581,7 +4581,7 @@ BufferIsPermanent(Buffer buffer) * not random garbage. */ bufHdr = GetBufferDescriptor(buffer - 1); - return (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT) != 0; + return (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT) != 0; } /* @@ -5044,11 +5044,11 @@ FlushRelationBuffers(Relation rel) { for (i = 0; i < NLocBuffer; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetLocalBufferDescriptor(i); if (BufTagMatchesRelFileLocator(&bufHdr->tag, &rel->rd_locator) && - ((buf_state = pg_atomic_read_u32(&bufHdr->state)) & + ((buf_state = pg_atomic_read_u64(&bufHdr->state)) & (BM_VALID | BM_DIRTY)) == (BM_VALID | BM_DIRTY)) { ErrorContextCallback errcallback; @@ -5084,7 +5084,7 @@ FlushRelationBuffers(Relation rel) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5156,7 +5156,7 @@ FlushRelationsAllBuffers(SMgrRelation *smgrs, int nrels) { SMgrSortArray *srelent = NULL; BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; /* * As in DropRelationBuffers, an unlocked precheck should be safe and @@ -5405,7 +5405,7 @@ FlushDatabaseBuffers(Oid dbid) for (i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; bufHdr = GetBufferDescriptor(i); @@ -5553,13 +5553,13 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * is only intended to be used in cases where failing to write out the * data would be harmless anyway, it doesn't really matter. */ - if ((pg_atomic_read_u32(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != + if ((pg_atomic_read_u64(&bufHdr->state) & (BM_DIRTY | BM_JUST_DIRTIED)) != (BM_DIRTY | BM_JUST_DIRTIED)) { XLogRecPtr lsn = InvalidXLogRecPtr; bool dirtied = false; bool delayChkptFlags = false; - uint32 buf_state; + uint64 buf_state; /* * If we need to protect hint bit updates from torn writes, WAL-log a @@ -5571,7 +5571,7 @@ MarkBufferDirtyHint(Buffer buffer, bool buffer_std) * when we call XLogInsert() since the value changes dynamically. */ if (XLogHintBitIsNeeded() && - (pg_atomic_read_u32(&bufHdr->state) & BM_PERMANENT)) + (pg_atomic_read_u64(&bufHdr->state) & BM_PERMANENT)) { /* * If we must not write WAL, due to a relfilelocator-specific @@ -5671,8 +5671,8 @@ UnlockBuffers(void) if (buf) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; buf_state = LockBufHdr(buf); @@ -5803,8 +5803,8 @@ LockBufferForCleanup(Buffer buffer) for (;;) { - uint32 buf_state; - uint32 unset_bits = 0; + uint64 buf_state; + uint64 unset_bits = 0; /* Try to acquire lock */ LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); @@ -5952,7 +5952,7 @@ bool ConditionalLockBufferForCleanup(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state, + uint64 buf_state, refcount; Assert(BufferIsValid(buffer)); @@ -6010,7 +6010,7 @@ bool IsBufferCleanupOK(Buffer buffer) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsValid(buffer)); @@ -6066,7 +6066,7 @@ WaitIO(BufferDesc *buf) ConditionVariablePrepareToSleep(cv); for (;;) { - uint32 buf_state; + uint64 buf_state; PgAioWaitRef iow; /* @@ -6140,7 +6140,7 @@ WaitIO(BufferDesc *buf) bool StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; ResourceOwnerEnlarge(CurrentResourceOwner); @@ -6196,11 +6196,11 @@ StartBufferIO(BufferDesc *buf, bool forInput, bool nowait) * is being released) */ void -TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint32 set_flag_bits, +TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag_bits, bool forget_owner, bool release_aio) { - uint32 buf_state; - uint32 unset_flag_bits = 0; + uint64 buf_state; + uint64 unset_flag_bits = 0; int refcount_change = 0; buf_state = LockBufHdr(buf); @@ -6261,7 +6261,7 @@ static void AbortBufferIO(Buffer buffer) { BufferDesc *buf_hdr = GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; buf_state = LockBufHdr(buf_hdr); Assert(buf_state & (BM_IO_IN_PROGRESS | BM_TAG_VALID)); @@ -6355,10 +6355,10 @@ rlocator_comparator(const void *p1, const void *p2) /* * Lock buffer header - set BM_LOCKED in buffer state. */ -uint32 +uint64 LockBufHdr(BufferDesc *desc) { - uint32 old_buf_state; + uint64 old_buf_state; Assert(!BufferIsLocal(BufferDescriptorGetBuffer(desc))); @@ -6369,7 +6369,7 @@ LockBufHdr(BufferDesc *desc) * the spin-delay infrastructure. The work necessary for that shows up * in profiles and is rarely necessary. */ - old_buf_state = pg_atomic_fetch_or_u32(&desc->state, BM_LOCKED); + old_buf_state = pg_atomic_fetch_or_u64(&desc->state, BM_LOCKED); if (likely(!(old_buf_state & BM_LOCKED))) break; /* got lock */ @@ -6382,7 +6382,7 @@ LockBufHdr(BufferDesc *desc) while (old_buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - old_buf_state = pg_atomic_read_u32(&desc->state); + old_buf_state = pg_atomic_read_u64(&desc->state); } finish_spin_delay(&delayStatus); } @@ -6403,20 +6403,20 @@ LockBufHdr(BufferDesc *desc) * Obviously the buffer could be locked by the time the value is returned, so * this is primarily useful in CAS style loops. */ -pg_noinline uint32 +pg_noinline uint64 WaitBufHdrUnlocked(BufferDesc *buf) { SpinDelayStatus delayStatus; - uint32 buf_state; + uint64 buf_state; init_local_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); while (buf_state & BM_LOCKED) { perform_spin_delay(&delayStatus); - buf_state = pg_atomic_read_u32(&buf->state); + buf_state = pg_atomic_read_u64(&buf->state); } finish_spin_delay(&delayStatus); @@ -6704,12 +6704,12 @@ ResOwnerPrintBufferPin(Datum res) static bool EvictUnpinnedBufferInternal(BufferDesc *desc, bool *buffer_flushed) { - uint32 buf_state; + uint64 buf_state; bool result; *buffer_flushed = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -6803,12 +6803,12 @@ EvictAllUnpinnedBuffers(int32 *buffers_evicted, int32 *buffers_flushed, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_flushed; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -6855,7 +6855,7 @@ EvictRelUnpinnedBuffers(Relation rel, int32 *buffers_evicted, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_flushed; CHECK_FOR_INTERRUPTS(); @@ -6897,12 +6897,12 @@ static bool MarkDirtyUnpinnedBufferInternal(Buffer buf, BufferDesc *desc, bool *buffer_already_dirty) { - uint32 buf_state; + uint64 buf_state; bool result = false; *buffer_already_dirty = false; - buf_state = pg_atomic_read_u32(&(desc->state)); + buf_state = pg_atomic_read_u64(&(desc->state)); Assert(buf_state & BM_LOCKED); if ((buf_state & BM_VALID) == 0) @@ -7000,7 +7000,7 @@ MarkDirtyRelUnpinnedBuffers(Relation rel, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state = pg_atomic_read_u32(&(desc->state)); + uint64 buf_state = pg_atomic_read_u64(&(desc->state)); bool buffer_already_dirty; CHECK_FOR_INTERRUPTS(); @@ -7054,12 +7054,12 @@ MarkDirtyAllUnpinnedBuffers(int32 *buffers_dirtied, for (int buf = 1; buf <= NBuffers; buf++) { BufferDesc *desc = GetBufferDescriptor(buf - 1); - uint32 buf_state; + uint64 buf_state; bool buffer_already_dirty; CHECK_FOR_INTERRUPTS(); - buf_state = pg_atomic_read_u32(&desc->state); + buf_state = pg_atomic_read_u64(&desc->state); if (!(buf_state & BM_VALID)) continue; @@ -7110,7 +7110,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) BufferDesc *buf_hdr = is_temp ? GetLocalBufferDescriptor(-buffer - 1) : GetBufferDescriptor(buffer - 1); - uint32 buf_state; + uint64 buf_state; /* * Check that all the buffers are actually ones that could conceivably @@ -7128,7 +7128,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) } if (is_temp) - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); else buf_state = LockBufHdr(buf_hdr); @@ -7166,7 +7166,7 @@ buffer_stage_common(PgAioHandle *ioh, bool is_write, bool is_temp) if (is_temp) { buf_state += BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else UnlockBufHdrExt(buf_hdr, buf_state, 0, 0, 1); @@ -7352,13 +7352,13 @@ buffer_readv_complete_one(PgAioTargetData *td, uint8 buf_off, Buffer buffer, : GetBufferDescriptor(buffer - 1); BufferTag tag = buf_hdr->tag; char *bufdata = BufferGetBlock(buffer); - uint32 set_flag_bits; + uint64 set_flag_bits; int piv_flags; /* check that the buffer is in the expected state for a read */ #ifdef USE_ASSERT_CHECKING { - uint32 buf_state = pg_atomic_read_u32(&buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_VALID)); diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c index 9a93fb335fc..b7687836188 100644 --- a/src/backend/storage/buffer/freelist.c +++ b/src/backend/storage/buffer/freelist.c @@ -86,7 +86,7 @@ typedef struct BufferAccessStrategyData /* Prototypes for internal functions */ static BufferDesc *GetBufferFromRing(BufferAccessStrategy strategy, - uint32 *buf_state); + uint64 *buf_state); static void AddBufferToRing(BufferAccessStrategy strategy, BufferDesc *buf); @@ -171,7 +171,7 @@ ClockSweepTick(void) * before returning. */ BufferDesc * -StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_ring) +StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_ring) { BufferDesc *buf; int bgwprocno; @@ -230,8 +230,8 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r trycounter = NBuffers; for (;;) { - uint32 old_buf_state; - uint32 local_buf_state; + uint64 old_buf_state; + uint64 local_buf_state; buf = GetBufferDescriptor(ClockSweepTick()); @@ -239,7 +239,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r * Check whether the buffer can be used and pin it if so. Do this * using a CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -277,7 +277,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r { local_buf_state -= BUF_USAGECOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { trycounter = NBuffers; @@ -289,7 +289,7 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint32 *buf_state, bool *from_r /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { /* Found a usable buffer */ @@ -655,12 +655,12 @@ FreeAccessStrategy(BufferAccessStrategy strategy) * returning. */ static BufferDesc * -GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) +GetBufferFromRing(BufferAccessStrategy strategy, uint64 *buf_state) { BufferDesc *buf; Buffer bufnum; - uint32 old_buf_state; - uint32 local_buf_state; /* to avoid repeated (de-)referencing */ + uint64 old_buf_state; + uint64 local_buf_state; /* to avoid repeated (de-)referencing */ /* Advance to next ring slot */ @@ -682,7 +682,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) * Check whether the buffer can be used and pin it if so. Do this using a * CAS loop, to avoid having to lock the buffer header. */ - old_buf_state = pg_atomic_read_u32(&buf->state); + old_buf_state = pg_atomic_read_u64(&buf->state); for (;;) { local_buf_state = old_buf_state; @@ -710,7 +710,7 @@ GetBufferFromRing(BufferAccessStrategy strategy, uint32 *buf_state) /* pin the buffer if the CAS succeeds */ local_buf_state += BUF_REFCOUNT_ONE; - if (pg_atomic_compare_exchange_u32(&buf->state, &old_buf_state, + if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state, local_buf_state)) { *buf_state = local_buf_state; diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index f6e2b1aa288..04a540379a2 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -148,7 +148,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, } else { - uint32 buf_state; + uint64 buf_state; victim_buffer = GetLocalVictimBuffer(); bufid = -victim_buffer - 1; @@ -165,10 +165,10 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, */ bufHdr->tag = newTag; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); buf_state &= ~(BUF_FLAG_MASK | BUF_USAGECOUNT_MASK); buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); *foundPtr = false; } @@ -245,12 +245,12 @@ GetLocalVictimBuffer(void) if (LocalRefCount[victim_bufid] == 0) { - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0) { buf_state -= BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); trycounter = NLocBuffer; } else if (BUF_STATE_GET_REFCOUNT(buf_state) > 0) @@ -286,13 +286,13 @@ GetLocalVictimBuffer(void) * this buffer is not referenced but it might still be dirty. if that's * the case, write it out before reusing it! */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY) FlushLocalBuffer(bufHdr, NULL); /* * Remove the victim buffer from the hashtable and mark as invalid. */ - if (pg_atomic_read_u32(&bufHdr->state) & BM_TAG_VALID) + if (pg_atomic_read_u64(&bufHdr->state) & BM_TAG_VALID) { InvalidateLocalBuffer(bufHdr, false); @@ -417,7 +417,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, if (found) { BufferDesc *existing_hdr; - uint32 buf_state; + uint64 buf_state; UnpinLocalBuffer(BufferDescriptorGetBuffer(victim_buf_hdr)); @@ -428,18 +428,18 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, /* * Clear the BM_VALID bit, do StartLocalBufferIO() and proceed. */ - buf_state = pg_atomic_read_u32(&existing_hdr->state); + buf_state = pg_atomic_read_u64(&existing_hdr->state); Assert(buf_state & BM_TAG_VALID); Assert(!(buf_state & BM_DIRTY)); buf_state &= ~BM_VALID; - pg_atomic_unlocked_write_u32(&existing_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&existing_hdr->state, buf_state); /* no need to loop for local buffers */ StartLocalBufferIO(existing_hdr, true, false); } else { - uint32 buf_state = pg_atomic_read_u32(&victim_buf_hdr->state); + uint64 buf_state = pg_atomic_read_u64(&victim_buf_hdr->state); Assert(!(buf_state & (BM_VALID | BM_TAG_VALID | BM_DIRTY | BM_JUST_DIRTIED))); @@ -447,7 +447,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE; - pg_atomic_unlocked_write_u32(&victim_buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&victim_buf_hdr->state, buf_state); hresult->id = victim_buf_id; @@ -467,13 +467,13 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr, { Buffer buf = buffers[i]; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); buf_state |= BM_VALID; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } *extended_by = extend_by; @@ -492,7 +492,7 @@ MarkLocalBufferDirty(Buffer buffer) { int bufid; BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; Assert(BufferIsLocal(buffer)); @@ -506,14 +506,14 @@ MarkLocalBufferDirty(Buffer buffer) bufHdr = GetLocalBufferDescriptor(bufid); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_DIRTY)) pgBufferUsage.local_blks_dirtied++; buf_state |= BM_DIRTY; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -522,7 +522,7 @@ MarkLocalBufferDirty(Buffer buffer) bool StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) { - uint32 buf_state; + uint64 buf_state; /* * With AIO the buffer could have IO in progress, e.g. when there are two @@ -542,7 +542,7 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) /* Once we get here, there is definitely no I/O active on this buffer */ /* Check if someone else already did the I/O */ - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (forInput ? (buf_state & BM_VALID) : !(buf_state & BM_DIRTY)) { return false; @@ -559,11 +559,11 @@ StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool nowait) * Like TerminateBufferIO, but for local buffers */ void -TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bits, +TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint64 set_flag_bits, bool release_aio) { /* Only need to adjust flags */ - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); /* BM_IO_IN_PROGRESS isn't currently used for local buffers */ @@ -582,7 +582,7 @@ TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint32 set_flag_bit } buf_state |= set_flag_bits; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); /* local buffers don't track IO using resowners */ @@ -606,7 +606,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) { Buffer buffer = BufferDescriptorGetBuffer(bufHdr); int bufid = -buffer - 1; - uint32 buf_state; + uint64 buf_state; LocalBufferLookupEnt *hresult; /* @@ -622,7 +622,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) Assert(!pgaio_wref_valid(&bufHdr->io_wref)); } - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); /* * We need to test not just LocalRefCount[bufid] but also the BufferDesc @@ -647,7 +647,7 @@ InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced) ClearBufferTag(&bufHdr->tag); buf_state &= ~BUF_FLAG_MASK; buf_state &= ~BUF_USAGECOUNT_MASK; - pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state); + pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state); } /* @@ -671,9 +671,9 @@ DropRelationLocalBuffers(RelFileLocator rlocator, ForkNumber *forkNum, for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (!(buf_state & BM_TAG_VALID) || !BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -706,9 +706,9 @@ DropRelationAllLocalBuffers(RelFileLocator rlocator) for (i = 0; i < NLocBuffer; i++) { BufferDesc *bufHdr = GetLocalBufferDescriptor(i); - uint32 buf_state; + uint64 buf_state; - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if ((buf_state & BM_TAG_VALID) && BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator)) @@ -804,11 +804,11 @@ InitLocalBuffers(void) bool PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { - uint32 buf_state; + uint64 buf_state; Buffer buffer = BufferDescriptorGetBuffer(buf_hdr); int bufid = -buffer - 1; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); if (LocalRefCount[bufid] == 0) { @@ -819,7 +819,7 @@ PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount) { buf_state += BUF_USAGECOUNT_ONE; } - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* * See comment in PinBuffer(). @@ -856,14 +856,14 @@ UnpinLocalBufferNoOwner(Buffer buffer) if (--LocalRefCount[buffid] == 0) { BufferDesc *buf_hdr = GetLocalBufferDescriptor(buffid); - uint32 buf_state; + uint64 buf_state; NLocalPinnedBuffers--; - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); Assert(BUF_STATE_GET_REFCOUNT(buf_state) > 0); buf_state -= BUF_REFCOUNT_ONE; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); /* see comment in UnpinBufferNoOwner */ VALGRIND_MAKE_MEM_NOACCESS(LocalBufHdrGetBlock(buf_hdr), BLCKSZ); diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index b682dca658b..dcba3fb5473 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -199,7 +199,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) for (i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -615,7 +615,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr; - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); @@ -626,7 +626,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) * noticeably increase the cost of the function. */ bufHdr = GetBufferDescriptor(i); - buf_state = pg_atomic_read_u32(&bufHdr->state); + buf_state = pg_atomic_read_u64(&bufHdr->state); if (buf_state & BM_VALID) { @@ -676,7 +676,7 @@ pg_buffercache_usage_counts(PG_FUNCTION_ARGS) for (int i = 0; i < NBuffers; i++) { BufferDesc *bufHdr = GetBufferDescriptor(i); - uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + uint64 buf_state = pg_atomic_read_u64(&bufHdr->state); int usage_count; CHECK_FOR_INTERRUPTS(); diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c index 3ca7d2ed772..89e187425cc 100644 --- a/contrib/pg_prewarm/autoprewarm.c +++ b/contrib/pg_prewarm/autoprewarm.c @@ -703,7 +703,7 @@ apw_dump_now(bool is_bgworker, bool dump_unlogged) for (num_blocks = 0, i = 0; i < NBuffers; i++) { - uint32 buf_state; + uint64 buf_state; CHECK_FOR_INTERRUPTS(); diff --git a/src/test/modules/test_aio/test_aio.c b/src/test/modules/test_aio/test_aio.c index e046b08f3d5..b1aa8af9ec0 100644 --- a/src/test/modules/test_aio/test_aio.c +++ b/src/test/modules/test_aio/test_aio.c @@ -308,9 +308,9 @@ create_toy_buffer(Relation rel, BlockNumber blkno) { Buffer buf; BufferDesc *buf_hdr; - uint32 buf_state; + uint64 buf_state; bool was_pinned = false; - uint32 unset_bits = 0; + uint64 unset_bits = 0; /* place buffer in shared buffers without erroring out */ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO_AND_LOCK, NULL); @@ -319,7 +319,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_hdr = GetLocalBufferDescriptor(-buf - 1); - buf_state = pg_atomic_read_u32(&buf_hdr->state); + buf_state = pg_atomic_read_u64(&buf_hdr->state); } else { @@ -340,7 +340,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno) if (RelationUsesLocalBuffers(rel)) { buf_state &= ~unset_bits; - pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state); + pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state); } else { @@ -489,7 +489,7 @@ invalidate_rel_block(PG_FUNCTION_ARGS) LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); - if (pg_atomic_read_u32(&buf_hdr->state) & BM_DIRTY) + if (pg_atomic_read_u64(&buf_hdr->state) & BM_DIRTY) { if (BufferIsLocal(buf)) FlushLocalBuffer(buf_hdr, NULL); @@ -572,7 +572,7 @@ buffer_call_terminate_io(PG_FUNCTION_ARGS) bool io_error = PG_GETARG_BOOL(3); bool release_aio = PG_GETARG_BOOL(4); bool clear_dirty = false; - uint32 set_flag_bits = 0; + uint64 set_flag_bits = 0; if (io_error) set_flag_bits |= BM_IO_ERROR; -- 2.48.1.76.g4e746b1a31.dirty --c6wqr3sg4llxfu2u Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v11-0002-bufmgr-Implement-buffer-content-locks-independen.patch" ^ permalink raw reply [nested|flat] 22+ messages in thread
* Re: First draft of PG 19 release notes @ 2026-07-02 22:12 Andreas Karlsson <[email protected]> 2026-07-02 22:16 ` Re: First draft of PG 19 release notes Andreas Karlsson <[email protected]> 2026-07-02 22:35 ` Re: First draft of PG 19 release notes Jacob Champion <[email protected]> 0 siblings, 2 replies; 22+ messages in thread From: Andreas Karlsson @ 2026-07-02 22:12 UTC (permalink / raw) To: Bruce Momjian <[email protected]>; PostgreSQL-development <[email protected]>; +Cc: Jacob Champion <[email protected]> Hi, I noticed that some of the OAuth-realted items ended up under the wrong sections. See my suggestions below and the attached patch. Jacob, do you have any opinion here? = Add a new OAUTH flow hook PQAUTHDATA_OAUTH_BEARER_TOKEN_V2 Should go under "libpq" = Allow custom OAUTH validators to register custom pg_hba.conf authentication options Should go under "Server Configuration". It could arguably go under "Source Code" too but that seems less useful to the reader. = Allow OAUTH validators to supply failure details Should go under "Source Code" as this is not user facing. -- Andreas Karlsson Percona Attachments: [text/x-patch] v1-0001-Move-some-OAuth-related-release-note-items-to-the.patch (4.0K, ../../[email protected]/2-v1-0001-Move-some-OAuth-related-release-note-items-to-the.patch) download | inline diff: From 73684c2832cd652fd055924ff0f3199862714efb Mon Sep 17 00:00:00 2001 From: Andreas Karlsson <[email protected]> Date: Fri, 3 Jul 2026 00:01:11 +0200 Subject: [PATCH v1] Move some OAuth related release note items to the right section The two validator items belong under Server Configuration and Source Code respectively and the one about PQAUTHDATA_OAUTH_BEARER_TOKEN_V2 belongs to libpq. --- doc/src/sgml/release-19.sgml | 42 ++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/doc/src/sgml/release-19.sgml b/doc/src/sgml/release-19.sgml index d8d3758d5ba..194aee056e3 100644 --- a/doc/src/sgml/release-19.sgml +++ b/doc/src/sgml/release-19.sgml @@ -1341,20 +1341,29 @@ New configuration file <link linkend="guc-hosts-file"><filename>PGDATA/pg_hosts. <!-- Author: Jacob Champion <[email protected]> -2026-03-06 [e982331b5] libpq: Introduce PQAUTHDATA_OAUTH_BEARER_TOKEN_V2 +2026-04-07 [b977bd308] oauth: Allow validators to register custom HBA options +--> + +<listitem> +<para> +Allow custom <acronym>OAUTH</acronym> validators to register custom <link linkend="auth-pg-hba-conf"><filename>pg_hba.conf</filename></link> authentication options (Jacob Champion) +<ulink url="&commit_baseurl;b977bd308">§</ulink> +</para> +</listitem> + +<!-- Author: Jacob Champion <[email protected]> -2026-03-31 [0af4d402c] libpq: Poison the v2 part of a v1 Bearer request +2026-04-03 [d438a3659] oauth: Let validators provide failure DETAILs --> <listitem> <para> -Add a new <acronym>OAUTH</acronym> flow hook <link linkend="libpq-oauth-authdata-oauth-bearer-token-v2"><literal>PQAUTHDATA_OAUTH_BEARER_TOKEN_V2</literal></link> (Jacob Champion) -<ulink url="&commit_baseurl;e982331b5">§</ulink> -<ulink url="&commit_baseurl;0af4d402c">§</ulink> +Allow <acronym>OAUTH</acronym> validators to supply failure details (Jacob Champion) +<ulink url="&commit_baseurl;d438a3659">§</ulink> </para> <para> -This is an improved version of <link linkend="libpq-oauth-authdata-oauth-bearer-token"><literal>PQAUTHDATA_OAUTH_BEARER_TOKEN</literal></link> by adding the issuer identifier and error message specification. +This is done by setting the <link linkend="oauth-validator-callback-validate"><structname>ValidatorModuleResult</structname></link> structure member error_detail. </para> </listitem> @@ -2355,29 +2364,20 @@ This can also be set via the <link linkend="libpq-envars"><envar>PGOAUTHCAFILE</ <!-- Author: Jacob Champion <[email protected]> -2026-04-07 [b977bd308] oauth: Allow validators to register custom HBA options ---> - -<listitem> -<para> -Allow custom <acronym>OAUTH</acronym> validators to register custom <link linkend="auth-pg-hba-conf"><filename>pg_hba.conf</filename></link> authentication options (Jacob Champion) -<ulink url="&commit_baseurl;b977bd308">§</ulink> -</para> -</listitem> - -<!-- +2026-03-06 [e982331b5] libpq: Introduce PQAUTHDATA_OAUTH_BEARER_TOKEN_V2 Author: Jacob Champion <[email protected]> -2026-04-03 [d438a3659] oauth: Let validators provide failure DETAILs +2026-03-31 [0af4d402c] libpq: Poison the v2 part of a v1 Bearer request --> <listitem> <para> -Allow <acronym>OAUTH</acronym> validators to supply failure details (Jacob Champion) -<ulink url="&commit_baseurl;d438a3659">§</ulink> +Add a new <acronym>OAUTH</acronym> flow hook <link linkend="libpq-oauth-authdata-oauth-bearer-token-v2"><literal>PQAUTHDATA_OAUTH_BEARER_TOKEN_V2</literal></link> (Jacob Champion) +<ulink url="&commit_baseurl;e982331b5">§</ulink> +<ulink url="&commit_baseurl;0af4d402c">§</ulink> </para> <para> -This is done by setting the <link linkend="oauth-validator-callback-validate"><structname>ValidatorModuleResult</structname></link> structure member error_detail. +This is an improved version of <link linkend="libpq-oauth-authdata-oauth-bearer-token"><literal>PQAUTHDATA_OAUTH_BEARER_TOKEN</literal></link> by adding the issuer identifier and error message specification. </para> </listitem> -- 2.43.0 ^ permalink raw reply [nested|flat] 22+ messages in thread
* Re: First draft of PG 19 release notes 2026-07-02 22:12 Re: First draft of PG 19 release notes Andreas Karlsson <[email protected]> @ 2026-07-02 22:16 ` Andreas Karlsson <[email protected]> 1 sibling, 0 replies; 22+ messages in thread From: Andreas Karlsson @ 2026-07-02 22:16 UTC (permalink / raw) To: Bruce Momjian <[email protected]>; PostgreSQL-development <[email protected]>; +Cc: Jacob Champion <[email protected]> On 7/3/26 00:12, Andreas Karlsson wrote: > I noticed that some of the OAuth-realted items ended up under the wrong > sections. See my suggestions below and the attached patch. Ops, right patch attached now. -- Andreas Karlsson Percona Attachments: [text/x-patch] v2-0001-Move-some-OAuth-related-release-note-items-to-the.patch (4.4K, ../../[email protected]/2-v2-0001-Move-some-OAuth-related-release-note-items-to-the.patch) download | inline diff: From ee68aa7653f2e7a0d31ec49684b66a8b9275e5d9 Mon Sep 17 00:00:00 2001 From: Andreas Karlsson <[email protected]> Date: Fri, 3 Jul 2026 00:01:11 +0200 Subject: [PATCH v2] Move some OAuth related release note items to the right section The two validator items belong under Server Configuration and Source Code respectively and the one about PQAUTHDATA_OAUTH_BEARER_TOKEN_V2 belongs to libpq. --- doc/src/sgml/release-19.sgml | 44 ++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/doc/src/sgml/release-19.sgml b/doc/src/sgml/release-19.sgml index d8d3758d5ba..5bb4c2ce15d 100644 --- a/doc/src/sgml/release-19.sgml +++ b/doc/src/sgml/release-19.sgml @@ -1341,20 +1341,18 @@ New configuration file <link linkend="guc-hosts-file"><filename>PGDATA/pg_hosts. <!-- Author: Jacob Champion <[email protected]> -2026-03-06 [e982331b5] libpq: Introduce PQAUTHDATA_OAUTH_BEARER_TOKEN_V2 -Author: Jacob Champion <[email protected]> -2026-03-31 [0af4d402c] libpq: Poison the v2 part of a v1 Bearer request +2026-04-07 [b977bd308] oauth: Allow validators to register custom HBA options --> <listitem> <para> -Add a new <acronym>OAUTH</acronym> flow hook <link linkend="libpq-oauth-authdata-oauth-bearer-token-v2"><literal>PQAUTHDATA_OAUTH_BEARER_TOKEN_V2</literal></link> (Jacob Champion) -<ulink url="&commit_baseurl;e982331b5">§</ulink> -<ulink url="&commit_baseurl;0af4d402c">§</ulink> +Allow custom <acronym>OAUTH</acronym> validators to register custom <link linkend="auth-pg-hba-conf"><filename>pg_hba.conf</filename></link> authentication options (Jacob Champion) +<ulink url="&commit_baseurl;b977bd308">§</ulink> </para> +</listitem> <para> -This is an improved version of <link linkend="libpq-oauth-authdata-oauth-bearer-token"><literal>PQAUTHDATA_OAUTH_BEARER_TOKEN</literal></link> by adding the issuer identifier and error message specification. +This is done by setting the <link linkend="oauth-validator-callback-validate"><structname>ValidatorModuleResult</structname></link> structure member error_detail. </para> </listitem> @@ -2355,29 +2353,20 @@ This can also be set via the <link linkend="libpq-envars"><envar>PGOAUTHCAFILE</ <!-- Author: Jacob Champion <[email protected]> -2026-04-07 [b977bd308] oauth: Allow validators to register custom HBA options ---> - -<listitem> -<para> -Allow custom <acronym>OAUTH</acronym> validators to register custom <link linkend="auth-pg-hba-conf"><filename>pg_hba.conf</filename></link> authentication options (Jacob Champion) -<ulink url="&commit_baseurl;b977bd308">§</ulink> -</para> -</listitem> - -<!-- +2026-03-06 [e982331b5] libpq: Introduce PQAUTHDATA_OAUTH_BEARER_TOKEN_V2 Author: Jacob Champion <[email protected]> -2026-04-03 [d438a3659] oauth: Let validators provide failure DETAILs +2026-03-31 [0af4d402c] libpq: Poison the v2 part of a v1 Bearer request --> <listitem> <para> -Allow <acronym>OAUTH</acronym> validators to supply failure details (Jacob Champion) -<ulink url="&commit_baseurl;d438a3659">§</ulink> +Add a new <acronym>OAUTH</acronym> flow hook <link linkend="libpq-oauth-authdata-oauth-bearer-token-v2"><literal>PQAUTHDATA_OAUTH_BEARER_TOKEN_V2</literal></link> (Jacob Champion) +<ulink url="&commit_baseurl;e982331b5">§</ulink> +<ulink url="&commit_baseurl;0af4d402c">§</ulink> </para> <para> -This is done by setting the <link linkend="oauth-validator-callback-validate"><structname>ValidatorModuleResult</structname></link> structure member error_detail. +This is an improved version of <link linkend="libpq-oauth-authdata-oauth-bearer-token"><literal>PQAUTHDATA_OAUTH_BEARER_TOKEN</literal></link> by adding the issuer identifier and error message specification. </para> </listitem> @@ -3016,6 +3005,17 @@ Author: Heikki Linnakangas <[email protected]> 2026-04-06 [283e823f9] Introduce a new mechanism for registering shared memory --> +<!-- +Author: Jacob Champion <[email protected]> +2026-04-03 [d438a3659] oauth: Let validators provide failure DETAILs +--> + +<listitem> +<para> +Allow <acronym>OAUTH</acronym> validators to supply failure details (Jacob Champion) +<ulink url="&commit_baseurl;d438a3659">§</ulink> +</para> + <listitem> <para> Add simplified and improved shared memory registration function <link linkend="xfunc-shared-addin-at-startup"><function>ShmemRequestStruct()</function></link> (Heikki Linnakangas, Ashutosh Bapat) -- 2.43.0 ^ permalink raw reply [nested|flat] 22+ messages in thread
* Re: First draft of PG 19 release notes 2026-07-02 22:12 Re: First draft of PG 19 release notes Andreas Karlsson <[email protected]> @ 2026-07-02 22:35 ` Jacob Champion <[email protected]> 1 sibling, 0 replies; 22+ messages in thread From: Jacob Champion @ 2026-07-02 22:35 UTC (permalink / raw) To: Andreas Karlsson <[email protected]>; +Cc: Bruce Momjian <[email protected]>; PostgreSQL-development <[email protected]> On Thu, Jul 2, 2026 at 3:12 PM Andreas Karlsson <[email protected]> wrote: > Jacob, do you have any opinion here? I've got a TODO to edit the feature docs that I haven't been able to check off yet. But no objections to your proposed moves at the moment (they might need to move again when I really sit down and stare at them). Thanks! --Jacob ^ permalink raw reply [nested|flat] 22+ messages in thread
end of thread, other threads:[~2026-07-02 22:35 UTC | newest] Thread overview: 22+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2019-06-28 08:03 [PATCH 2/5] Benchmark extension and required core change Kyotaro Horiguchi <[email protected]> 2023-08-31 14:38 [PATCH v9 2/4] make common enum for sync methods Nathan Bossart <[email protected]> 2023-08-31 14:38 [PATCH v9 2/4] make common enum for sync methods Nathan Bossart <[email protected]> 2023-08-31 14:38 [PATCH v9 2/4] make common enum for sync methods Nathan Bossart <[email protected]> 2023-08-31 14:38 [PATCH v8 2/4] make common enum for sync methods Nathan Bossart <[email protected]> 2023-08-31 14:38 [PATCH v8 2/4] make common enum for sync methods Nathan Bossart <[email protected]> 2023-08-31 14:38 [PATCH v9 2/4] make common enum for sync methods Nathan Bossart <[email protected]> 2023-08-31 14:38 [PATCH v9 2/4] make common enum for sync methods Nathan Bossart <[email protected]> 2023-11-08 06:57 [PATCH v11 5/7] Row pattern recognition patch (docs). Tatsuo Ishii <[email protected]> 2025-11-06 00:22 [PATCH v6 04/14] bufmgr: Change BufferDesc.state to be a 64bit atomic Andres Freund <[email protected]> 2025-11-06 00:22 [PATCH v6 04/14] bufmgr: Change BufferDesc.state to be a 64bit atomic Andres Freund <[email protected]> 2025-12-02 23:46 [PATCH v7 11/15] bufmgr: Change BufferDesc.state to be a 64bit atomic Andres Freund <[email protected]> 2025-12-18 23:28 [PATCH v8 06/10] bufmgr: Change BufferDesc.state to be a 64bit atomic Andres Freund <[email protected]> 2026-01-07 22:26 [PATCH v9 06/10] bufmgr: Change BufferDesc.state to be a 64bit atomic Andres Freund <[email protected]> 2026-01-07 22:26 [PATCH v10 3/8] bufmgr: Change BufferDesc.state to be a 64-bit atomic Andres Freund <[email protected]> 2026-01-07 22:26 [PATCH v9 06/10] bufmgr: Change BufferDesc.state to be a 64bit atomic Andres Freund <[email protected]> 2026-01-07 22:26 [PATCH v10 3/8] bufmgr: Change BufferDesc.state to be a 64-bit atomic Andres Freund <[email protected]> 2026-01-14 01:10 [PATCH v11 1/7] bufmgr: Change BufferDesc.state to be a 64-bit atomic Andres Freund <[email protected]> 2026-01-14 01:10 [PATCH v11 1/7] bufmgr: Change BufferDesc.state to be a 64-bit atomic Andres Freund <[email protected]> 2026-07-02 22:12 Re: First draft of PG 19 release notes Andreas Karlsson <[email protected]> 2026-07-02 22:16 ` Re: First draft of PG 19 release notes Andreas Karlsson <[email protected]> 2026-07-02 22:35 ` Re: First draft of PG 19 release notes Jacob Champion <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox