Add function to clear sequence's amdata
authorCraig Ringer <craig@2ndquadrant.com>
Mon, 6 Jul 2015 08:35:48 +0000 (16:35 +0800)
committerCraig Ringer <craig@2ndquadrant.com>
Mon, 6 Jul 2015 09:04:48 +0000 (17:04 +0800)
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
bdr.control
bdr.h
bdr_seq.c
expected/dml/sequence.out [new file with mode: 0644]
expected/upgrade.out
extsql/bdr--0.9.1.0--0.9.2.0.sql [new file with mode: 0644]
sql/dml/sequence.sql [new file with mode: 0644]
sql/upgrade.sql

index 42f3a81b12514b7826aa2f653dc858602b344ca6..1d1778709917a808be2c3931863ff2d2679f9cae 100644 (file)
@@ -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)
 
 
index aae2525bed293f60c835b3e698e7463aebe65f1a..65ab28d2a3a6c5b0a62482925ce3a09d4a3799b8 100644 (file)
@@ -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 fbb7abdf6fe3286c41eb57d3e9cf1abefb360a3b..b700e351df5e6465940cb36177ce2cfa1f3846d9 100644 (file)
--- 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
index 69a8a778d4c95607bd705938bcb80cc485087050..344039ec67051b2dd6fbe5cf146cb34da731f518 100644 (file)
--- 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 (file)
index 0000000..461e4f7
--- /dev/null
@@ -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)
+
index 35a391544a68bf71a7becc61275833a00cb4b710..3c10589e49bdc1ca4eb2f770f9a46d064954ca4d 100644 (file)
@@ -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 (file)
index 0000000..f870764
--- /dev/null
@@ -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 (file)
index 0000000..6084dd4
--- /dev/null
@@ -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;
index 191378f8c243abb2555d941d3e0b2a9500c76319..d9bebdfd85fb1417d4eb55df75a0673eb42a713d 100644 (file)
@@ -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;