diff --git a/Makefile b/Makefile index 483aebc35..ac7e15037 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ ifeq ($(USE_FDW),yes) OBJS += cstore_fdw.o REGRESS += fdw_create fdw_load fdw_query fdw_analyze fdw_data_types \ fdw_functions fdw_block_filtering fdw_drop fdw_insert \ - fdw_copyto fdw_alter fdw_truncate fdw_clean + fdw_copyto fdw_alter fdw_rollback fdw_truncate fdw_clean endif # disabled tests: am_block_filtering @@ -53,7 +53,7 @@ ifeq ($(USE_TABLEAM),yes) PG_CFLAGS += -DUSE_TABLEAM OBJS += cstore_tableam.o REGRESS += am_create am_load am_query am_analyze am_data_types am_functions \ - am_drop am_insert am_copyto am_alter am_truncate am_clean + am_drop am_insert am_copyto am_alter am_rollback am_truncate am_clean endif ifeq ($(enable_coverage),yes) diff --git a/cstore_writer.c b/cstore_writer.c index c70b448c7..1146bd0a3 100644 --- a/cstore_writer.c +++ b/cstore_writer.c @@ -403,7 +403,19 @@ WriteToSmgr(TableWriteState *writeState, char *data, uint32 dataLength) PageInit(page, BLCKSZ, 0); } - /* always appending */ + /* + * After a transaction has been rolled-back, we might be + * over-writing the rolledback write, so phdr->pd_lower can be + * different from addr.offset. + * + * We reset pd_lower to reset the rolledback write. + */ + if (phdr->pd_lower > addr.offset) + { + ereport(DEBUG1, (errmsg("over-writing page %u", addr.blockno), + errdetail("This can happen after a roll-back."))); + phdr->pd_lower = addr.offset; + } Assert(phdr->pd_lower == addr.offset); START_CRIT_SECTION(); diff --git a/expected/am_rollback.out b/expected/am_rollback.out new file mode 100644 index 000000000..130baaa3a --- /dev/null +++ b/expected/am_rollback.out @@ -0,0 +1,77 @@ +-- +-- Testing we handle rollbacks properly +-- +CREATE TABLE t(a int, b int) USING cstore_tableam; +BEGIN; +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +ROLLBACK; +SELECT count(*) FROM t; + count +------- + 0 +(1 row) + +-- check stripe metadata also have been rolled-back +SELECT count(*) FROM cstore.cstore_stripes a, pg_class b +WHERE a.relfilenode = b.relfilenode AND b.relname = 't'; + count +------- + 0 +(1 row) + +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +SELECT count(*) FROM t; + count +------- + 10 +(1 row) + +SELECT count(*) FROM cstore.cstore_stripes a, pg_class b +WHERE a.relfilenode = b.relfilenode AND b.relname = 't'; + count +------- + 1 +(1 row) + +-- savepoint rollback +BEGIN; +SAVEPOINT s0; +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +SAVEPOINT s1; +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +SELECT count(*) FROM t; + count +------- + 30 +(1 row) + +ROLLBACK TO SAVEPOINT s1; +SELECT count(*) FROM t; + count +------- + 20 +(1 row) + +ROLLBACK TO SAVEPOINT s0; +SELECT count(*) FROM t; + count +------- + 10 +(1 row) + +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +COMMIT; +SELECT count(*) FROM t; + count +------- + 20 +(1 row) + +SELECT count(*) FROM cstore.cstore_stripes a, pg_class b +WHERE a.relfilenode = b.relfilenode AND b.relname = 't'; + count +------- + 2 +(1 row) + +DROP TABLE t; diff --git a/expected/fdw_rollback.out b/expected/fdw_rollback.out new file mode 100644 index 000000000..f50f9fd19 --- /dev/null +++ b/expected/fdw_rollback.out @@ -0,0 +1,77 @@ +-- +-- Testing we handle rollbacks properly +-- +CREATE FOREIGN TABLE t(a int, b int) SERVER cstore_server; +BEGIN; +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +ROLLBACK; +SELECT count(*) FROM t; + count +------- + 0 +(1 row) + +-- check stripe metadata also have been rolled-back +SELECT count(*) FROM cstore.cstore_stripes a, pg_class b +WHERE a.relfilenode = b.relfilenode AND b.relname = 't'; + count +------- + 0 +(1 row) + +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +SELECT count(*) FROM t; + count +------- + 10 +(1 row) + +SELECT count(*) FROM cstore.cstore_stripes a, pg_class b +WHERE a.relfilenode = b.relfilenode AND b.relname = 't'; + count +------- + 1 +(1 row) + +-- savepoint rollback +BEGIN; +SAVEPOINT s0; +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +SAVEPOINT s1; +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +SELECT count(*) FROM t; + count +------- + 30 +(1 row) + +ROLLBACK TO SAVEPOINT s1; +SELECT count(*) FROM t; + count +------- + 20 +(1 row) + +ROLLBACK TO SAVEPOINT s0; +SELECT count(*) FROM t; + count +------- + 10 +(1 row) + +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +COMMIT; +SELECT count(*) FROM t; + count +------- + 20 +(1 row) + +SELECT count(*) FROM cstore.cstore_stripes a, pg_class b +WHERE a.relfilenode = b.relfilenode AND b.relname = 't'; + count +------- + 2 +(1 row) + +DROP FOREIGN TABLE t; diff --git a/sql/am_rollback.sql b/sql/am_rollback.sql new file mode 100644 index 000000000..da1cc8ce4 --- /dev/null +++ b/sql/am_rollback.sql @@ -0,0 +1,41 @@ +-- +-- Testing we handle rollbacks properly +-- + +CREATE TABLE t(a int, b int) USING cstore_tableam; + +BEGIN; +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +ROLLBACK; +SELECT count(*) FROM t; + +-- check stripe metadata also have been rolled-back +SELECT count(*) FROM cstore.cstore_stripes a, pg_class b +WHERE a.relfilenode = b.relfilenode AND b.relname = 't'; + +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +SELECT count(*) FROM t; + +SELECT count(*) FROM cstore.cstore_stripes a, pg_class b +WHERE a.relfilenode = b.relfilenode AND b.relname = 't'; + +-- savepoint rollback +BEGIN; +SAVEPOINT s0; +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +SAVEPOINT s1; +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +SELECT count(*) FROM t; +ROLLBACK TO SAVEPOINT s1; +SELECT count(*) FROM t; +ROLLBACK TO SAVEPOINT s0; +SELECT count(*) FROM t; +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +COMMIT; + +SELECT count(*) FROM t; + +SELECT count(*) FROM cstore.cstore_stripes a, pg_class b +WHERE a.relfilenode = b.relfilenode AND b.relname = 't'; + +DROP TABLE t; diff --git a/sql/fdw_rollback.sql b/sql/fdw_rollback.sql new file mode 100644 index 000000000..804868ac9 --- /dev/null +++ b/sql/fdw_rollback.sql @@ -0,0 +1,41 @@ +-- +-- Testing we handle rollbacks properly +-- + +CREATE FOREIGN TABLE t(a int, b int) SERVER cstore_server; + +BEGIN; +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +ROLLBACK; +SELECT count(*) FROM t; + +-- check stripe metadata also have been rolled-back +SELECT count(*) FROM cstore.cstore_stripes a, pg_class b +WHERE a.relfilenode = b.relfilenode AND b.relname = 't'; + +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +SELECT count(*) FROM t; + +SELECT count(*) FROM cstore.cstore_stripes a, pg_class b +WHERE a.relfilenode = b.relfilenode AND b.relname = 't'; + +-- savepoint rollback +BEGIN; +SAVEPOINT s0; +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +SAVEPOINT s1; +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +SELECT count(*) FROM t; +ROLLBACK TO SAVEPOINT s1; +SELECT count(*) FROM t; +ROLLBACK TO SAVEPOINT s0; +SELECT count(*) FROM t; +INSERT INTO t SELECT i, i+1 FROM generate_series(1, 10) i; +COMMIT; + +SELECT count(*) FROM t; + +SELECT count(*) FROM cstore.cstore_stripes a, pg_class b +WHERE a.relfilenode = b.relfilenode AND b.relname = 't'; + +DROP FOREIGN TABLE t;