From 828e4416bd8582f24802f48bde1e05a1d656988a Mon Sep 17 00:00:00 2001 From: Craig Ringer Date: Mon, 6 Jul 2015 16:35:48 +0800 Subject: [PATCH] Add function to clear sequence's amdata Function bdr.bdr_internal_sequence_reset_cache(regclass) sets the amdata of the sequence to NULL and schedules sequencer wakeup. This is first step for implementing GH #101. Backport to 0.9.2 --- Makefile.in | 13 ++++- bdr.control | 2 +- bdr.h | 4 -- bdr_seq.c | 88 ++++++++++++++++++++++++++++++++ expected/dml/sequence.out | 45 ++++++++++++++++ expected/upgrade.out | 5 +- extsql/bdr--0.9.1.0--0.9.2.0.sql | 15 ++++++ sql/dml/sequence.sql | 31 +++++++++++ sql/upgrade.sql | 4 ++ 9 files changed, 199 insertions(+), 8 deletions(-) create mode 100644 expected/dml/sequence.out create mode 100644 extsql/bdr--0.9.1.0--0.9.2.0.sql create mode 100644 sql/dml/sequence.sql diff --git a/Makefile.in b/Makefile.in index 42f3a81b12..1d17787099 100644 --- a/Makefile.in +++ b/Makefile.in @@ -26,7 +26,8 @@ DATA = \ extsql/bdr--0.9.0.2--0.9.0.3.sql \ extsql/bdr--0.9.0.3--0.9.0.4.sql \ extsql/bdr--0.9.0.4--0.9.0.5.sql \ - extsql/bdr--0.9.0.5--0.9.1.0.sql + extsql/bdr--0.9.0.5--0.9.1.0.sql \ + extsql/bdr--0.9.1.0--0.9.2.0.sql DATA_built = \ extsql/bdr--0.8.0.1.sql \ @@ -42,7 +43,8 @@ DATA_built = \ extsql/bdr--0.9.0.3.sql \ extsql/bdr--0.9.0.4.sql \ extsql/bdr--0.9.0.5.sql \ - extsql/bdr--0.9.1.0.sql + extsql/bdr--0.9.1.0.sql \ + extsql/bdr--0.9.2.0.sql DOCS = bdr.conf.sample README.bdr SCRIPTS = scripts/bdr_initial_load bdr_init_copy bdr_resetxlog bdr_dump @@ -178,6 +180,10 @@ extsql/bdr--0.9.1.0.sql: extsql/bdr--0.9.0.5.sql extsql/bdr--0.9.0.5--0.9.1.0.sq mkdir -p extsql cat $^ > $@ +extsql/bdr--0.9.2.0.sql: extsql/bdr--0.9.1.0.sql extsql/bdr--0.9.1.0--0.9.2.0.sql + mkdir -p extsql + cat $^ > $@ + bdr_resetxlog: pg_resetxlog.o $(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(libpq_pgport) $(LIBS) -o $@$(X) @@ -227,11 +233,13 @@ check: regresscheck isolationcheck DDLREGRESSCHECKS=ddl/enable_ddl ddl/create ddl/alter_table ddl/extension ddl/function \ ddl/grant ddl/mixed ddl/namespace ddl/replication_set \ ddl/sequence ddl/view ddl/disable_ddl +EXTRAREGRESSCHECKS=dml/sequence REGRESSINIT=init_bdr REGRESSTEARDOWN=part_bdr else check: regresscheck DDLREGRESSCHECKS= +EXTRAREGRESSCHECKS= REGRESSINIT=init_udr REGRESSTEARDOWN=part_udr endif @@ -246,6 +254,7 @@ REGRESSCHECKS= \ pause \ $(DDLREGRESSCHECKS) \ dml/basic dml/contrib dml/delete_pk dml/extended dml/missing_pk dml/toasted \ + $(EXTRAREGRESSCHECKS) \ $(REGRESSTEARDOWN) diff --git a/bdr.control b/bdr.control index aae2525bed..65ab28d2a3 100644 --- a/bdr.control +++ b/bdr.control @@ -1,6 +1,6 @@ # bdr extension comment = 'Bi-directional replication for PostgreSQL' -default_version = '0.9.1.0' +default_version = '0.9.2.0' module_pathname = '$libdir/bdr' relocatable = false requires = btree_gist diff --git a/bdr.h b/bdr.h index fbb7abdf6f..b700e351df 100644 --- a/bdr.h +++ b/bdr.h @@ -424,10 +424,6 @@ extern void bdr_sequencer_fill_sequences(void); extern void bdr_sequencer_wakeup(void); extern void bdr_schedule_eoxact_sequencer_wakeup(void); - -PGDLLEXPORT extern Datum bdr_sequence_alloc(PG_FUNCTION_ARGS); -PGDLLEXPORT extern Datum bdr_sequence_setval(PG_FUNCTION_ARGS); -PGDLLEXPORT extern Datum bdr_sequence_options(PG_FUNCTION_ARGS); #endif extern int bdr_sequencer_get_next_free_slot(void); //XXX PERDB temp diff --git a/bdr_seq.c b/bdr_seq.c index 69a8a778d4..344039ec67 100644 --- a/bdr_seq.c +++ b/bdr_seq.c @@ -32,6 +32,7 @@ #include "executor/spi.h" #include "utils/builtins.h" +#include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/snapmgr.h" @@ -464,6 +465,10 @@ bdr_sequencer_shmem_init(int sequencers) prev_shmem_startup_hook = shmem_startup_hook; shmem_startup_hook = bdr_sequencer_shmem_startup; + /* + * We do the reloptions initialization here because this function is called + * at startup for every backend. + */ bdr_seq_relopt_kind = add_reloption_kind(); add_int_reloption(bdr_seq_relopt_kind, "cache_chunks", "Sets how many chunks shoult be cached on each node.", @@ -1322,3 +1327,86 @@ bdr_sequence_options(PG_FUNCTION_ARGS) PG_RETURN_NULL(); } + + +/* + * Resets the sequence cache, needed for initialization from binary clone. + */ +PGDLLEXPORT Datum bdr_internal_sequence_reset_cache(PG_FUNCTION_ARGS); + +PG_FUNCTION_INFO_V1(bdr_internal_sequence_reset_cache); + +Datum +bdr_internal_sequence_reset_cache(PG_FUNCTION_ARGS) +{ + Oid seqoid = PG_GETARG_OID(0); + Buffer buf; + SeqTable elm; + Relation rel; + HeapTupleData seqtuple; + Datum values[SEQ_COL_LASTCOL]; + bool nulls[SEQ_COL_LASTCOL]; + HeapTuple newtup; + Page page, temppage; + + /* lock page, fill heaptup */ + init_sequence(seqoid, &elm, &rel); + (void) read_seq_tuple(elm, rel, &buf, &seqtuple); + + /* get values */ + heap_deform_tuple(&seqtuple, RelationGetDescr(rel), + values, nulls); + + /* if already null nothing needs to be done */ + if (nulls[SEQ_COL_AMDATA - 1]) + goto done_with_sequence; + + /* otherwise create new tuple with null amdata and save it */ + nulls[SEQ_COL_AMDATA - 1] = true; + newtup = heap_form_tuple(RelationGetDescr(rel), values, nulls); + + /* special requirements for sequence tuples */ + HeapTupleHeaderSetXmin(newtup->t_data, FrozenTransactionId); + HeapTupleHeaderSetXminFrozen(newtup->t_data); + HeapTupleHeaderSetCmin(newtup->t_data, FirstCommandId); + HeapTupleHeaderSetXmax(newtup->t_data, InvalidTransactionId); + newtup->t_data->t_infomask |= HEAP_XMAX_INVALID; + ItemPointerSet(&newtup->t_data->t_ctid, 0, FirstOffsetNumber); + + page = BufferGetPage(buf); + temppage = PageGetTempPage(page); + + /* replace page contents, the direct way */ + PageInit(temppage, BufferGetPageSize(buf), PageGetSpecialSize(page)); + memcpy(PageGetSpecialPointer(temppage), + PageGetSpecialPointer(page), + PageGetSpecialSize(page)); + + if (PageAddItem(temppage, (Item) newtup->t_data, newtup->t_len, + FirstOffsetNumber, false, false) == InvalidOffsetNumber) + elog(PANIC, "reset_sequence_cache: failed to add item to page"); + + PageSetLSN(temppage, PageGetLSN(page)); + + START_CRIT_SECTION(); + + MarkBufferDirty(buf); + + memcpy(page, temppage, BufferGetPageSize(buf)); + + seqtuple.t_len = newtup->t_len; + + log_sequence_tuple(rel, &seqtuple, page); + + END_CRIT_SECTION(); + +done_with_sequence: + + UnlockReleaseBuffer(buf); + heap_close(rel, NoLock); + + bdr_sequencer_wakeup(); + bdr_schedule_eoxact_sequencer_wakeup(); + + PG_RETURN_VOID(); +} diff --git a/expected/dml/sequence.out b/expected/dml/sequence.out new file mode 100644 index 0000000000..461e4f7600 --- /dev/null +++ b/expected/dml/sequence.out @@ -0,0 +1,45 @@ +CREATE SEQUENCE bdr_test_seq USING bdr; +SELECT pg_xlog_wait_remote_apply(pg_current_xlog_location(), 0); + pg_xlog_wait_remote_apply +--------------------------- + +(1 row) + +DO $$ +BEGIN + LOOP + IF (SELECT amdata IS NOT NULL FROM bdr_test_seq) THEN + EXIT; + END IF; + PERFORM pg_sleep(0.1); + END LOOP; +END;$$; +CREATE TEMP TABLE bdr_test_seq_val AS SELECT nextval('bdr_test_seq') as last_val; +SELECT bdr.bdr_internal_sequence_reset_cache('bdr_test_seq'::regclass); + bdr_internal_sequence_reset_cache +----------------------------------- + +(1 row) + +SELECT amdata IS NULL FROM bdr_test_seq; + ?column? +---------- + t +(1 row) + +DO $$ +BEGIN + LOOP + IF (SELECT amdata IS NOT NULL FROM bdr_test_seq) THEN + EXIT; + END IF; + PERFORM pg_sleep(0.1); + END LOOP; +END;$$; +-- 10000 is maximum cache size in amdata +SELECT nextval('bdr_test_seq') >= last_val + 10000 FROM bdr_test_seq_val; + ?column? +---------- + t +(1 row) + diff --git a/expected/upgrade.out b/expected/upgrade.out index 35a391544a..3c10589e49 100644 --- a/expected/upgrade.out +++ b/expected/upgrade.out @@ -37,6 +37,8 @@ CREATE EXTENSION bdr VERSION '0.9.0.5'; DROP EXTENSION bdr; CREATE EXTENSION bdr VERSION '0.9.1.0'; DROP EXTENSION bdr; +CREATE EXTENSION bdr VERSION '0.9.2.0'; +DROP EXTENSION bdr; -- evolve version one by one from the oldest to the newest one CREATE EXTENSION bdr VERSION '0.8.0'; ALTER EXTENSION bdr UPDATE TO '0.8.0.1'; @@ -53,8 +55,9 @@ ALTER EXTENSION bdr UPDATE TO '0.9.0.3'; ALTER EXTENSION bdr UPDATE TO '0.9.0.4'; ALTER EXTENSION bdr UPDATE TO '0.9.0.5'; ALTER EXTENSION bdr UPDATE TO '0.9.1.0'; +ALTER EXTENSION bdr UPDATE TO '0.9.2.0'; -- Should never have to do anything: You missed adding the new version above. ALTER EXTENSION bdr UPDATE; -NOTICE: version "0.9.1.0" of extension "bdr" is already installed +NOTICE: version "0.9.2.0" of extension "bdr" is already installed \c postgres DROP DATABASE extension_upgrade; diff --git a/extsql/bdr--0.9.1.0--0.9.2.0.sql b/extsql/bdr--0.9.1.0--0.9.2.0.sql new file mode 100644 index 0000000000..f870764cf6 --- /dev/null +++ b/extsql/bdr--0.9.1.0--0.9.2.0.sql @@ -0,0 +1,15 @@ +SET LOCAL search_path = bdr; +SET bdr.permit_unsafe_ddl_commands = true; +SET bdr.skip_ddl_replication = true; + +-- +-- This is the same file as extsql/bdr--0.10.0.5--0.10.0.6.sql +-- in 0.10.0. It's safe to run twice. +-- + +CREATE OR REPLACE FUNCTION bdr.bdr_internal_sequence_reset_cache(seq regclass) +RETURNS void LANGUAGE c AS 'MODULE_PATHNAME' STRICT; + +RESET bdr.permit_unsafe_ddl_commands; +RESET bdr.skip_ddl_replication; +RESET search_path; diff --git a/sql/dml/sequence.sql b/sql/dml/sequence.sql new file mode 100644 index 0000000000..6084dd4514 --- /dev/null +++ b/sql/dml/sequence.sql @@ -0,0 +1,31 @@ +CREATE SEQUENCE bdr_test_seq USING bdr; + +SELECT pg_xlog_wait_remote_apply(pg_current_xlog_location(), 0); + +DO $$ +BEGIN + LOOP + IF (SELECT amdata IS NOT NULL FROM bdr_test_seq) THEN + EXIT; + END IF; + PERFORM pg_sleep(0.1); + END LOOP; +END;$$; + +CREATE TEMP TABLE bdr_test_seq_val AS SELECT nextval('bdr_test_seq') as last_val; + +SELECT bdr.bdr_internal_sequence_reset_cache('bdr_test_seq'::regclass); +SELECT amdata IS NULL FROM bdr_test_seq; + +DO $$ +BEGIN + LOOP + IF (SELECT amdata IS NOT NULL FROM bdr_test_seq) THEN + EXIT; + END IF; + PERFORM pg_sleep(0.1); + END LOOP; +END;$$; + +-- 10000 is maximum cache size in amdata +SELECT nextval('bdr_test_seq') >= last_val + 10000 FROM bdr_test_seq_val; diff --git a/sql/upgrade.sql b/sql/upgrade.sql index 191378f8c2..d9bebdfd85 100644 --- a/sql/upgrade.sql +++ b/sql/upgrade.sql @@ -54,6 +54,9 @@ DROP EXTENSION bdr; CREATE EXTENSION bdr VERSION '0.9.1.0'; DROP EXTENSION bdr; +CREATE EXTENSION bdr VERSION '0.9.2.0'; +DROP EXTENSION bdr; + -- evolve version one by one from the oldest to the newest one CREATE EXTENSION bdr VERSION '0.8.0'; ALTER EXTENSION bdr UPDATE TO '0.8.0.1'; @@ -70,6 +73,7 @@ ALTER EXTENSION bdr UPDATE TO '0.9.0.3'; ALTER EXTENSION bdr UPDATE TO '0.9.0.4'; ALTER EXTENSION bdr UPDATE TO '0.9.0.5'; ALTER EXTENSION bdr UPDATE TO '0.9.1.0'; +ALTER EXTENSION bdr UPDATE TO '0.9.2.0'; -- Should never have to do anything: You missed adding the new version above. ALTER EXTENSION bdr UPDATE; -- 2.39.5