Re: RangeVarGetRelid()

From: Robert Haas <robertmhaas(at)gmail(dot)com>
To: Noah Misch <noah(at)leadboat(dot)com>
Cc: Alvaro Herrera <alvherre(at)commandprompt(dot)com>, Pg Hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: RangeVarGetRelid()
Date: 2011-11-24 15:54:50
Message-ID: CA+TgmoaU=O+BAh+etOirGd35MVmQd3DrEXduiP+LY-S2nKs5ag@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Fri, Nov 18, 2011 at 9:12 AM, Noah Misch <noah(at)leadboat(dot)com> wrote:
> Good call.

All right, here's an updated patch, and a couple of follow-on patches.

I updated the main patch (rangevargetrelid-callback-v2.patch) per
previous discussion. I also added a "callback_arg" argument to the
RangeVarGetRelidExtended(), because it's a law of nature that all
callback functions need such a thing, and this case proved to be no
exception: the old version of the REINDEX INDEX callback was flaky,
since it assumed that the index it locked during one iteration would
still exist during the next iteration, which won't be true when the
retry is caused by the index having been concurrently dropped. There
were some other bugs as well, which I believe I've now fixed.

fix-lock-table.patch applies over rangevargetrelid-callback-v2.patch
and adjusts LOCK TABLE so that we never obtain a relation lock before
validating that the object is a table and we have permission to lock
it. fix-drop-relation.patch applies over that, and makes similar
corrections to the logic for DROP TABLE/INDEX/SEQUENCE/VIEW/FOREIGN
TABLE. This means that it's no longer possible to use these commands
to launch a denial-of-service attack against a table you have no
rights to. Sadly, there are a bunch of other commands that can be
used the same way. I'd like to fix them all, but it's a decent amount
of work, so I'm working through them one at a time.

In the case of DROP, this also improves handling of concurrent DROP,
DROP-and-CREATE, RENAME-and-CREATE, and similar situations. For
example, in unpatched master:

rhaas=# create table t (a int);
CREATE TABLE
rhaas=# begin;
BEGIN
rhaas=# drop table t;
DROP TABLE
rhaas=# create table t (b int);
CREATE TABLE

And then, from another session:

rhaas=# drop table t;

When the first session commits, you get something like this:

ERROR: cache lookup failed for relation 16401

With these patches, that goes away: the concurrent DROP correctly sees
the new relation and drops that one. Or, if the concurrent
transaction just does a DROP rather than a DROP-and-CREATE, then you
get an error - but instead of a somewhat incomprehensible complaint
about a cache lookup having failed, you get the same error you would
have gotten had the relation not existed in the first place:

ERROR: table "t" does not exist

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

Attachment Content-Type Size
rangevargetrelid-callback-v2.patch application/octet-stream 21.9 KB
fix-lock-table.patch application/octet-stream 6.6 KB
fix-drop-relation.patch application/octet-stream 6.3 KB

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Theo Schlossnagle 2011-11-24 16:33:31 Re: logging in high performance systems.
Previous Message Bruce Momjian 2011-11-24 15:26:41 Re: pg_upgrade relation OID mismatches