1
0
mirror of https://github.com/postgres/postgres.git synced 2025-10-18 04:29:09 +03:00

Fix ALTER SEQUENCE locking

In 1753b1b027, the pg_sequence system
catalog was introduced.  This made sequence metadata changes
transactional, while the actual sequence values are still behaving
nontransactionally.  This requires some refinement in how ALTER
SEQUENCE, which operates on both, locks the sequence and the catalog.

The main problems were:

- Concurrent ALTER SEQUENCE causes "tuple concurrently updated" error,
  caused by updates to pg_sequence catalog.

- Sequence WAL writes and catalog updates are not protected by same
  lock, which could lead to inconsistent recovery order.

- nextval() disregarding uncommitted ALTER SEQUENCE changes.

To fix, nextval() and friends now lock the sequence using
RowExclusiveLock instead of AccessShareLock.  ALTER SEQUENCE locks the
sequence using ShareRowExclusiveLock.  This means that nextval() and
ALTER SEQUENCE block each other, and ALTER SEQUENCE on the same sequence
blocks itself.  (This was already the case previously for the OWNER TO,
RENAME, and SET SCHEMA variants.)  Also, rearrange some code so that the
entire AlterSequence is protected by the lock on the sequence.

As an exception, use reduced 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.

Reviewed-by: Michael Paquier <michael.paquier@gmail.com>
Reported-by: Jason Petersen <jason@citusdata.com>
Reported-by: Andres Freund <andres@anarazel.de>
This commit is contained in:
Peter Eisentraut
2017-05-09 23:35:31 -04:00
parent b1c45afb01
commit f8dc1985fd
5 changed files with 180 additions and 21 deletions

View File

@@ -0,0 +1,39 @@
# Test sequence usage and concurrent sequence DDL
setup
{
CREATE SEQUENCE seq1;
}
teardown
{
DROP SEQUENCE seq1;
}
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"
step "s2begin" { BEGIN; }
step "s2nv" { SELECT nextval('seq1') FROM generate_series(1, 15); }
step "s2commit" { COMMIT; }
permutation "s1alter" "s1commit" "s2nv"
# Prior to PG10, the s2nv would see the uncommitted s1alter change,
# but now it waits.
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"