1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-25 01:02:05 +03:00

Implement SKIP LOCKED for row-level locks

This clause changes the behavior of SELECT locking clauses in the
presence of locked rows: instead of causing a process to block waiting
for the locks held by other processes (or raise an error, with NOWAIT),
SKIP LOCKED makes the new reader skip over such rows.  While this is not
appropriate behavior for general purposes, there are some cases in which
it is useful, such as queue-like tables.

Catalog version bumped because this patch changes the representation of
stored rules.

Reviewed by Craig Ringer (based on a previous attempt at an
implementation by Simon Riggs, who also provided input on the syntax
used in the current patch), David Rowley, and Álvaro Herrera.

Author: Thomas Munro
This commit is contained in:
Alvaro Herrera
2014-10-07 17:23:34 -03:00
parent c421efd213
commit df630b0dd5
38 changed files with 907 additions and 121 deletions

View File

@ -2358,7 +2358,7 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
allrels = makeNode(LockingClause);
allrels->lockedRels = NIL; /* indicates all rels */
allrels->strength = lc->strength;
allrels->noWait = lc->noWait;
allrels->waitPolicy = lc->waitPolicy;
if (lockedRels == NIL)
{
@ -2372,13 +2372,13 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
switch (rte->rtekind)
{
case RTE_RELATION:
applyLockingClause(qry, i,
lc->strength, lc->noWait, pushedDown);
applyLockingClause(qry, i, lc->strength, lc->waitPolicy,
pushedDown);
rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
break;
case RTE_SUBQUERY:
applyLockingClause(qry, i,
lc->strength, lc->noWait, pushedDown);
applyLockingClause(qry, i, lc->strength, lc->waitPolicy,
pushedDown);
/*
* FOR UPDATE/SHARE of subquery is propagated to all of
@ -2424,15 +2424,13 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
switch (rte->rtekind)
{
case RTE_RELATION:
applyLockingClause(qry, i,
lc->strength, lc->noWait,
pushedDown);
applyLockingClause(qry, i, lc->strength,
lc->waitPolicy, pushedDown);
rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
break;
case RTE_SUBQUERY:
applyLockingClause(qry, i,
lc->strength, lc->noWait,
pushedDown);
applyLockingClause(qry, i, lc->strength,
lc->waitPolicy, pushedDown);
/* see comment above */
transformLockingClause(pstate, rte->subquery,
allrels, true);
@ -2499,7 +2497,8 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
*/
void
applyLockingClause(Query *qry, Index rtindex,
LockClauseStrength strength, bool noWait, bool pushedDown)
LockClauseStrength strength, LockWaitPolicy waitPolicy,
bool pushedDown)
{
RowMarkClause *rc;
@ -2516,15 +2515,20 @@ applyLockingClause(Query *qry, Index rtindex,
* a shared and exclusive lock at the same time; it'll end up being
* exclusive anyway.)
*
* We also consider that NOWAIT wins if it's specified both ways. This
* is a bit more debatable but raising an error doesn't seem helpful.
* (Consider for instance SELECT FOR UPDATE NOWAIT from a view that
* internally contains a plain FOR UPDATE spec.)
* Similarly, if the same RTE is specified with more than one lock wait
* policy, consider that NOWAIT wins over SKIP LOCKED, which in turn
* wins over waiting for the lock (the default). This is a bit more
* debatable but raising an error doesn't seem helpful. (Consider for
* instance SELECT FOR UPDATE NOWAIT from a view that internally
* contains a plain FOR UPDATE spec.) Having NOWAIT win over SKIP
* LOCKED is reasonable since the former throws an error in case of
* coming across a locked tuple, which may be undesirable in some cases
* but it seems better than silently returning inconsistent results.
*
* And of course pushedDown becomes false if any clause is explicit.
*/
rc->strength = Max(rc->strength, strength);
rc->noWait |= noWait;
rc->waitPolicy = Max(rc->waitPolicy, waitPolicy);
rc->pushedDown &= pushedDown;
return;
}
@ -2533,7 +2537,7 @@ applyLockingClause(Query *qry, Index rtindex,
rc = makeNode(RowMarkClause);
rc->rti = rtindex;
rc->strength = strength;
rc->noWait = noWait;
rc->waitPolicy = waitPolicy;
rc->pushedDown = pushedDown;
qry->rowMarks = lappend(qry->rowMarks, rc);
}

View File

@ -284,6 +284,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <boolean> opt_force opt_or_replace
opt_grant_grant_option opt_grant_admin_option
opt_nowait opt_if_exists opt_with_data
%type <ival> opt_nowait_or_skip
%type <list> OptRoleList AlterOptRoleList
%type <defelt> CreateOptRoleElem AlterOptRoleElem
@ -582,7 +583,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
LABEL LANGUAGE LARGE_P LAST_P LATERAL_P
LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL
LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P LOGGED
LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P LOCKED LOGGED
MAPPING MATCH MATERIALIZED MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
@ -606,7 +607,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES
SERIALIZABLE SERVER SESSION SESSION_USER SET SETOF SHARE
SHOW SIMILAR SIMPLE SMALLINT SNAPSHOT SOME STABLE STANDALONE_P START
SHOW SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME STABLE STANDALONE_P START
STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING
SYMMETRIC SYSID SYSTEM_P
@ -9370,6 +9371,12 @@ opt_nowait: NOWAIT { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
opt_nowait_or_skip:
NOWAIT { $$ = LockWaitError; }
| SKIP LOCKED { $$ = LockWaitSkip; }
| /*EMPTY*/ { $$ = LockWaitBlock; }
;
/*****************************************************************************
*
@ -10011,12 +10018,12 @@ for_locking_items:
;
for_locking_item:
for_locking_strength locked_rels_list opt_nowait
for_locking_strength locked_rels_list opt_nowait_or_skip
{
LockingClause *n = makeNode(LockingClause);
n->lockedRels = $2;
n->strength = $1;
n->noWait = $3;
n->waitPolicy = $3;
$$ = (Node *) n;
}
;
@ -13145,6 +13152,7 @@ unreserved_keyword:
| LOCAL
| LOCATION
| LOCK_P
| LOCKED
| LOGGED
| MAPPING
| MATCH
@ -13229,6 +13237,7 @@ unreserved_keyword:
| SHARE
| SHOW
| SIMPLE
| SKIP
| SNAPSHOT
| STABLE
| STANDALONE_P