Hope this patch will be usefull/ On Mon, Sep 18, 2023 at 5:47 PM Sergey Sergey <ioxg...@gmail.com> wrote:
> While replaying our production workload we have found Postgres spending a > lot of time inside TimescaleDB planner. The planner itself need an > information about whether a table involved is a TimescaleDB hypertable. So > planner need an access to TimescaleDB internal metainformation tables. This > planner access become extremely slow when you have a lot of tables involved > and you are beyond fast-path lock limit > > This humble example makes only 2330 tps on REL_15_STABLE but 27041tps on > patched version with 64 slots for fast-path locks. > > \set bid random(1,1000) > > BEGIN; > select bbalance from pgbench_branches where bid = :bid > UNION > select bbalance from pgbench_branches2 where bid = :bid > UNION > select bbalance from pgbench_branches3 where bid = :bid > UNION > select bbalance from pgbench_branches4 where bid = :bid > UNION > select bbalance from pgbench_branches5 where bid = :bid > UNION > select bbalance from pgbench_branches6 where bid = :bid > UNION > select bbalance from pgbench_branches7 where bid = :bid > UNION > select bbalance from pgbench_branches8 where bid = :bid > UNION > select bbalance from pgbench_branches9 where bid = :bid > UNION > select bbalance from pgbench_branches10 where bid = :bid > UNION > select bbalance from pgbench_branches11 where bid = :bid > UNION > select bbalance from pgbench_branches12 where bid = :bid > UNION > select bbalance from pgbench_branches13 where bid = :bid > UNION > select bbalance from pgbench_branches14 where bid = :bid > UNION > select bbalance from pgbench_branches15 where bid = :bid > UNION > select bbalance from pgbench_branches16 where bid = :bid > UNION > select bbalance from pgbench_branches17 where bid = :bid > UNION > select bbalance from pgbench_branches18 where bid = :bid > UNION > select bbalance from pgbench_branches19 where bid = :bid > UNION > select bbalance from pgbench_branches20 where bid = :bid; > END; > > First i try to make the number of fast-path locks as a GUC parameter. But > it implies a lot of changes with PGPROC structure. Next I implement it as a > compile-time parameter. >
diff --git a/home/nikor/tmp/postgres/configure.ac b/configure.ac index c216ac4447..558e17273c 100644 --- a/home/nikor/tmp/postgres/configure.ac +++ b/configure.ac @@ -283,6 +283,23 @@ AC_DEFINE_UNQUOTED([BLCKSZ], ${BLCKSZ}, [ Changing BLCKSZ requires an initdb. ]) +# +# Fastlock size +# +AC_MSG_CHECKING([for fastlock size]) +PGAC_ARG_REQ(with, fastlocksize, [FASTLOCKSIZE], [set fastlock array size [16]], + [fastlocksize=$withval], + [fastlocksize=16]) +AC_MSG_RESULT([${fastlocksize}]) + +AC_DEFINE_UNQUOTED([FP_LOCK_SLOTS_PER_BACKEND], ${fastlocksize}, [ + Size of a fastlock slots. Large values can help when transaction + touch a lot of objects. + + Changes requires restart. + +]) + # # Relation segment size # diff --git a/home/nikor/tmp/postgres/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index 86fc5576af..81e0d5f839 100644 --- a/home/nikor/tmp/postgres/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -191,18 +191,18 @@ static bool IsRelationExtensionLockHeld PG_USED_FOR_ASSERTS_ONLY = false; #define FAST_PATH_LOCKNUMBER_OFFSET 1 #define FAST_PATH_MASK ((1 << FAST_PATH_BITS_PER_SLOT) - 1) #define FAST_PATH_GET_BITS(proc, n) \ - (((proc)->fpLockBits >> (FAST_PATH_BITS_PER_SLOT * n)) & FAST_PATH_MASK) + ((proc)->fpLockBits[n] & FAST_PATH_MASK) #define FAST_PATH_BIT_POSITION(n, l) \ (AssertMacro((l) >= FAST_PATH_LOCKNUMBER_OFFSET), \ AssertMacro((l) < FAST_PATH_BITS_PER_SLOT+FAST_PATH_LOCKNUMBER_OFFSET), \ AssertMacro((n) < FP_LOCK_SLOTS_PER_BACKEND), \ - ((l) - FAST_PATH_LOCKNUMBER_OFFSET + FAST_PATH_BITS_PER_SLOT * (n))) + ((l) - FAST_PATH_LOCKNUMBER_OFFSET )) #define FAST_PATH_SET_LOCKMODE(proc, n, l) \ - (proc)->fpLockBits |= UINT64CONST(1) << FAST_PATH_BIT_POSITION(n, l) + (proc)->fpLockBits[n] |= UINT64CONST(1) << FAST_PATH_BIT_POSITION(n, l) #define FAST_PATH_CLEAR_LOCKMODE(proc, n, l) \ - (proc)->fpLockBits &= ~(UINT64CONST(1) << FAST_PATH_BIT_POSITION(n, l)) + (proc)->fpLockBits[n] &= ~(UINT64CONST(1) << FAST_PATH_BIT_POSITION(n, l)) #define FAST_PATH_CHECK_LOCKMODE(proc, n, l) \ - ((proc)->fpLockBits & (UINT64CONST(1) << FAST_PATH_BIT_POSITION(n, l))) + ((proc)->fpLockBits[n] & (UINT64CONST(1) << FAST_PATH_BIT_POSITION(n, l))) /* * The fast-path lock mechanism is concerned only with relation locks on diff --git a/home/nikor/tmp/postgres/src/include/pg_config.h.in b/src/include/pg_config.h.in index d09e9f9a1c..c8fc4f9e3f 100644 --- a/home/nikor/tmp/postgres/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -62,6 +62,14 @@ # define gettimeofday(a,b) gettimeofday(a) #endif +/* Size of a fastlock array. + We allow a small number of "weak" relation locks (AccessShareLock, + RowShareLock, RowExclusiveLock) to be recorded in the PGPROC structure + rather than the main lock table. This eases contention on the lock + manager LWLocks. See storage/lmgr/README for additional details. +*/ +#undef FP_LOCK_SLOTS_PER_BACKEND + /* Define to 1 if you have the `append_history' function. */ #undef HAVE_APPEND_HISTORY diff --git a/home/nikor/tmp/postgres/src/include/storage/proc.h b/src/include/storage/proc.h index 2579e619eb..5303675a3a 100644 --- a/home/nikor/tmp/postgres/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -74,14 +74,6 @@ struct XidCache */ #define PROC_XMIN_FLAGS (PROC_IN_VACUUM | PROC_IN_SAFE_IC) -/* - * We allow a small number of "weak" relation locks (AccessShareLock, - * RowShareLock, RowExclusiveLock) to be recorded in the PGPROC structure - * rather than the main lock table. This eases contention on the lock - * manager LWLocks. See storage/lmgr/README for additional details. - */ -#define FP_LOCK_SLOTS_PER_BACKEND 16 - /* * An invalid pgprocno. Must be larger than the maximum number of PGPROC * structures we could possibly have. See comments for MAX_BACKENDS. @@ -282,7 +274,7 @@ struct PGPROC /* Lock manager data, recording fast-path locks taken by this backend. */ LWLock fpInfoLock; /* protects per-backend fast-path state */ - uint64 fpLockBits; /* lock modes held for each fast-path slot */ + uint8 fpLockBits[FP_LOCK_SLOTS_PER_BACKEND]; /* lock modes held for each fast-path slot */ Oid fpRelId[FP_LOCK_SLOTS_PER_BACKEND]; /* slots for rel oids */ bool fpVXIDLock; /* are we holding a fast-path VXID lock? */ LocalTransactionId fpLocalTransactionId; /* lxid for fast-path VXID diff --git a/home/nikor/tmp/postgres/configure b/./configure index 57607d79df..58228f42fa 100755 --- a/home/nikor/tmp/postgres/configure +++ b/./configure @@ -806,6 +806,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -845,6 +846,7 @@ enable_coverage enable_dtrace enable_tap_tests with_blocksize +with_fastlocksize with_segsize with_wal_blocksize with_CC @@ -950,6 +952,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1202,6 +1205,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1339,7 +1351,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1492,6 +1504,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -1555,6 +1568,8 @@ Optional Packages: --with-pgport=PORTNUM set default port number [5432] --with-blocksize=BLOCKSIZE set table block size in kB [8] + --with-fastlocksize=FASTLOCKSIZE + set fastlock array size [16] --with-segsize=SEGSIZE set table segment size in GB [1] --with-wal-blocksize=BLOCKSIZE set WAL block size in kB [8] @@ -3735,6 +3750,43 @@ cat >>confdefs.h <<_ACEOF _ACEOF +# +# Fastlock size +# +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fastlock size" >&5 +$as_echo_n "checking for fastlock size... " >&6; } + + + +# Check whether --with-fastlocksize was given. +if test "${with_fastlocksize+set}" = set; then : + withval=$with_fastlocksize; + case $withval in + yes) + as_fn_error $? "argument required for --with-fastlocksize option" "$LINENO" 5 + ;; + no) + as_fn_error $? "argument required for --with-fastlocksize option" "$LINENO" 5 + ;; + *) + fastlocksize=$withval + ;; + esac + +else + fastlocksize=16 +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${fastlocksize}" >&5 +$as_echo "${fastlocksize}" >&6; } + + +cat >>confdefs.h <<_ACEOF +#define FP_LOCK_SLOTS_PER_BACKEND ${fastlocksize} +_ACEOF + + # # Relation segment size # @@ -15780,7 +15832,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -15826,7 +15878,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -15850,7 +15902,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -15895,7 +15947,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -15919,7 +15971,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1];