From 1f7c6b489664b52764b131d303915e175c3e5299 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter_e@gmx.net>
Date: Wed, 10 May 2017 00:44:51 -0400
Subject: [PATCH 3/3] Reduce locking for ALTER SEQUENCE ... RESTART

Since that is basically a setval(), it does not require the full locking
of other ALTER SEQUENCE actions.  So check whether we are only running a
RESTART and run with less locking if so.
---
 src/backend/commands/sequence.c              | 27 +++++++++++++++-
 src/test/isolation/expected/sequence-ddl.out | 46 ++++++++++++++++++++++++++++
 src/test/isolation/specs/sequence-ddl.spec   |  7 +++++
 3 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 44cfcef66b..8d7979a22a 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -98,6 +98,7 @@ static void create_seq_hashtable(void);
 static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel);
 static Form_pg_sequence_data read_seq_tuple(Relation rel,
 			   Buffer *buf, HeapTuple seqdatatuple);
+static bool check_params_only_restart(List *options);
 static void init_params(ParseState *pstate, List *options, bool for_identity,
 						bool isInit,
 						Form_pg_sequence seqform,
@@ -427,7 +428,11 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt)
 	HeapTuple	tuple;
 
 	/* Open and lock sequence. */
-	relid = RangeVarGetRelid(stmt->sequence, ShareRowExclusiveLock, stmt->missing_ok);
+	relid = RangeVarGetRelid(stmt->sequence,
+							 (check_params_only_restart(stmt->options)
+							  ? RowExclusiveLock
+							  : ShareRowExclusiveLock),
+							 stmt->missing_ok);
 	if (relid == InvalidOid)
 	{
 		ereport(NOTICE,
@@ -1219,6 +1224,26 @@ read_seq_tuple(Relation rel, Buffer *buf, HeapTuple seqdatatuple)
 }
 
 /*
+ * Check the sequence options list.  Return true if only the RESTART option
+ * (or no option at all) is present.  This allows for less locking.
+ */
+static bool
+check_params_only_restart(List *options)
+{
+	ListCell   *option;
+
+	foreach(option, options)
+	{
+		DefElem    *defel = (DefElem *) lfirst(option);
+
+		if (strcmp(defel->defname, "restart") != 0)
+			return false;
+	}
+
+	return true;
+}
+
+/*
  * init_params: process the options list of CREATE or ALTER SEQUENCE, and
  * store the values into appropriate fields of seqform, for changes that go
  * into the pg_sequence catalog, and seqdataform for changes to the sequence
diff --git a/src/test/isolation/expected/sequence-ddl.out b/src/test/isolation/expected/sequence-ddl.out
index eb534c1006..6b7119738f 100644
--- a/src/test/isolation/expected/sequence-ddl.out
+++ b/src/test/isolation/expected/sequence-ddl.out
@@ -37,3 +37,49 @@ step s1alter2: ALTER SEQUENCE seq1 MAXVALUE 20; <waiting ...>
 step s2commit: COMMIT;
 step s1alter2: <... completed>
 step s1commit: COMMIT;
+
+starting permutation: s1restart s2nv s1commit
+step s1restart: ALTER SEQUENCE seq1 RESTART WITH 5;
+step s2nv: SELECT nextval('seq1') FROM generate_series(1, 15);
+nextval        
+
+5              
+6              
+7              
+8              
+9              
+10             
+11             
+12             
+13             
+14             
+15             
+16             
+17             
+18             
+19             
+step s1commit: COMMIT;
+
+starting permutation: s2begin s2nv s1restart s2commit s1commit
+step s2begin: BEGIN;
+step s2nv: SELECT nextval('seq1') FROM generate_series(1, 15);
+nextval        
+
+1              
+2              
+3              
+4              
+5              
+6              
+7              
+8              
+9              
+10             
+11             
+12             
+13             
+14             
+15             
+step s1restart: ALTER SEQUENCE seq1 RESTART WITH 5;
+step s2commit: COMMIT;
+step s1commit: COMMIT;
diff --git a/src/test/isolation/specs/sequence-ddl.spec b/src/test/isolation/specs/sequence-ddl.spec
index a9969252f2..42ee3b0615 100644
--- a/src/test/isolation/specs/sequence-ddl.spec
+++ b/src/test/isolation/specs/sequence-ddl.spec
@@ -14,6 +14,7 @@ session "s1"
 setup           { BEGIN; }
 step "s1alter"  { ALTER SEQUENCE seq1 MAXVALUE 10; }
 step "s1alter2" { ALTER SEQUENCE seq1 MAXVALUE 20; }
+step "s1restart" { ALTER SEQUENCE seq1 RESTART WITH 5; }
 step "s1commit" { COMMIT; }
 
 session "s2"
@@ -30,3 +31,9 @@ permutation "s1alter" "s2nv" "s1commit"
 # nextval doesn't release lock until transaction end, so s1alter2 has
 # to wait for s2commit.
 permutation "s2begin" "s2nv" "s1alter2" "s2commit" "s1commit"
+
+# RESTART is nontransactional, so s2nv sees it right away
+permutation "s1restart" "s2nv" "s1commit"
+
+# RESTART does not wait
+permutation "s2begin" "s2nv" "s1restart" "s2commit" "s1commit"
-- 
2.12.2

