diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2007-09-05 18:10:48 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2007-09-05 18:10:48 +0000 |
commit | 295e63983d7596ccc5717ff4a0a235ba241a2614 (patch) | |
tree | d4d8baaed4992dab3a4ae5110f765237da136cb3 /src/backend/utils/adt/lockfuncs.c | |
parent | 2e74c53ec1103f92c5704d87a4af2ab573402212 (diff) | |
download | postgresql-295e63983d7596ccc5717ff4a0a235ba241a2614.tar.gz postgresql-295e63983d7596ccc5717ff4a0a235ba241a2614.zip |
Implement lazy XID allocation: transactions that do not modify any database
rows will normally never obtain an XID at all. We already did things this way
for subtransactions, but this patch extends the concept to top-level
transactions. In applications where there are lots of short read-only
transactions, this should improve performance noticeably; not so much from
removal of the actual XID-assignments, as from reduction of overhead that's
driven by the rate of XID consumption. We add a concept of a "virtual
transaction ID" so that active transactions can be uniquely identified even
if they don't have a regular XID. This is a much lighter-weight concept:
uniqueness of VXIDs is only guaranteed over the short term, and no on-disk
record is made about them.
Florian Pflug, with some editorialization by Tom.
Diffstat (limited to 'src/backend/utils/adt/lockfuncs.c')
-rw-r--r-- | src/backend/utils/adt/lockfuncs.c | 86 |
1 files changed, 63 insertions, 23 deletions
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c index 2263a946039..e78d74f9efe 100644 --- a/src/backend/utils/adt/lockfuncs.c +++ b/src/backend/utils/adt/lockfuncs.c @@ -6,7 +6,7 @@ * Copyright (c) 2002-2007, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.28 2007/01/05 22:19:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.29 2007/09/05 18:10:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,6 +27,7 @@ static const char *const LockTagTypeNames[] = { "page", "tuple", "transactionid", + "virtualxid", "object", "userlock", "advisory" @@ -39,6 +40,27 @@ typedef struct int currIdx; /* current PROCLOCK index */ } PG_Lock_Status; + +/* + * VXIDGetDatum - Construct a text representation of a VXID + * + * This is currently only used in pg_lock_status, so we put it here. + */ +static Datum +VXIDGetDatum(BackendId bid, LocalTransactionId lxid) +{ + /* + * The representation is "<bid>/<lxid>", decimal and unsigned decimal + * respectively. Note that elog.c also knows how to format a vxid. + */ + char vxidstr[32]; + + snprintf(vxidstr, sizeof(vxidstr), "%d/%u", bid, lxid); + + return DirectFunctionCall1(textin, CStringGetDatum(vxidstr)); +} + + /* * pg_lock_status - produce a view with one row per held or awaited lock mode */ @@ -64,7 +86,7 @@ pg_lock_status(PG_FUNCTION_ARGS) /* build tupdesc for result tuples */ /* this had better match pg_locks view in system_views.sql */ - tupdesc = CreateTemplateTupleDesc(13, false); + tupdesc = CreateTemplateTupleDesc(14, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database", @@ -75,21 +97,23 @@ pg_lock_status(PG_FUNCTION_ARGS) INT4OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple", INT2OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 6, "transactionid", + TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid", XIDOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 7, "classid", + TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid", OIDOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 8, "objid", + TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid", OIDOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objsubid", + TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid", INT2OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 10, "transaction", - XIDOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 11, "pid", + TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction", + TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid", INT4OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 12, "mode", + TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode", TEXTOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 13, "granted", + TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted", BOOLOID, -1, 0); funcctx->tuple_desc = BlessTupleDesc(tupdesc); @@ -120,8 +144,8 @@ pg_lock_status(PG_FUNCTION_ARGS) LOCKMODE mode = 0; const char *locktypename; char tnbuf[32]; - Datum values[13]; - char nulls[13]; + Datum values[14]; + char nulls[14]; HeapTuple tuple; Datum result; @@ -193,7 +217,6 @@ pg_lock_status(PG_FUNCTION_ARGS) values[0] = DirectFunctionCall1(textin, CStringGetDatum(locktypename)); - switch (lock->tag.locktag_type) { case LOCKTAG_RELATION: @@ -206,6 +229,7 @@ pg_lock_status(PG_FUNCTION_ARGS) nulls[6] = 'n'; nulls[7] = 'n'; nulls[8] = 'n'; + nulls[9] = 'n'; break; case LOCKTAG_PAGE: values[1] = ObjectIdGetDatum(lock->tag.locktag_field1); @@ -216,6 +240,7 @@ pg_lock_status(PG_FUNCTION_ARGS) nulls[6] = 'n'; nulls[7] = 'n'; nulls[8] = 'n'; + nulls[9] = 'n'; break; case LOCKTAG_TUPLE: values[1] = ObjectIdGetDatum(lock->tag.locktag_field1); @@ -226,9 +251,22 @@ pg_lock_status(PG_FUNCTION_ARGS) nulls[6] = 'n'; nulls[7] = 'n'; nulls[8] = 'n'; + nulls[9] = 'n'; break; case LOCKTAG_TRANSACTION: - values[5] = TransactionIdGetDatum(lock->tag.locktag_field1); + values[6] = TransactionIdGetDatum(lock->tag.locktag_field1); + nulls[1] = 'n'; + nulls[2] = 'n'; + nulls[3] = 'n'; + nulls[4] = 'n'; + nulls[5] = 'n'; + nulls[7] = 'n'; + nulls[8] = 'n'; + nulls[9] = 'n'; + break; + case LOCKTAG_VIRTUALTRANSACTION: + values[5] = VXIDGetDatum(lock->tag.locktag_field1, + lock->tag.locktag_field2); nulls[1] = 'n'; nulls[2] = 'n'; nulls[3] = 'n'; @@ -236,31 +274,33 @@ pg_lock_status(PG_FUNCTION_ARGS) nulls[6] = 'n'; nulls[7] = 'n'; nulls[8] = 'n'; + nulls[9] = 'n'; break; case LOCKTAG_OBJECT: case LOCKTAG_USERLOCK: case LOCKTAG_ADVISORY: default: /* treat unknown locktags like OBJECT */ values[1] = ObjectIdGetDatum(lock->tag.locktag_field1); - values[6] = ObjectIdGetDatum(lock->tag.locktag_field2); - values[7] = ObjectIdGetDatum(lock->tag.locktag_field3); - values[8] = Int16GetDatum(lock->tag.locktag_field4); + values[7] = ObjectIdGetDatum(lock->tag.locktag_field2); + values[8] = ObjectIdGetDatum(lock->tag.locktag_field3); + values[9] = Int16GetDatum(lock->tag.locktag_field4); nulls[2] = 'n'; nulls[3] = 'n'; nulls[4] = 'n'; nulls[5] = 'n'; + nulls[6] = 'n'; break; } - values[9] = TransactionIdGetDatum(proc->xid); + values[10] = VXIDGetDatum(proc->backendId, proc->lxid); if (proc->pid != 0) - values[10] = Int32GetDatum(proc->pid); + values[11] = Int32GetDatum(proc->pid); else - nulls[10] = 'n'; - values[11] = DirectFunctionCall1(textin, + nulls[11] = 'n'; + values[12] = DirectFunctionCall1(textin, CStringGetDatum(GetLockmodeName(LOCK_LOCKMETHOD(*lock), mode))); - values[12] = BoolGetDatum(granted); + values[13] = BoolGetDatum(granted); tuple = heap_formtuple(funcctx->tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); |