0006-Serialize-and-restore-ParitionDesc-PartitionBound.patch
application/octet-stream
Filename: 0006-Serialize-and-restore-ParitionDesc-PartitionBound.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch 0006
Subject: Serialize and restore ParitionDesc/PartitionBound.
| File | + | − |
|---|---|---|
| src/backend/partitioning/partbounds.c | 238 | 0 |
| src/backend/partitioning/partdesc.c | 74 | 0 |
| src/include/partitioning/partbounds.h | 6 | 0 |
| src/include/partitioning/partdesc.h | 6 | 0 |
From 3e4e99a2cc23d0f03be3486ee6aae44c0d552157 Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Fri, 1 Feb 2019 13:16:40 -0500
Subject: [PATCH 6/6] Serialize and restore ParitionDesc/PartitionBound.
---
src/backend/partitioning/partbounds.c | 238 ++++++++++++++++++++++++++
src/backend/partitioning/partdesc.c | 74 ++++++++
src/include/partitioning/partbounds.h | 6 +
src/include/partitioning/partdesc.h | 6 +
4 files changed, 324 insertions(+)
diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c
index e71eb3793b..779cbd83f5 100644
--- a/src/backend/partitioning/partbounds.c
+++ b/src/backend/partitioning/partbounds.c
@@ -859,6 +859,244 @@ partition_bounds_copy(PartitionBoundInfo src,
return dest;
}
+/*
+ * Estimate the amount of space required to serialize a PartitionBoundInfo.
+ * As usual, we require the PartitionKey as an additional argument to
+ * properly interpret the stored Datums.
+ */
+Size
+partition_bounds_estimate(PartitionBoundInfo bound, PartitionKey key)
+{
+ Size sz;
+ int i;
+ int datums_per_bound;
+
+ /* Assorted sanity checks on the input data. */
+ Assert(bound->strategy == PARTITION_STRATEGY_RANGE ||
+ bound->strategy == PARTITION_STRATEGY_LIST ||
+ bound->strategy == PARTITION_STRATEGY_HASH);
+ Assert((bound->strategy == PARTITION_STRATEGY_RANGE) ==
+ (bound->kind != NULL));
+ Assert(key->partnatts > 0);
+
+ /* Space for strategy, ndatums, null_index, default_index. */
+ sz = sizeof(char) + 3 * sizeof(int);
+
+ /* Space for kind. */
+ if (bound->strategy == PARTITION_STRATEGY_RANGE)
+ sz = add_size(sz,
+ mul_size(mul_size(bound->ndatums, key->partnatts),
+ sizeof(PartitionRangeDatumKind)));
+
+ /* Space for datums. */
+ if (key->strategy == PARTITION_STRATEGY_HASH)
+ datums_per_bound = 2; /* modulus and remainder */
+ else
+ datums_per_bound = key->partnatts;
+ for (i = 0; i < bound->ndatums; i++)
+ {
+ int j;
+
+ for (j = 0; j < datums_per_bound; j++)
+ {
+ bool byval;
+ int typlen;
+
+ if (bound->strategy == PARTITION_STRATEGY_RANGE &&
+ bound->kind[i][j] != PARTITION_RANGE_DATUM_VALUE)
+ continue;
+
+ if (bound->strategy == PARTITION_STRATEGY_HASH)
+ {
+ typlen = sizeof(int32); /* Always int4 */
+ byval = true; /* int4 is pass-by-value */
+ }
+ else
+ {
+ byval = key->parttypbyval[j];
+ typlen = key->parttyplen[j];
+ }
+
+ sz = add_size(sz,
+ datumEstimateSpace(bound->datums[i][j], false,
+ byval, typlen));
+ }
+ }
+
+ /* Space for indexes. */
+ sz = add_size(sz,
+ mul_size(get_partition_bound_num_indexes(bound),
+ sizeof(int)));
+
+ return sz;
+}
+
+/*
+ * Serialize a PartitionBoundInfo; the PartitionKey is required for context
+ * both now and when restoring from the serialized state. Note that the caller
+ * must ensure that enough space is available. To find out how much space will
+ * be needed, call partition_bounds_estimate().
+ */
+void
+partition_bounds_serialize(PartitionBoundInfo bound, PartitionKey key,
+ char *start_address)
+{
+ Size indexbytes;
+ int i;
+ int datums_per_bound;
+
+ /*
+ * Copy fixed-width fields, remembering that start_address may not be
+ * aligned.
+ */
+ memcpy(start_address, &bound->strategy, sizeof(char));
+ start_address += sizeof(char);
+ memcpy(start_address, &bound->ndatums, sizeof(int));
+ start_address += sizeof(int);
+ memcpy(start_address, &bound->null_index, sizeof(int));
+ start_address += sizeof(int);
+ memcpy(start_address, &bound->default_index, sizeof(int));
+ start_address += sizeof(int);
+
+ /* Copy kind, if applicable. */
+ if (key->strategy == PARTITION_STRATEGY_RANGE)
+ {
+ for (i = 0; i < bound->ndatums; ++i)
+ {
+ Size bytes;
+
+ bytes = sizeof(PartitionRangeDatumKind) * key->partnatts;
+ memcpy(start_address, bound->kind[i], bytes);
+ start_address += bytes;
+ }
+ }
+
+ /* Space for datums. */
+ if (key->strategy == PARTITION_STRATEGY_HASH)
+ datums_per_bound = 2; /* modulus and remainder */
+ else
+ datums_per_bound = key->partnatts;
+ for (i = 0; i < bound->ndatums; i++)
+ {
+ int j;
+
+ for (j = 0; j < datums_per_bound; j++)
+ {
+ bool byval;
+ int typlen;
+
+ if (bound->strategy == PARTITION_STRATEGY_RANGE &&
+ bound->kind[i][j] != PARTITION_RANGE_DATUM_VALUE)
+ continue;
+
+ if (bound->strategy == PARTITION_STRATEGY_HASH)
+ {
+ typlen = sizeof(int32); /* Always int4 */
+ byval = true; /* int4 is pass-by-value */
+ }
+ else
+ {
+ byval = key->parttypbyval[j];
+ typlen = key->parttyplen[j];
+ }
+
+ datumSerialize(bound->datums[i][j], false, byval, typlen,
+ &start_address);
+ }
+ }
+
+ /* Copy indexes. */
+ indexbytes = sizeof(int) * get_partition_bound_num_indexes(bound);
+ memcpy(start_address, bound->indexes, indexbytes);
+ start_address += indexbytes;
+}
+
+/*
+ * Restore a previously-serialized PartitionBoundInfo.
+ *
+ * The result is allocated in CurrentMemoryContext. *start_address is
+ * incremented based on the number of bytes consumed.
+ */
+PartitionBoundInfo
+partition_bounds_restore(char **start_address, PartitionKey key)
+{
+ PartitionBoundInfo bound;
+ int datums_per_bound;
+ int i;
+ Size indexbytes;
+
+ bound = palloc0(sizeof(PartitionBoundInfoData));
+
+ /*
+ * Restore fixed-width fields, remembering that start_address may not be
+ * aligned.
+ */
+ memcpy(&bound->strategy, *start_address, sizeof(char));
+ *start_address += sizeof(char);
+ memcpy(&bound->ndatums, *start_address, sizeof(int));
+ *start_address += sizeof(int);
+ memcpy(&bound->null_index, *start_address, sizeof(int));
+ *start_address += sizeof(int);
+ memcpy(&bound->default_index, *start_address, sizeof(int));
+ *start_address += sizeof(int);
+
+ /* Restore kind, if applicable. */
+ if (key->strategy == PARTITION_STRATEGY_RANGE)
+ {
+ bound->kind =
+ palloc(bound->ndatums * sizeof(PartitionRangeDatumKind *));
+
+ for (i = 0; i < bound->ndatums; ++i)
+ {
+ Size bytes;
+
+ bytes = sizeof(PartitionRangeDatumKind) * key->partnatts;
+ bound->kind[i] = palloc(bytes);
+ memcpy(bound->kind[i], *start_address, bytes);
+ *start_address += bytes;
+ }
+ }
+
+ /* Restore datums; note that we must have 'kind' already to do this. */
+ if (key->strategy == PARTITION_STRATEGY_HASH)
+ datums_per_bound = 2; /* modulus and remainder */
+ else
+ datums_per_bound = key->partnatts;
+ bound->datums = palloc(sizeof(Datum *) * bound->ndatums);
+ for (i = 0; i < bound->ndatums; i++)
+ {
+ int j;
+
+ bound->datums[i] = palloc0(sizeof(Datum) * datums_per_bound);
+ for (j = 0; j < datums_per_bound; j++)
+ {
+ bool isnull;
+
+ if (bound->strategy == PARTITION_STRATEGY_RANGE &&
+ bound->kind[i][j] != PARTITION_RANGE_DATUM_VALUE)
+ continue;
+
+ /* datumRestore may palloc */
+ bound->datums[i][j] = datumRestore(start_address, &isnull);
+ Assert(!isnull);
+ }
+ }
+
+ /*
+ * Restore indexes.
+ *
+ * Note that we're calling get_partition_bound_num_indexes on the bound
+ * object even though it isn't complete yet. Fortunately it doesn't
+ * depend on the array we're about to restore, so that's OK.
+ */
+ indexbytes = sizeof(int) * get_partition_bound_num_indexes(bound);
+ bound->indexes = palloc(indexbytes);
+ memcpy(bound->indexes, *start_address, indexbytes);
+ *start_address += indexbytes;
+
+ return bound;
+}
+
/*
* check_new_partition_bound
*
diff --git a/src/backend/partitioning/partdesc.c b/src/backend/partitioning/partdesc.c
index a207ff35ee..84e24646a4 100644
--- a/src/backend/partitioning/partdesc.c
+++ b/src/backend/partitioning/partdesc.c
@@ -331,6 +331,80 @@ equalPartitionDescs(PartitionKey key, PartitionDesc partdesc1,
return true;
}
+/*
+ * Estimate the amount of space required to serialize a PartitionDesc.
+ */
+Size
+EstimatePartitionDesc(PartitionDesc partdesc, PartitionKey key)
+{
+ Size sz = sizeof(int); /* for nparts */
+
+ /* Space for oids and is_leaf. */
+ sz = add_size(sz, mul_size(partdesc->nparts, sizeof(Oid) + sizeof(bool)));
+
+ /* Space for boundinfo, if required. */
+ if (partdesc->nparts > 0)
+ sz = add_size(sz, partition_bounds_estimate(partdesc->boundinfo, key));
+
+ return sz;
+}
+
+/*
+ * Serialize a PartitionDesc. The caller must use EstimatePartitionDesc to
+ * determine how much space will be needed and pass a sufficiently-large
+ * buffer to this function.
+ */
+void
+SerializePartitionDesc(PartitionDesc partdesc, PartitionKey key,
+ char *start_address)
+{
+ Size oids_bytes = sizeof(Oid) * partdesc->nparts;
+ Size is_leaf_bytes = sizeof(bool) * partdesc->nparts;
+
+ memcpy(start_address, &partdesc->nparts, sizeof(int));
+ start_address += sizeof(int);
+ if (partdesc->nparts > 0)
+ {
+ memcpy(start_address, partdesc->oids, oids_bytes);
+ start_address += oids_bytes;
+ memcpy(start_address, partdesc->is_leaf, is_leaf_bytes);
+ start_address += is_leaf_bytes;
+ partition_bounds_serialize(partdesc->boundinfo, key, start_address);
+ }
+}
+
+/*
+ * Restore a serialized PartitionDesc into CurrentMemoryContext, advancing
+ * *start_address based on the number of bytes consumed.
+ */
+PartitionDesc
+RestorePartitionDesc(char **start_address, PartitionKey key)
+{
+ PartitionDesc partdesc;
+
+ partdesc = palloc0(sizeof(PartitionDescData));
+ memcpy(&partdesc->nparts, *start_address, sizeof(int));
+ *start_address += sizeof(int);
+
+ if (partdesc->nparts > 0)
+ {
+ Size oids_bytes = partdesc->nparts * sizeof(Oid);
+ Size is_leaf_bytes = partdesc->nparts * sizeof(bool);
+
+ partdesc->oids = palloc(oids_bytes);
+ memcpy(partdesc->oids, *start_address, oids_bytes);
+ *start_address += oids_bytes;
+
+ partdesc->is_leaf = palloc(is_leaf_bytes);
+ memcpy(partdesc->is_leaf, *start_address, is_leaf_bytes);
+ *start_address += is_leaf_bytes;
+
+ partdesc->boundinfo = partition_bounds_restore(start_address, key);
+ }
+
+ return partdesc;
+}
+
/*
* get_default_oid_from_partdesc
*
diff --git a/src/include/partitioning/partbounds.h b/src/include/partitioning/partbounds.h
index b1ae39ad63..0ac6daf319 100644
--- a/src/include/partitioning/partbounds.h
+++ b/src/include/partitioning/partbounds.h
@@ -87,6 +87,12 @@ extern bool partition_bounds_equal(int partnatts, int16 *parttyplen,
PartitionBoundInfo b2);
extern PartitionBoundInfo partition_bounds_copy(PartitionBoundInfo src,
PartitionKey key);
+extern Size partition_bounds_estimate(PartitionBoundInfo bound,
+ PartitionKey key);
+extern void partition_bounds_serialize(PartitionBoundInfo bound,
+ PartitionKey key, char *start_address);
+extern PartitionBoundInfo partition_bounds_restore(char **start_address,
+ PartitionKey key);
extern void check_new_partition_bound(char *relname, Relation parent,
PartitionBoundSpec *spec);
extern void check_default_partition_contents(Relation parent,
diff --git a/src/include/partitioning/partdesc.h b/src/include/partitioning/partdesc.h
index 6e384541da..1e679083d5 100644
--- a/src/include/partitioning/partdesc.h
+++ b/src/include/partitioning/partdesc.h
@@ -39,4 +39,10 @@ extern Oid get_default_oid_from_partdesc(PartitionDesc partdesc);
extern bool equalPartitionDescs(PartitionKey key, PartitionDesc partdesc1,
PartitionDesc partdesc2);
+extern Size EstimatePartitionDesc(PartitionDesc partdesc, PartitionKey key);
+extern void SerializePartitionDesc(PartitionDesc partdesc, PartitionKey key,
+ char *start_address);
+extern PartitionDesc RestorePartitionDesc(char **start_address,
+ PartitionKey key);
+
#endif /* PARTCACHE_H */
--
2.17.2 (Apple Git-113)