mirror of https://github.com/citusdata/citus.git
Remove foreign keys between columnar metadata tables (#4791)
Postgres keeps AFTER trigger state for each transaction, because we can have deferred AFTER triggers which will be fired at the end of a transaction. Postgres cleans up this state at the end of transaction. Postgres processes ON COMMIT triggers after cleaning-up the AFTER trigger states. So if we fire any triggers in ON COMMIT, the AFTER trigger state won't be cleaned-up properly and the transaction state will be left in an inconsistent state, which might result in assertion failure. So with this commit, we remove foreign keys between columnar metadata tables and enforce constraints between them manually when dropping columnar tables.pull/4806/head
parent
71a9f45513
commit
874d5fd962
|
@ -95,6 +95,10 @@ static Oid ColumnarChunkGroupRelationId(void);
|
|||
static Oid ColumnarChunkIndexRelationId(void);
|
||||
static Oid ColumnarChunkGroupIndexRelationId(void);
|
||||
static Oid ColumnarNamespaceId(void);
|
||||
static void DeleteStorageFromColumnarMetadataTable(Oid metadataTableId,
|
||||
AttrNumber storageIdAtrrNumber,
|
||||
Oid storageIdIndexId,
|
||||
uint64 storageId);
|
||||
static ModifyState * StartModifyRelation(Relation rel);
|
||||
static void InsertTupleAndEnforceConstraints(ModifyState *state, Datum *values,
|
||||
bool *nulls);
|
||||
|
@ -951,13 +955,12 @@ ReadDataFileStripeList(uint64 storageId, Snapshot snapshot)
|
|||
|
||||
|
||||
/*
|
||||
* DeleteMetadataRows removes the rows with given relfilenode from columnar.stripe.
|
||||
* DeleteMetadataRows removes the rows with given relfilenode from columnar
|
||||
* metadata tables.
|
||||
*/
|
||||
void
|
||||
DeleteMetadataRows(RelFileNode relfilenode)
|
||||
{
|
||||
ScanKeyData scanKey[1];
|
||||
|
||||
/*
|
||||
* During a restore for binary upgrade, metadata tables and indexes may or
|
||||
* may not exist.
|
||||
|
@ -977,23 +980,47 @@ DeleteMetadataRows(RelFileNode relfilenode)
|
|||
return;
|
||||
}
|
||||
|
||||
ScanKeyInit(&scanKey[0], Anum_columnar_stripe_storageid,
|
||||
BTEqualStrategyNumber, F_INT8EQ, UInt64GetDatum(metapage->storageId));
|
||||
DeleteStorageFromColumnarMetadataTable(ColumnarStripeRelationId(),
|
||||
Anum_columnar_stripe_storageid,
|
||||
ColumnarStripeIndexRelationId(),
|
||||
metapage->storageId);
|
||||
DeleteStorageFromColumnarMetadataTable(ColumnarChunkGroupRelationId(),
|
||||
Anum_columnar_chunkgroup_storageid,
|
||||
ColumnarChunkGroupIndexRelationId(),
|
||||
metapage->storageId);
|
||||
DeleteStorageFromColumnarMetadataTable(ColumnarChunkRelationId(),
|
||||
Anum_columnar_chunk_storageid,
|
||||
ColumnarChunkIndexRelationId(),
|
||||
metapage->storageId);
|
||||
}
|
||||
|
||||
Oid columnarStripesOid = ColumnarStripeRelationId();
|
||||
Relation columnarStripes = try_relation_open(columnarStripesOid, AccessShareLock);
|
||||
if (columnarStripes == NULL)
|
||||
|
||||
/*
|
||||
* DeleteStorageFromColumnarMetadataTable removes the rows with given
|
||||
* storageId from given columnar metadata table.
|
||||
*/
|
||||
static void
|
||||
DeleteStorageFromColumnarMetadataTable(Oid metadataTableId,
|
||||
AttrNumber storageIdAtrrNumber,
|
||||
Oid storageIdIndexId, uint64 storageId)
|
||||
{
|
||||
ScanKeyData scanKey[1];
|
||||
ScanKeyInit(&scanKey[0], storageIdAtrrNumber, BTEqualStrategyNumber,
|
||||
F_INT8EQ, UInt64GetDatum(storageId));
|
||||
|
||||
Relation metadataTable = try_relation_open(metadataTableId, AccessShareLock);
|
||||
if (metadataTable == NULL)
|
||||
{
|
||||
/* extension has been dropped */
|
||||
return;
|
||||
}
|
||||
|
||||
Relation index = index_open(ColumnarStripeIndexRelationId(), AccessShareLock);
|
||||
Relation index = index_open(storageIdIndexId, AccessShareLock);
|
||||
|
||||
SysScanDesc scanDescriptor = systable_beginscan_ordered(columnarStripes, index, NULL,
|
||||
SysScanDesc scanDescriptor = systable_beginscan_ordered(metadataTable, index, NULL,
|
||||
1, scanKey);
|
||||
|
||||
ModifyState *modifyState = StartModifyRelation(columnarStripes);
|
||||
ModifyState *modifyState = StartModifyRelation(metadataTable);
|
||||
|
||||
HeapTuple heapTuple = systable_getnext(scanDescriptor);
|
||||
while (HeapTupleIsValid(heapTuple))
|
||||
|
@ -1006,7 +1033,7 @@ DeleteMetadataRows(RelFileNode relfilenode)
|
|||
|
||||
systable_endscan_ordered(scanDescriptor);
|
||||
index_close(index, AccessShareLock);
|
||||
table_close(columnarStripes, AccessShareLock);
|
||||
table_close(metadataTable, AccessShareLock);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/* columnar--10.0-3--10.1-1.sql */
|
||||
|
||||
-- Drop foreign keys between columnar metadata tables.
|
||||
-- Postgres assigns different names to those foreign keys in PG11, so act accordingly.
|
||||
DO $proc$
|
||||
BEGIN
|
||||
IF substring(current_Setting('server_version'), '\d+')::int >= 12 THEN
|
||||
EXECUTE $$
|
||||
ALTER TABLE columnar.chunk DROP CONSTRAINT chunk_storage_id_stripe_num_chunk_group_num_fkey;
|
||||
ALTER TABLE columnar.chunk_group DROP CONSTRAINT chunk_group_storage_id_stripe_num_fkey;
|
||||
$$;
|
||||
ELSE
|
||||
EXECUTE $$
|
||||
ALTER TABLE columnar.chunk DROP CONSTRAINT chunk_storage_id_fkey;
|
||||
ALTER TABLE columnar.chunk_group DROP CONSTRAINT chunk_group_storage_id_fkey;
|
||||
$$;
|
||||
END IF;
|
||||
END$proc$;
|
|
@ -0,0 +1,10 @@
|
|||
/* columnar--10.1-1--10.0-3.sql */
|
||||
|
||||
-- define foreign keys between columnar metadata tables
|
||||
ALTER TABLE columnar.chunk
|
||||
ADD FOREIGN KEY (storage_id, stripe_num, chunk_group_num)
|
||||
REFERENCES columnar.chunk_group(storage_id, stripe_num, chunk_group_num) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE columnar.chunk_group
|
||||
ADD FOREIGN KEY (storage_id, stripe_num)
|
||||
REFERENCES columnar.stripe(storage_id, stripe_num) ON DELETE CASCADE;
|
|
@ -1,4 +1,3 @@
|
|||
-- citus--10.0-3--10.1-1
|
||||
|
||||
-- bump version to 10.1-1
|
||||
|
||||
#include "../../columnar/sql/columnar--10.0-3--10.1-1.sql"
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
-- citus--10.1-1--10.0-2
|
||||
-- this is an empty downgrade path since citus--10.0-3--10.1-1.sql is empty for now
|
||||
|
||||
#include "../../../columnar/sql/downgrades/columnar--10.1-1--10.0-3.sql"
|
||||
|
|
|
@ -67,3 +67,65 @@ WITH a as (
|
|||
)
|
||||
SELECT (SELECT count(*) = 0 FROM c) AND
|
||||
(SELECT count(*) = 0 FROM f) as consistent;
|
||||
CREATE FUNCTION columnar_metadata_has_storage_id(input_storage_id bigint) RETURNS boolean
|
||||
AS $$
|
||||
DECLARE
|
||||
union_storage_id_count integer;
|
||||
BEGIN
|
||||
SELECT count(*) INTO union_storage_id_count FROM
|
||||
(
|
||||
SELECT storage_id FROM columnar.stripe UNION ALL
|
||||
SELECT storage_id FROM columnar.chunk UNION ALL
|
||||
SELECT storage_id FROM columnar.chunk_group
|
||||
) AS union_storage_id
|
||||
WHERE storage_id=input_storage_id;
|
||||
|
||||
IF union_storage_id_count > 0 THEN
|
||||
RETURN true;
|
||||
END IF;
|
||||
|
||||
RETURN false;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
CREATE TABLE columnar_table_1 (a int) USING columnar;
|
||||
INSERT INTO columnar_table_1 VALUES (1);
|
||||
CREATE MATERIALIZED VIEW columnar_table_1_mv USING columnar
|
||||
AS SELECT * FROM columnar_table_1;
|
||||
SELECT columnar_relation_storageid(oid) AS columnar_table_1_mv_storage_id
|
||||
FROM pg_class WHERE relname='columnar_table_1_mv' \gset
|
||||
-- test columnar_relation_set_new_filenode
|
||||
REFRESH MATERIALIZED VIEW columnar_table_1_mv;
|
||||
SELECT columnar_metadata_has_storage_id(:columnar_table_1_mv_storage_id);
|
||||
columnar_metadata_has_storage_id
|
||||
---------------------------------------------------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT columnar_relation_storageid(oid) AS columnar_table_1_storage_id
|
||||
FROM pg_class WHERE relname='columnar_table_1' \gset
|
||||
BEGIN;
|
||||
-- test columnar_relation_nontransactional_truncate
|
||||
TRUNCATE columnar_table_1;
|
||||
SELECT columnar_metadata_has_storage_id(:columnar_table_1_storage_id);
|
||||
columnar_metadata_has_storage_id
|
||||
---------------------------------------------------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
ROLLBACK;
|
||||
-- since we rollback'ed above xact, should return true
|
||||
SELECT columnar_metadata_has_storage_id(:columnar_table_1_storage_id);
|
||||
columnar_metadata_has_storage_id
|
||||
---------------------------------------------------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
-- test dropping columnar table
|
||||
DROP TABLE columnar_table_1 CASCADE;
|
||||
NOTICE: drop cascades to materialized view columnar_table_1_mv
|
||||
SELECT columnar_metadata_has_storage_id(:columnar_table_1_storage_id);
|
||||
columnar_metadata_has_storage_id
|
||||
---------------------------------------------------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
|
|
|
@ -71,3 +71,53 @@ WITH a as (
|
|||
)
|
||||
SELECT (SELECT count(*) = 0 FROM c) AND
|
||||
(SELECT count(*) = 0 FROM f) as consistent;
|
||||
|
||||
CREATE FUNCTION columnar_metadata_has_storage_id(input_storage_id bigint) RETURNS boolean
|
||||
AS $$
|
||||
DECLARE
|
||||
union_storage_id_count integer;
|
||||
BEGIN
|
||||
SELECT count(*) INTO union_storage_id_count FROM
|
||||
(
|
||||
SELECT storage_id FROM columnar.stripe UNION ALL
|
||||
SELECT storage_id FROM columnar.chunk UNION ALL
|
||||
SELECT storage_id FROM columnar.chunk_group
|
||||
) AS union_storage_id
|
||||
WHERE storage_id=input_storage_id;
|
||||
|
||||
IF union_storage_id_count > 0 THEN
|
||||
RETURN true;
|
||||
END IF;
|
||||
|
||||
RETURN false;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TABLE columnar_table_1 (a int) USING columnar;
|
||||
INSERT INTO columnar_table_1 VALUES (1);
|
||||
|
||||
CREATE MATERIALIZED VIEW columnar_table_1_mv USING columnar
|
||||
AS SELECT * FROM columnar_table_1;
|
||||
|
||||
SELECT columnar_relation_storageid(oid) AS columnar_table_1_mv_storage_id
|
||||
FROM pg_class WHERE relname='columnar_table_1_mv' \gset
|
||||
|
||||
-- test columnar_relation_set_new_filenode
|
||||
REFRESH MATERIALIZED VIEW columnar_table_1_mv;
|
||||
SELECT columnar_metadata_has_storage_id(:columnar_table_1_mv_storage_id);
|
||||
|
||||
SELECT columnar_relation_storageid(oid) AS columnar_table_1_storage_id
|
||||
FROM pg_class WHERE relname='columnar_table_1' \gset
|
||||
|
||||
BEGIN;
|
||||
-- test columnar_relation_nontransactional_truncate
|
||||
TRUNCATE columnar_table_1;
|
||||
SELECT columnar_metadata_has_storage_id(:columnar_table_1_storage_id);
|
||||
ROLLBACK;
|
||||
|
||||
-- since we rollback'ed above xact, should return true
|
||||
SELECT columnar_metadata_has_storage_id(:columnar_table_1_storage_id);
|
||||
|
||||
-- test dropping columnar table
|
||||
DROP TABLE columnar_table_1 CASCADE;
|
||||
SELECT columnar_metadata_has_storage_id(:columnar_table_1_storage_id);
|
||||
|
|
Loading…
Reference in New Issue