public inbox for [email protected]  
help / color / mirror / Atom feed
[PATCH 6/8] Add default_toast_compression GUC
2+ messages / 2 participants
[nested] [flat]

* [PATCH 6/8] Add default_toast_compression GUC
@ 2021-03-10 08:35 Dilip Kumar <[email protected]>
  0 siblings, 0 replies; 2+ messages in thread

From: Dilip Kumar @ 2021-03-10 08:35 UTC (permalink / raw)

Justin Pryzby and Dilip Kumar
---
 src/backend/access/common/toast_compression.c | 46 +++++++++++++++++++
 src/backend/access/common/tupdesc.c           |  2 +-
 src/backend/bootstrap/bootstrap.c             |  2 +-
 src/backend/commands/tablecmds.c              |  8 ++--
 src/backend/utils/misc/guc.c                  | 12 +++++
 src/backend/utils/misc/postgresql.conf.sample |  1 +
 src/include/access/toast_compression.h        | 22 ++++++++-
 src/test/regress/expected/compression.out     | 16 +++++++
 src/test/regress/expected/compression_1.out   | 19 ++++++++
 src/test/regress/sql/compression.sql          |  8 ++++
 10 files changed, 128 insertions(+), 8 deletions(-)

diff --git a/src/backend/access/common/toast_compression.c b/src/backend/access/common/toast_compression.c
index db4911ce43..27fe47b201 100644
--- a/src/backend/access/common/toast_compression.c
+++ b/src/backend/access/common/toast_compression.c
@@ -55,6 +55,9 @@ const CompressionRoutine toast_compression[] =
 	}
 };
 
+/* Compile-time default */
+char	*default_toast_compression = DEFAULT_TOAST_COMPRESSION;
+
 /*
  * pglz_cmcompress - compression routine for pglz compression method
  *
@@ -306,3 +309,46 @@ GetCompressionRoutines(char method)
 {
 	return &toast_compression[CompressionMethodToId(method)];
 }
+
+/* check_hook: validate new default_toast_compression */
+bool
+check_default_toast_compression(char **newval, void **extra, GucSource source)
+{
+	if (**newval == '\0')
+	{
+		GUC_check_errdetail("%s cannot be empty.",
+							"default_toast_compression");
+		return false;
+	}
+
+	if (strlen(*newval) >= NAMEDATALEN)
+	{
+		GUC_check_errdetail("%s is too long (maximum %d characters).",
+							"default_toast_compression", NAMEDATALEN - 1);
+		return false;
+	}
+
+	if (!CompressionMethodIsValid(CompressionNameToMethod(*newval)))
+	{
+		/*
+		 * When source == PGC_S_TEST, don't throw a hard error for a
+		 * nonexistent compression method, only a NOTICE. See comments in
+		 * guc.h.
+		 */
+		if (source == PGC_S_TEST)
+		{
+			ereport(NOTICE,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+						errmsg("compression method \"%s\" does not exist",
+							*newval)));
+		}
+		else
+		{
+			GUC_check_errdetail("Compression method \"%s\" does not exist.",
+								*newval);
+			return false;
+		}
+	}
+
+	return true;
+}
diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index a66d1113db..362a371a6c 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -668,7 +668,7 @@ TupleDescInitEntry(TupleDesc desc,
 	att->attcollation = typeForm->typcollation;
 
 	if (IsStorageCompressible(typeForm->typstorage))
-		att->attcompression = DefaultCompressionMethod;
+		att->attcompression = GetDefaultToastCompression();
 	else
 		att->attcompression = InvalidCompressionMethod;
 
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index af0c0aa77e..9be0841d08 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -733,7 +733,7 @@ DefineAttr(char *name, char *type, int attnum, int nullness)
 	attrtypes[attnum]->atttypmod = -1;
 	attrtypes[attnum]->attislocal = true;
 	if (IsStorageCompressible(attrtypes[attnum]->attstorage))
-		attrtypes[attnum]->attcompression = DefaultCompressionMethod;
+		attrtypes[attnum]->attcompression = GetDefaultToastCompression();
 	else
 		attrtypes[attnum]->attcompression = InvalidCompressionMethod;
 
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index e20dd5f63c..a0d2af0cde 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -11971,7 +11971,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 		if (!IsStorageCompressible(tform->typstorage))
 			attTup->attcompression = InvalidCompressionMethod;
 		else if (!CompressionMethodIsValid(attTup->attcompression))
-			attTup->attcompression = DefaultCompressionMethod;
+			attTup->attcompression = GetDefaultToastCompression();
 	}
 	else
 		attTup->attcompression = InvalidCompressionMethod;
@@ -17847,9 +17847,9 @@ GetAttributeCompression(Form_pg_attribute att, char *compression)
 
 	/* fallback to default compression if it's not specified */
 	if (compression == NULL)
-		return DefaultCompressionMethod;
-
-	cmethod = CompressionNameToMethod(compression);
+		cmethod = GetDefaultToastCompression();
+	else
+		cmethod = CompressionNameToMethod(compression);
 
 	return cmethod;
 }
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 953837085f..e59ed5b214 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -33,6 +33,7 @@
 #include "access/gin.h"
 #include "access/rmgr.h"
 #include "access/tableam.h"
+#include "access/toast_compression.h"
 #include "access/transam.h"
 #include "access/twophase.h"
 #include "access/xact.h"
@@ -3915,6 +3916,17 @@ static struct config_string ConfigureNamesString[] =
 		check_default_table_access_method, NULL, NULL
 	},
 
+	{
+		{"default_toast_compression", PGC_USERSET, CLIENT_CONN_STATEMENT,
+			gettext_noop("Sets the default compression for new columns."),
+			NULL,
+			GUC_IS_NAME
+		},
+		&default_toast_compression,
+		DEFAULT_TOAST_COMPRESSION,
+		check_default_toast_compression, NULL, NULL
+	},
+
 	{
 		{"default_tablespace", PGC_USERSET, CLIENT_CONN_STATEMENT,
 			gettext_noop("Sets the default tablespace to create tables and indexes in."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index f46c2dd7a8..7d7a433dcc 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -659,6 +659,7 @@
 #temp_tablespaces = ''			# a list of tablespace names, '' uses
 					# only default tablespace
 #default_table_access_method = 'heap'
+#default_toast_compression = 'pglz'	# 'pglz' or 'lz4'
 #check_function_bodies = on
 #default_transaction_isolation = 'read committed'
 #default_transaction_read_only = off
diff --git a/src/include/access/toast_compression.h b/src/include/access/toast_compression.h
index 38800cb97a..e9d9ce5634 100644
--- a/src/include/access/toast_compression.h
+++ b/src/include/access/toast_compression.h
@@ -15,6 +15,14 @@
 
 #include "postgres.h"
 
+#include "utils/guc.h"
+
+/* default compression method if not specified. */
+#define DEFAULT_TOAST_COMPRESSION	"pglz"
+
+/* GUCs */
+extern char *default_toast_compression;
+
 /*
  * Built-in compression methods.  pg_attribute will store this in the
  * attcompression column.
@@ -36,8 +44,6 @@ typedef enum CompressionId
 	LZ4_COMPRESSION_ID = 1
 } CompressionId;
 
-/* use default compression method if it is not specified. */
-#define DefaultCompressionMethod PGLZ_COMPRESSION
 #define IsValidCompression(cm)  ((cm) != InvalidCompressionMethod)
 
 #define IsStorageCompressible(storage) ((storage) != TYPSTORAGE_PLAIN && \
@@ -67,6 +73,8 @@ typedef struct CompressionRoutine
 
 extern char CompressionNameToMethod(char *compression);
 extern const CompressionRoutine *GetCompressionRoutines(char method);
+extern bool check_default_toast_compression(char **newval, void **extra,
+											GucSource source);
 
 /*
  * CompressionMethodToId - Convert compression method to compression id.
@@ -115,5 +123,15 @@ GetCompressionMethodName(char method)
 	return GetCompressionRoutines(method)->cmname;
 }
 
+/*
+ * GetDefaultToastCompression -- get the current toast compression
+ *
+ * This exists to hide the use of the default_toast_compression GUC variable.
+ */
+static inline char
+GetDefaultToastCompression(void)
+{
+	return CompressionNameToMethod(default_toast_compression);
+}
 
 #endif							/* TOAST_COMPRESSION_H */
diff --git a/src/test/regress/expected/compression.out b/src/test/regress/expected/compression.out
index 6981d580dc..9ddffc8b18 100644
--- a/src/test/regress/expected/compression.out
+++ b/src/test/regress/expected/compression.out
@@ -231,6 +231,22 @@ CREATE TABLE cminh(f1 TEXT COMPRESSION lz4) INHERITS(cmdata);
 NOTICE:  merging column "f1" with inherited definition
 ERROR:  column "f1" has a compression method conflict
 DETAIL:  pglz versus lz4
+-- test default_toast_compression GUC
+SET default_toast_compression = '';
+ERROR:  invalid value for parameter "default_toast_compression": ""
+DETAIL:  default_toast_compression cannot be empty.
+SET default_toast_compression = 'I do not exist compression';
+ERROR:  invalid value for parameter "default_toast_compression": "I do not exist compression"
+DETAIL:  Compression method "I do not exist compression" does not exist.
+SET default_toast_compression = 'lz4';
+DROP TABLE cmdata2;
+CREATE TABLE cmdata2 (f1 text);
+\d+ cmdata2
+                                        Table "public.cmdata2"
+ Column | Type | Collation | Nullable | Default | Storage  | Compression | Stats target | Description 
+--------+------+-----------+----------+---------+----------+-------------+--------------+-------------
+ f1     | text |           |          |         | extended | lz4         |              | 
+
 -- check data is ok
 SELECT length(f1) FROM cmdata;
  length 
diff --git a/src/test/regress/expected/compression_1.out b/src/test/regress/expected/compression_1.out
index 893c18c7fa..03a7f46554 100644
--- a/src/test/regress/expected/compression_1.out
+++ b/src/test/regress/expected/compression_1.out
@@ -237,6 +237,25 @@ CREATE TABLE cminh(f1 TEXT COMPRESSION lz4) INHERITS(cmdata);
 NOTICE:  merging column "f1" with inherited definition
 ERROR:  column "f1" has a compression method conflict
 DETAIL:  pglz versus lz4
+-- test default_toast_compression GUC
+SET default_toast_compression = '';
+ERROR:  invalid value for parameter "default_toast_compression": ""
+DETAIL:  default_toast_compression cannot be empty.
+SET default_toast_compression = 'I do not exist compression';
+ERROR:  invalid value for parameter "default_toast_compression": "I do not exist compression"
+DETAIL:  Compression method "I do not exist compression" does not exist.
+SET default_toast_compression = 'lz4';
+ERROR:  unsupported LZ4 compression method
+DETAIL:  This functionality requires the server to be built with lz4 support.
+HINT:  You need to rebuild PostgreSQL using --with-lz4.
+DROP TABLE cmdata2;
+CREATE TABLE cmdata2 (f1 text);
+\d+ cmdata2
+                                        Table "public.cmdata2"
+ Column | Type | Collation | Nullable | Default | Storage  | Compression | Stats target | Description 
+--------+------+-----------+----------+---------+----------+-------------+--------------+-------------
+ f1     | text |           |          |         | extended | pglz        |              | 
+
 -- check data is ok
 SELECT length(f1) FROM cmdata;
  length 
diff --git a/src/test/regress/sql/compression.sql b/src/test/regress/sql/compression.sql
index b085c9fbd9..6c9b24f1f7 100644
--- a/src/test/regress/sql/compression.sql
+++ b/src/test/regress/sql/compression.sql
@@ -103,6 +103,14 @@ SELECT pg_column_compression(f1) FROM cmpart;
 CREATE TABLE cminh() INHERITS(cmdata, cmdata1);
 CREATE TABLE cminh(f1 TEXT COMPRESSION lz4) INHERITS(cmdata);
 
+-- test default_toast_compression GUC
+SET default_toast_compression = '';
+SET default_toast_compression = 'I do not exist compression';
+SET default_toast_compression = 'lz4';
+DROP TABLE cmdata2;
+CREATE TABLE cmdata2 (f1 text);
+\d+ cmdata2
+
 -- check data is ok
 SELECT length(f1) FROM cmdata;
 SELECT length(f1) FROM cmdata1;
-- 
2.17.0


--C94crkcyjafcjHxo
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
 filename="0007-Alter-table-set-compression.patch"



^ permalink  raw  reply  [nested|flat] 2+ messages in thread

* [PATCH v35 3/5] Move conversion of a "historic" to MVCC snapshot to a separate function.
@ 2026-02-16 19:49 Antonin Houska <[email protected]>
  0 siblings, 0 replies; 2+ messages in thread

From: Antonin Houska @ 2026-02-16 19:49 UTC (permalink / raw)

The conversion is now handled by SnapBuildMVCCFromHistoric(). REPACK
CONCURRENTLY will also need it.
---
 src/backend/replication/logical/snapbuild.c | 59 +++++++++++++++++----
 src/backend/utils/time/snapmgr.c            |  3 +-
 src/include/replication/snapbuild.h         |  1 +
 src/include/utils/snapmgr.h                 |  1 +
 4 files changed, 52 insertions(+), 12 deletions(-)

diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index 7f79621b57e..a738ad8a864 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -440,10 +440,7 @@ Snapshot
 SnapBuildInitialSnapshot(SnapBuild *builder)
 {
 	Snapshot	snap;
-	TransactionId xid;
 	TransactionId safeXid;
-	TransactionId *newxip;
-	int			newxcnt = 0;
 
 	Assert(XactIsoLevel == XACT_REPEATABLE_READ);
 	Assert(builder->building_full_snapshot);
@@ -485,7 +482,35 @@ SnapBuildInitialSnapshot(SnapBuild *builder)
 
 	MyProc->xmin = snap->xmin;
 
-	/* allocate in transaction context */
+	/* Convert the historic snapshot to MVCC snapshot. */
+	return SnapBuildMVCCFromHistoric(snap, true);
+}
+
+/*
+ * Turn a historic MVCC snapshot into an ordinary MVCC snapshot.
+ *
+ * Unlike a regular (non-historic) MVCC snapshot, the 'xip' array of this
+ * snapshot contains not only running main transactions, but also their
+ * subtransactions. On the other hand, 'subxip' will usually be empty. This
+ * difference does not affect the result of XidInMVCCSnapshot() because it
+ * searches both in 'xip' and 'subxip'.
+ *
+ * Pass true for 'in_place' if you don't care about modifying the source
+ * snapshot. If you need a new instance, and one that was allocated as a
+ * single chunk of memory, pass false.
+ */
+Snapshot
+SnapBuildMVCCFromHistoric(Snapshot snapshot, bool in_place)
+{
+	TransactionId xid;
+	TransactionId *oldxip = snapshot->xip;
+	uint32		oldxcnt = snapshot->xcnt;
+	TransactionId *newxip;
+	int			newxcnt = 0;
+	Snapshot	result;
+
+	Assert(snapshot->snapshot_type == SNAPSHOT_HISTORIC_MVCC);
+
 	newxip = palloc_array(TransactionId, GetMaxSnapshotXidCount());
 
 	/*
@@ -494,7 +519,7 @@ SnapBuildInitialSnapshot(SnapBuild *builder)
 	 * classical snapshot by marking all non-committed transactions as
 	 * in-progress. This can be expensive.
 	 */
-	for (xid = snap->xmin; NormalTransactionIdPrecedes(xid, snap->xmax);)
+	for (xid = snapshot->xmin; NormalTransactionIdPrecedes(xid, snapshot->xmax);)
 	{
 		void	   *test;
 
@@ -502,7 +527,7 @@ SnapBuildInitialSnapshot(SnapBuild *builder)
 		 * Check whether transaction committed using the decoding snapshot
 		 * meaning of ->xip.
 		 */
-		test = bsearch(&xid, snap->xip, snap->xcnt,
+		test = bsearch(&xid, snapshot->xip, snapshot->xcnt,
 					   sizeof(TransactionId), xidComparator);
 
 		if (test == NULL)
@@ -519,11 +544,25 @@ SnapBuildInitialSnapshot(SnapBuild *builder)
 	}
 
 	/* adjust remaining snapshot fields as needed */
-	snap->snapshot_type = SNAPSHOT_MVCC;
-	snap->xcnt = newxcnt;
-	snap->xip = newxip;
+	snapshot->xcnt = newxcnt;
+	snapshot->xip = newxip;
 
-	return snap;
+	if (in_place)
+		result = snapshot;
+	else
+	{
+		result = CopySnapshot(snapshot);
+
+		/* Restore the original values so the source is intact. */
+		snapshot->xip = oldxip;
+		snapshot->xcnt = oldxcnt;
+
+		/* newxip has been copied */
+		pfree(newxip);
+	}
+	result->snapshot_type = SNAPSHOT_MVCC;
+
+	return result;
 }
 
 /*
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index 2e6197f5f35..3af1b366adf 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -213,7 +213,6 @@ typedef struct ExportedSnapshot
 static List *exportedSnapshots = NIL;
 
 /* Prototypes for local functions */
-static Snapshot CopySnapshot(Snapshot snapshot);
 static void UnregisterSnapshotNoOwner(Snapshot snapshot);
 static void FreeSnapshot(Snapshot snapshot);
 static void SnapshotResetXmin(void);
@@ -604,7 +603,7 @@ SetTransactionSnapshot(Snapshot sourcesnap, VirtualTransactionId *sourcevxid,
  * The copy is palloc'd in TopTransactionContext and has initial refcounts set
  * to 0.  The returned snapshot has the copied flag set.
  */
-static Snapshot
+Snapshot
 CopySnapshot(Snapshot snapshot)
 {
 	Snapshot	newsnap;
diff --git a/src/include/replication/snapbuild.h b/src/include/replication/snapbuild.h
index ccded021433..34383dea776 100644
--- a/src/include/replication/snapbuild.h
+++ b/src/include/replication/snapbuild.h
@@ -73,6 +73,7 @@ extern void FreeSnapshotBuilder(SnapBuild *builder);
 extern void SnapBuildSnapDecRefcount(Snapshot snap);
 
 extern Snapshot SnapBuildInitialSnapshot(SnapBuild *builder);
+extern Snapshot SnapBuildMVCCFromHistoric(Snapshot snapshot, bool in_place);
 extern const char *SnapBuildExportSnapshot(SnapBuild *builder);
 extern void SnapBuildClearExportedSnapshot(void);
 extern void SnapBuildResetExportedSnapshotState(void);
diff --git a/src/include/utils/snapmgr.h b/src/include/utils/snapmgr.h
index b8c01a291a1..de824945f0b 100644
--- a/src/include/utils/snapmgr.h
+++ b/src/include/utils/snapmgr.h
@@ -63,6 +63,7 @@ extern Snapshot GetTransactionSnapshot(void);
 extern Snapshot GetLatestSnapshot(void);
 extern void SnapshotSetCommandId(CommandId curcid);
 
+extern Snapshot CopySnapshot(Snapshot snapshot);
 extern Snapshot GetCatalogSnapshot(Oid relid);
 extern Snapshot GetNonHistoricCatalogSnapshot(Oid relid);
 extern void InvalidateCatalogSnapshot(void);
-- 
2.47.3


--kmtyk4ln3767qrma
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
	filename="v35-0004-Add-CONCURRENTLY-option-to-REPACK-command.patch"



^ permalink  raw  reply  [nested|flat] 2+ messages in thread


end of thread, other threads:[~2026-02-16 19:49 UTC | newest]

Thread overview: 2+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2021-03-10 08:35 [PATCH 6/8] Add default_toast_compression GUC Dilip Kumar <[email protected]>
2026-02-16 19:49 [PATCH v35 3/5] Move conversion of a "historic" to MVCC snapshot to a separate function. Antonin Houska <[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