Implement nontransactional truncate

merge-cstore-pykello
Hadi Moshayedi 2020-10-05 10:09:19 -07:00
parent b72a4d8d19
commit 62fc59202c
9 changed files with 119 additions and 10 deletions

View File

@ -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);

View File

@ -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));

View File

@ -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)
{ {

View File

@ -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);
} }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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