Several objects have issues where you can drop them while a dependent is
being created -- a good example is Domains (and types in general) -- but
I'll hunt down others later (languages?). The solution (as Tom stated
earlier) is to create a more generic lock tag.
1. Modify LOCKTAG to include 'classId'. Rename 'relId' to 'objId', and
rename 'objId' to 'objsubId' -- very similar to dependency tracking.
Expands locktag by sizeof(Oid), but also allows locking anything that we
can attach a dependency to. If it wasn't for Page locks, objId could be
a part of the union with xid.
typedef struct LOCKTAG
{Oid objId;Oid classId;Oid dbId;union{ BlockNumber blkno; TransactionId xid;}
objsubId;
/* * offnum should be part of objId.tupleId above, but would increase * sizeof(LOCKTAG) and so moved here; currently
usedby userlocks * only. */OffsetNumber offnum;
uint16 lockmethod; /* needed by userlocks */
} LOCKTAG;
2. Modify current locks to set classId to RelOid_pg_class in most
cases. Transaction locks will set classId to XactLockTableId and objId
to InvalidOid.
3. Generate two new lock functions which allow locking of an arbitrary
classId with the intent that they will be used to lock / unlock
non-relation or transaction oriented locks (none of the current locks).
The lock functions will only deal with 'AccessShare' and
'AccessExclusive' locks -- others will be rejected.
4. Lock problematic Type / Domain areas (classId RelOid_pg_type):
ALTER TABLE .. [ ADD | ALTER | DROP ] COLUMN (AccessShareLock)
CREATE TABLE -- one per column (AccessShareLock)
SELECT -- one per column in query (AccessShareLock)
DROP DOMAIN / DROP TYPE (AccessExclusive)
ALTER DOMAIN (AccessExclusive)
Since the below aren't visible, they don't require a lock:
CREATE DOMAIN / CREATE TYPE (AccessExclusive)
5. Continue the process with schemas, languages, casts, etc. All of
which can be dropped while another entity is being created that uses it.
PSQL 1: CREATE SCHEMA sch;
PSQL 1: BEGIN; CREATE TABLE sch.tab (col integer);
PSQL 2: DROP SCHEMA sch;
PSQL 1: COMMIT; -- Table tab is missing a schema entry.
The above works with almost all database objects that are not relations
(tables, views, indexes, sequences should be fine).
Potential Problems:
- This will add a huge number of 'AccessShare' locks, as every select
will need to lock the types, casts, etc. involved.
- You don't need to lock on pinned objects like the 'integer' type as
it's guarenteed not be to dropped. If we create an ALTER TYPE command
this changes. Do we kill a syscache lookup to prevent the lock --
probably not -- but it makes the above mentioned AccessShareLock count
much larger.
--
Rod Taylor <rbt@rbt.ca>
PGP Key: http://www.rbt.ca/rbtpub.asc