mirror of https://github.com/citusdata/citus.git
Implement nontransactional truncate
parent
b72a4d8d19
commit
62fc59202c
2
cstore.h
2
cstore.h
|
@ -283,7 +283,7 @@ extern StringInfo DecompressBuffer(StringInfo buffer, CompressionType compressio
|
||||||
extern void DeleteDataFileMetadataRowIfExists(Oid relfilenode);
|
extern void DeleteDataFileMetadataRowIfExists(Oid relfilenode);
|
||||||
extern void InitCStoreDataFileMetadata(Oid relfilenode, int blockRowCount);
|
extern void InitCStoreDataFileMetadata(Oid relfilenode, int blockRowCount);
|
||||||
extern void InsertStripeMetadataRow(Oid relfilenode, StripeMetadata *stripe);
|
extern void InsertStripeMetadataRow(Oid relfilenode, StripeMetadata *stripe);
|
||||||
extern DataFileMetadata * ReadDataFileMetadata(Oid relfilenode);
|
extern DataFileMetadata * ReadDataFileMetadata(Oid relfilenode, bool missingOk);
|
||||||
extern void SaveStripeSkipList(Oid relfilenode, uint64 stripe,
|
extern void SaveStripeSkipList(Oid relfilenode, uint64 stripe,
|
||||||
StripeSkipList *stripeSkipList,
|
StripeSkipList *stripeSkipList,
|
||||||
TupleDesc tupleDescriptor);
|
TupleDesc tupleDescriptor);
|
||||||
|
|
|
@ -343,7 +343,7 @@ InsertStripeMetadataRow(Oid relfilenode, StripeMetadata *stripe)
|
||||||
* from cstore_data_files and cstore_stripes.
|
* from cstore_data_files and cstore_stripes.
|
||||||
*/
|
*/
|
||||||
DataFileMetadata *
|
DataFileMetadata *
|
||||||
ReadDataFileMetadata(Oid relfilenode)
|
ReadDataFileMetadata(Oid relfilenode, bool missingOk)
|
||||||
{
|
{
|
||||||
Oid cstoreStripesOid = InvalidOid;
|
Oid cstoreStripesOid = InvalidOid;
|
||||||
Relation cstoreStripes = NULL;
|
Relation cstoreStripes = NULL;
|
||||||
|
@ -357,10 +357,17 @@ ReadDataFileMetadata(Oid relfilenode)
|
||||||
DataFileMetadata *datafileMetadata = palloc0(sizeof(DataFileMetadata));
|
DataFileMetadata *datafileMetadata = palloc0(sizeof(DataFileMetadata));
|
||||||
found = ReadCStoreDataFiles(relfilenode, &datafileMetadata->blockRowCount);
|
found = ReadCStoreDataFiles(relfilenode, &datafileMetadata->blockRowCount);
|
||||||
if (!found)
|
if (!found)
|
||||||
|
{
|
||||||
|
if (!missingOk)
|
||||||
{
|
{
|
||||||
ereport(ERROR, (errmsg("Relfilenode %d doesn't belong to a cstore table.",
|
ereport(ERROR, (errmsg("Relfilenode %d doesn't belong to a cstore table.",
|
||||||
relfilenode)));
|
relfilenode)));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ScanKeyInit(&scanKey[0], Anum_cstore_stripes_relfilenode,
|
ScanKeyInit(&scanKey[0], Anum_cstore_stripes_relfilenode,
|
||||||
BTEqualStrategyNumber, F_OIDEQ, Int32GetDatum(relfilenode));
|
BTEqualStrategyNumber, F_OIDEQ, Int32GetDatum(relfilenode));
|
||||||
|
|
|
@ -88,7 +88,7 @@ CStoreBeginRead(Relation relation, TupleDesc tupleDescriptor,
|
||||||
MemoryContext stripeReadContext = NULL;
|
MemoryContext stripeReadContext = NULL;
|
||||||
Oid relNode = relation->rd_node.relNode;
|
Oid relNode = relation->rd_node.relNode;
|
||||||
|
|
||||||
datafileMetadata = ReadDataFileMetadata(relNode);
|
datafileMetadata = ReadDataFileMetadata(relNode, false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We allocate all stripe specific data in the stripeReadContext, and reset
|
* We allocate all stripe specific data in the stripeReadContext, and reset
|
||||||
|
@ -309,7 +309,7 @@ CStoreTableRowCount(Relation relation)
|
||||||
ListCell *stripeMetadataCell = NULL;
|
ListCell *stripeMetadataCell = NULL;
|
||||||
uint64 totalRowCount = 0;
|
uint64 totalRowCount = 0;
|
||||||
|
|
||||||
datafileMetadata = ReadDataFileMetadata(relation->rd_node.relNode);
|
datafileMetadata = ReadDataFileMetadata(relation->rd_node.relNode, false);
|
||||||
|
|
||||||
foreach(stripeMetadataCell, datafileMetadata->stripeMetadataList)
|
foreach(stripeMetadataCell, datafileMetadata->stripeMetadataList)
|
||||||
{
|
{
|
||||||
|
|
|
@ -443,7 +443,20 @@ cstore_relation_set_new_filenode(Relation rel,
|
||||||
MultiXactId *minmulti)
|
MultiXactId *minmulti)
|
||||||
{
|
{
|
||||||
SMgrRelation srel;
|
SMgrRelation srel;
|
||||||
|
DataFileMetadata *metadata = ReadDataFileMetadata(rel->rd_node.relNode, true);
|
||||||
|
uint64 blockRowCount = 0;
|
||||||
|
|
||||||
|
if (metadata != NULL)
|
||||||
|
{
|
||||||
|
/* existing table (e.g. TRUNCATE), use existing blockRowCount */
|
||||||
|
blockRowCount = metadata->blockRowCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* new table, use options */
|
||||||
CStoreOptions *options = CStoreTableAMGetOptions();
|
CStoreOptions *options = CStoreTableAMGetOptions();
|
||||||
|
blockRowCount = options->blockRowCount;
|
||||||
|
}
|
||||||
|
|
||||||
/* delete old relfilenode metadata */
|
/* delete old relfilenode metadata */
|
||||||
DeleteDataFileMetadataRowIfExists(rel->rd_node.relNode);
|
DeleteDataFileMetadataRowIfExists(rel->rd_node.relNode);
|
||||||
|
@ -452,7 +465,7 @@ cstore_relation_set_new_filenode(Relation rel,
|
||||||
*freezeXid = RecentXmin;
|
*freezeXid = RecentXmin;
|
||||||
*minmulti = GetOldestMultiXactId();
|
*minmulti = GetOldestMultiXactId();
|
||||||
srel = RelationCreateStorage(*newrnode, persistence);
|
srel = RelationCreateStorage(*newrnode, persistence);
|
||||||
InitCStoreDataFileMetadata(newrnode->relNode, options->blockRowCount);
|
InitCStoreDataFileMetadata(newrnode->relNode, blockRowCount);
|
||||||
smgrclose(srel);
|
smgrclose(srel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,7 +473,20 @@ cstore_relation_set_new_filenode(Relation rel,
|
||||||
static void
|
static void
|
||||||
cstore_relation_nontransactional_truncate(Relation rel)
|
cstore_relation_nontransactional_truncate(Relation rel)
|
||||||
{
|
{
|
||||||
elog(ERROR, "cstore_relation_nontransactional_truncate not implemented");
|
DataFileMetadata *metadata = ReadDataFileMetadata(rel->rd_node.relNode, false);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No need to set new relfilenode, since the table was created in this
|
||||||
|
* transaction and no other transaction can see this relation yet. We
|
||||||
|
* can just truncate the relation.
|
||||||
|
*
|
||||||
|
* This is similar to what is done in heapam_relation_nontransactional_truncate.
|
||||||
|
*/
|
||||||
|
RelationTruncate(rel, 0);
|
||||||
|
|
||||||
|
/* Delete old relfilenode metadata and recreate it */
|
||||||
|
DeleteDataFileMetadataRowIfExists(rel->rd_node.relNode);
|
||||||
|
InitCStoreDataFileMetadata(rel->rd_node.relNode, metadata->blockRowCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ CStoreBeginWrite(Relation relation,
|
||||||
uint64 currentStripeId = 0;
|
uint64 currentStripeId = 0;
|
||||||
Oid relNode = relation->rd_node.relNode;
|
Oid relNode = relation->rd_node.relNode;
|
||||||
|
|
||||||
datafileMetadata = ReadDataFileMetadata(relNode);
|
datafileMetadata = ReadDataFileMetadata(relNode, false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If stripeMetadataList is not empty, jump to the position right after
|
* If stripeMetadataList is not empty, jump to the position right after
|
||||||
|
|
|
@ -153,6 +153,30 @@ SELECT :cstore_data_files_before_truncate - count(*) FROM cstore.cstore_data_fil
|
||||||
0
|
0
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
-- test if truncation in the same transaction that created the table works properly
|
||||||
|
BEGIN;
|
||||||
|
CREATE TABLE cstore_same_transaction_truncate(a int) USING cstore_tableam;
|
||||||
|
INSERT INTO cstore_same_transaction_truncate SELECT * FROM generate_series(1, 100);
|
||||||
|
TRUNCATE cstore_same_transaction_truncate;
|
||||||
|
INSERT INTO cstore_same_transaction_truncate SELECT * FROM generate_series(20, 23);
|
||||||
|
COMMIT;
|
||||||
|
-- should output "1" for the newly created relation
|
||||||
|
SELECT count(*) - :cstore_data_files_before_truncate FROM cstore.cstore_data_files;
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT * FROM cstore_same_transaction_truncate;
|
||||||
|
a
|
||||||
|
----
|
||||||
|
20
|
||||||
|
21
|
||||||
|
22
|
||||||
|
23
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
DROP TABLE cstore_same_transaction_truncate;
|
||||||
-- test if a cached truncate from a pl/pgsql function works
|
-- test if a cached truncate from a pl/pgsql function works
|
||||||
CREATE FUNCTION cstore_truncate_test_regular_func() RETURNS void AS $$
|
CREATE FUNCTION cstore_truncate_test_regular_func() RETURNS void AS $$
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
|
@ -150,6 +150,30 @@ SELECT :cstore_data_files_before_truncate - count(*) FROM cstore.cstore_data_fil
|
||||||
0
|
0
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
-- test if truncation in the same transaction that created the table works properly
|
||||||
|
BEGIN;
|
||||||
|
CREATE FOREIGN TABLE cstore_same_transaction_truncate(a int) SERVER cstore_server;
|
||||||
|
INSERT INTO cstore_same_transaction_truncate SELECT * FROM generate_series(1, 100);
|
||||||
|
TRUNCATE cstore_same_transaction_truncate;
|
||||||
|
INSERT INTO cstore_same_transaction_truncate SELECT * FROM generate_series(20, 23);
|
||||||
|
COMMIT;
|
||||||
|
-- should output "1" for the newly created relation
|
||||||
|
SELECT count(*) - :cstore_data_files_before_truncate FROM cstore.cstore_data_files;
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT * FROM cstore_same_transaction_truncate;
|
||||||
|
a
|
||||||
|
----
|
||||||
|
20
|
||||||
|
21
|
||||||
|
22
|
||||||
|
23
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
DROP FOREIGN TABLE cstore_same_transaction_truncate;
|
||||||
-- test if a cached truncate from a pl/pgsql function works
|
-- test if a cached truncate from a pl/pgsql function works
|
||||||
CREATE FUNCTION cstore_truncate_test_regular_func() RETURNS void AS $$
|
CREATE FUNCTION cstore_truncate_test_regular_func() RETURNS void AS $$
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
|
@ -65,6 +65,20 @@ SELECT * from cstore_truncate_test;
|
||||||
-- make sure TRUNATE deletes metadata for old relfilenode
|
-- make sure TRUNATE deletes metadata for old relfilenode
|
||||||
SELECT :cstore_data_files_before_truncate - count(*) FROM cstore.cstore_data_files;
|
SELECT :cstore_data_files_before_truncate - count(*) FROM cstore.cstore_data_files;
|
||||||
|
|
||||||
|
-- test if truncation in the same transaction that created the table works properly
|
||||||
|
BEGIN;
|
||||||
|
CREATE TABLE cstore_same_transaction_truncate(a int) USING cstore_tableam;
|
||||||
|
INSERT INTO cstore_same_transaction_truncate SELECT * FROM generate_series(1, 100);
|
||||||
|
TRUNCATE cstore_same_transaction_truncate;
|
||||||
|
INSERT INTO cstore_same_transaction_truncate SELECT * FROM generate_series(20, 23);
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- should output "1" for the newly created relation
|
||||||
|
SELECT count(*) - :cstore_data_files_before_truncate FROM cstore.cstore_data_files;
|
||||||
|
SELECT * FROM cstore_same_transaction_truncate;
|
||||||
|
|
||||||
|
DROP TABLE cstore_same_transaction_truncate;
|
||||||
|
|
||||||
-- test if a cached truncate from a pl/pgsql function works
|
-- test if a cached truncate from a pl/pgsql function works
|
||||||
CREATE FUNCTION cstore_truncate_test_regular_func() RETURNS void AS $$
|
CREATE FUNCTION cstore_truncate_test_regular_func() RETURNS void AS $$
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
|
@ -62,6 +62,20 @@ SELECT * from cstore_truncate_test;
|
||||||
-- make sure TRUNATE deletes metadata for old relfilenode
|
-- make sure TRUNATE deletes metadata for old relfilenode
|
||||||
SELECT :cstore_data_files_before_truncate - count(*) FROM cstore.cstore_data_files;
|
SELECT :cstore_data_files_before_truncate - count(*) FROM cstore.cstore_data_files;
|
||||||
|
|
||||||
|
-- test if truncation in the same transaction that created the table works properly
|
||||||
|
BEGIN;
|
||||||
|
CREATE FOREIGN TABLE cstore_same_transaction_truncate(a int) SERVER cstore_server;
|
||||||
|
INSERT INTO cstore_same_transaction_truncate SELECT * FROM generate_series(1, 100);
|
||||||
|
TRUNCATE cstore_same_transaction_truncate;
|
||||||
|
INSERT INTO cstore_same_transaction_truncate SELECT * FROM generate_series(20, 23);
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
-- should output "1" for the newly created relation
|
||||||
|
SELECT count(*) - :cstore_data_files_before_truncate FROM cstore.cstore_data_files;
|
||||||
|
SELECT * FROM cstore_same_transaction_truncate;
|
||||||
|
|
||||||
|
DROP FOREIGN TABLE cstore_same_transaction_truncate;
|
||||||
|
|
||||||
-- test if a cached truncate from a pl/pgsql function works
|
-- test if a cached truncate from a pl/pgsql function works
|
||||||
CREATE FUNCTION cstore_truncate_test_regular_func() RETURNS void AS $$
|
CREATE FUNCTION cstore_truncate_test_regular_func() RETURNS void AS $$
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
Loading…
Reference in New Issue