Skip to content

Commit a933ee3

Browse files
committed
Change SearchSysCache coding conventions so that a reference count is
maintained for each cache entry. A cache entry will not be freed until the matching ReleaseSysCache call has been executed. This eliminates worries about cache entries getting dropped while still in use. See my posting to pg-hackers of even date for more info.
1 parent cff2384 commit a933ee3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+2645
-2287
lines changed

contrib/array/array_iterator.c

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,29 @@
1414
* either version 2, or (at your option) any later version.
1515
*/
1616

17+
#include "postgres.h"
18+
1719
#include <ctype.h>
1820
#include <stdio.h>
1921
#include <sys/types.h>
2022
#include <string.h>
2123

22-
#include "postgres.h"
23-
#include "miscadmin.h"
2424
#include "access/xact.h"
2525
#include "fmgr.h"
26-
#include "catalog/pg_type.h"
26+
#include "miscadmin.h"
2727
#include "utils/array.h"
2828
#include "utils/builtins.h"
2929
#include "utils/memutils.h"
30-
#include "utils/syscache.h"
30+
#include "utils/lsyscache.h"
3131

3232
#include "array_iterator.h"
3333

34+
3435
static int32
3536
array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value)
3637
{
37-
HeapTuple typ_tuple;
38-
Form_pg_type typ_struct;
38+
int16 typlen;
3939
bool typbyval;
40-
int typlen;
4140
int nitems,
4241
i;
4342
Datum result;
@@ -66,16 +65,7 @@ array_iterator(Oid elemtype, Oid proc, int and, ArrayType *array, Datum value)
6665
}
6766

6867
/* Lookup element type information */
69-
typ_tuple = SearchSysCacheTuple(TYPEOID, ObjectIdGetDatum(elemtype),
70-
0, 0, 0);
71-
if (!HeapTupleIsValid(typ_tuple))
72-
{
73-
elog(ERROR, "array_iterator: cache lookup failed for type %u", elemtype);
74-
return 0;
75-
}
76-
typ_struct = (Form_pg_type) GETSTRUCT(typ_tuple);
77-
typlen = typ_struct->typlen;
78-
typbyval = typ_struct->typbyval;
68+
get_typlenbyval(elemtype, &typlen, &typbyval);
7969

8070
/* Lookup the function entry point */
8171
fmgr_info(proc, &finfo);

doc/FAQ_DEV

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ c-mode)
311311
9) How do I efficiently access information in tables from the backend code?
312312

313313
You first need to find the tuples(rows) you are interested in. There
314-
are two ways. First, SearchSysCacheTuple() and related functions allow
314+
are two ways. First, SearchSysCache() and related functions allow
315315
you to query the system catalogs. This is the preferred way to access
316316
system tables, because the first call to the cache loads the needed
317317
rows, and future requests can return the results without accessing the
@@ -321,14 +321,13 @@ c-mode)
321321
src/backend/utils/cache/lsyscache.c contains many column-specific
322322
cache lookup functions.
323323

324-
The rows returned are cached-owned versions of the heap rows. They are
325-
invalidated when the base table changes. Because the cache is local to
326-
each backend, you may use the pointer returned from the cache for
327-
short periods without making a copy of the tuple. If you send the
328-
pointer into a large function that will be doing its own cache
329-
lookups, it is possible the cache entry may be flushed, so you should
330-
use SearchSysCacheTupleCopy() in these cases, and pfree() the tuple
331-
when you are done.
324+
The rows returned are cache-owned versions of the heap rows. Therefore,
325+
you must not modify or delete the tuple returned by SearchSysCache().
326+
What you *should* do is release it with ReleaseSysCache() when you are
327+
done using it; this informs the cache that it can discard that tuple
328+
if necessary. If you neglect to call ReleaseSysCache(), then the cache
329+
entry will remain locked in the cache until end of transaction, which is
330+
tolerable but not very desirable.
332331

333332
If you can't use the system cache, you will need to retrieve the data
334333
directly from the heap table, using the buffer cache that is shared by
@@ -344,7 +343,9 @@ c-mode)
344343
You can also use heap_fetch() to fetch rows by block number/offset.
345344
While scans automatically lock/unlock rows from the buffer cache, with
346345
heap_fetch(), you must pass a Buffer pointer, and ReleaseBuffer() it
347-
when completed. Once you have the row, you can get data that is common
346+
when completed.
347+
348+
Once you have the row, you can get data that is common
348349
to all tuples, like t_self and t_oid, by merely accessing the
349350
HeapTuple structure entries. If you need a table-specific column, you
350351
should take the HeapTuple pointer, and use the GETSTRUCT() macro to
@@ -355,15 +356,16 @@ c-mode)
355356

356357
((Form_pg_class) GETSTRUCT(tuple))->relnatts
357358

358-
You should not directly change live tuples in this way. The best way
359-
is to use heap_tuplemodify() and pass it your palloc'ed tuple, and the
360-
values you want changed. It returns another palloc'ed tuple, which you
359+
You must not directly change live tuples in this way. The best way
360+
is to use heap_modifytuple() and pass it your original tuple, and the
361+
values you want changed. It returns a palloc'ed tuple, which you
361362
pass to heap_replace(). You can delete tuples by passing the tuple's
362-
t_self to heap_destroy(). You can use it for heap_update() too.
363-
Remember, tuples can be either system cache versions, which may go
364-
away soon after you get them, buffer cache versions, which go away
365-
when you heap_getnext(), heap_endscan, or ReleaseBuffer(), in the
366-
heap_fetch() case. Or it may be a palloc'ed tuple, that you must
363+
t_self to heap_destroy(). You use t_self for heap_update() too.
364+
365+
Remember, tuples can be either system cache copies, which may go away
366+
after you call ReleaseSysCache(), or read directly from disk buffers,
367+
which go away when you heap_getnext(), heap_endscan, or ReleaseBuffer(),
368+
in the heap_fetch() case. Or it may be a palloc'ed tuple, that you must
367369
pfree() when finished.
368370

369371
10) What is elog()?

doc/src/FAQ/FAQ_DEV.html

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ <H3><a name="9">9</a>) How do I efficiently access information in
358358
tables from the backend code?</H3><P>
359359

360360
You first need to find the tuples(rows) you are interested in. There
361-
are two ways. First, <I>SearchSysCacheTuple()</I> and related functions
361+
are two ways. First, <I>SearchSysCache()</I> and related functions
362362
allow you to query the system catalogs. This is the preferred way to
363363
access system tables, because the first call to the cache loads the
364364
needed rows, and future requests can return the results without
@@ -367,15 +367,14 @@ <H3><a name="9">9</a>) How do I efficiently access information in
367367
<I>src/backend/utils/cache/syscache.c.</I>
368368
<I>src/backend/utils/cache/lsyscache.c</I> contains many column-specific
369369
cache lookup functions.<P>
370-
371-
The rows returned are cached-owned versions of the heap rows. They are
372-
invalidated when the base table changes. Because the cache is local to
373-
each backend, you may use the pointer returned from the cache for short
374-
periods without making a copy of the tuple. If you send the pointer
375-
into a large function that will be doing its own cache lookups, it is
376-
possible the cache entry may be flushed, so you should use
377-
<I>SearchSysCacheTupleCopy()</I> in these cases, and <I>pfree()</I> the
378-
tuple when you are done.<P>
370+
371+
The rows returned are cache-owned versions of the heap rows. Therefore, you
372+
must not modify or delete the tuple returned by <I>SearchSysCache()</I>. What
373+
you <I>should</I> do is release it with <I>ReleaseSysCache()</I> when you are
374+
done using it; this informs the cache that it can discard that tuple if
375+
necessary. If you neglect to call <I>ReleaseSysCache()</I>, then the cache
376+
entry will remain locked in the cache until end of transaction, which is
377+
tolerable but not very desirable.<P>
379378

380379
If you can't use the system cache, you will need to retrieve the data
381380
directly from the heap table, using the buffer cache that is shared by
@@ -392,12 +391,11 @@ <H3><a name="9">9</a>) How do I efficiently access information in
392391
You can also use <I>heap_fetch()</I> to fetch rows by block
393392
number/offset. While scans automatically lock/unlock rows from the
394393
buffer cache, with <I>heap_fetch(),</I> you must pass a <I>Buffer</I>
395-
pointer, and <I>ReleaseBuffer()</I> it when completed.
394+
pointer, and <I>ReleaseBuffer()</I> it when completed.<P>
396395

397396
Once you have the row, you can get data that is common to all tuples,
398397
like <I>t_self</I> and <I>t_oid,</I> by merely accessing the
399398
<I>HeapTuple</I> structure entries.
400-
401399
If you need a table-specific column, you should take the HeapTuple
402400
pointer, and use the <I>GETSTRUCT()</I> macro to access the
403401
table-specific start of the tuple. You then cast the pointer as a
@@ -411,18 +409,18 @@ <H3><a name="9">9</a>) How do I efficiently access information in
411409
</CODE>
412410
</PRE>
413411

414-
You should not directly change <I>live</I> tuples in this way. The best
415-
way is to use <I>heap_tuplemodify()</I> and pass it your palloc'ed
416-
tuple, and the values you want changed. It returns another palloc'ed
412+
You must not directly change <I>live</I> tuples in this way. The best
413+
way is to use <I>heap_modifytuple()</I> and pass it your original
414+
tuple, and the values you want changed. It returns a palloc'ed
417415
tuple, which you pass to <I>heap_replace().</I>
418416

419417
You can delete tuples by passing the tuple's <I>t_self</I> to
420-
<I>heap_destroy().</I> You can use it for <I>heap_update()</I> too.
418+
<I>heap_destroy().</I> You use <I>t_self</I> for <I>heap_update()</I> too.
421419

422-
Remember, tuples can be either system cache versions, which may go away
423-
soon after you get them, buffer cache versions, which go away when
424-
you <I>heap_getnext(),</I> <I>heap_endscan,</I> or
425-
<I>ReleaseBuffer()</I>, in the <I>heap_fetch()</I> case. Or it may be a
420+
Remember, tuples can be either system cache copies, which may go away after
421+
you call <I>ReleaseSysCache()</I>, or read directly from disk buffers, which
422+
go away when you <I>heap_getnext()</I>, <I>heap_endscan</I>, or
423+
<I>ReleaseBuffer()</I>, in the <I>heap_fetch()</I> case. Or it may be a
426424
palloc'ed tuple, that you must <I>pfree()</I> when finished.
427425

428426
<H3><a name="10">10</a>) What is elog()?</H3><P>

src/backend/access/common/printtup.c

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.53 2000/05/30 04:24:27 tgl Exp $
12+
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.54 2000/11/16 22:30:15 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -36,33 +36,27 @@ static void printtup_cleanup(DestReceiver *self);
3636
* getTypeOutAndElem -- get both typoutput and typelem for a type
3737
*
3838
* We used to fetch these with two separate function calls,
39-
* typtoout() and gettypelem(), which each called SearchSysCacheTuple.
39+
* typtoout() and gettypelem(), which each called SearchSysCache.
4040
* This way takes half the time.
4141
* ----------------
4242
*/
4343
int
4444
getTypeOutAndElem(Oid type, Oid *typOutput, Oid *typElem)
4545
{
4646
HeapTuple typeTuple;
47-
48-
typeTuple = SearchSysCacheTuple(TYPEOID,
49-
ObjectIdGetDatum(type),
50-
0, 0, 0);
51-
52-
if (HeapTupleIsValid(typeTuple))
53-
{
54-
Form_pg_type pt = (Form_pg_type) GETSTRUCT(typeTuple);
55-
56-
*typOutput = (Oid) pt->typoutput;
57-
*typElem = (Oid) pt->typelem;
58-
return OidIsValid(*typOutput);
59-
}
60-
61-
elog(ERROR, "getTypeOutAndElem: Cache lookup of type %u failed", type);
62-
63-
*typOutput = InvalidOid;
64-
*typElem = InvalidOid;
65-
return 0;
47+
Form_pg_type pt;
48+
49+
typeTuple = SearchSysCache(TYPEOID,
50+
ObjectIdGetDatum(type),
51+
0, 0, 0);
52+
if (!HeapTupleIsValid(typeTuple))
53+
elog(ERROR, "getTypeOutAndElem: Cache lookup of type %u failed", type);
54+
pt = (Form_pg_type) GETSTRUCT(typeTuple);
55+
56+
*typOutput = pt->typoutput;
57+
*typElem = pt->typelem;
58+
ReleaseSysCache(typeTuple);
59+
return OidIsValid(*typOutput);
6660
}
6761

6862
/* ----------------

src/backend/access/common/tupdesc.c

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.68 2000/11/08 22:09:53 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.69 2000/11/16 22:30:15 tgl Exp $
1212
*
1313
* NOTES
1414
* some of the executor utility code such as "ExecTypeFromTL" should be
@@ -401,9 +401,9 @@ TupleDescInitEntry(TupleDesc desc,
401401
* -cim 6/14/90
402402
* ----------------
403403
*/
404-
tuple = SearchSysCacheTuple(TYPEOID,
405-
ObjectIdGetDatum(oidtypeid),
406-
0, 0, 0);
404+
tuple = SearchSysCache(TYPEOID,
405+
ObjectIdGetDatum(oidtypeid),
406+
0, 0, 0);
407407
if (!HeapTupleIsValid(tuple))
408408
{
409409
/* ----------------
@@ -455,25 +455,18 @@ TupleDescInitEntry(TupleDesc desc,
455455
*/
456456
if (attisset)
457457
{
458-
Type t = typeidType(OIDOID);
459-
460-
att->attlen = typeLen(t);
461-
att->attbyval = typeByVal(t);
458+
att->attlen = sizeof(Oid);
459+
att->attbyval = true;
460+
att->attstorage = 'p';
462461
}
463462
else
464463
{
465464
att->attlen = typeForm->typlen;
466465
att->attbyval = typeForm->typbyval;
467-
/*
468-
* Default to the types storage
469-
*/
470-
#ifdef TUPLE_TOASTER_ACTIVE
471466
att->attstorage = typeForm->typstorage;
472-
#else
473-
att->attstorage = 'p';
474-
#endif
475467
}
476468

469+
ReleaseSysCache(tuple);
477470

478471
return true;
479472
}
@@ -496,12 +489,11 @@ TupleDescMakeSelfReference(TupleDesc desc,
496489
char *relname)
497490
{
498491
Form_pg_attribute att;
499-
Type t = typeidType(OIDOID);
500492

501493
att = desc->attrs[attnum - 1];
502494
att->atttypid = TypeShellMake(relname);
503-
att->attlen = typeLen(t);
504-
att->attbyval = typeByVal(t);
495+
att->attlen = sizeof(Oid);
496+
att->attbyval = true;
505497
att->attstorage = 'p';
506498
att->attnelems = 0;
507499
}
@@ -580,7 +572,7 @@ BuildDescForRelation(List *schema, char *relname)
580572
}
581573

582574
if (!TupleDescInitEntry(desc, attnum, attname,
583-
typeTypeId(typenameType(typename)),
575+
typenameTypeId(typename),
584576
atttypmod, attdim, attisset))
585577
{
586578
/* ----------------

src/backend/access/gist/gist.c

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
*
88
* IDENTIFICATION
9-
* $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.64 2000/11/08 22:09:53 tgl Exp $
9+
* $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.65 2000/11/16 22:30:15 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -1140,6 +1140,7 @@ initGISTstate(GISTSTATE *giststate, Relation index)
11401140
equal_proc;
11411141
HeapTuple htup;
11421142
Form_pg_index itupform;
1143+
Oid indexrelid;
11431144

11441145
consistent_proc = index_getprocid(index, 1, GIST_CONSISTENT_PROC);
11451146
union_proc = index_getprocid(index, 1, GIST_UNION_PROC);
@@ -1157,32 +1158,32 @@ initGISTstate(GISTSTATE *giststate, Relation index)
11571158
fmgr_info(equal_proc, &giststate->equalFn);
11581159

11591160
/* see if key type is different from type of attribute being indexed */
1160-
htup = SearchSysCacheTuple(INDEXRELID,
1161-
ObjectIdGetDatum(RelationGetRelid(index)),
1162-
0, 0, 0);
1163-
itupform = (Form_pg_index) GETSTRUCT(htup);
1161+
htup = SearchSysCache(INDEXRELID,
1162+
ObjectIdGetDatum(RelationGetRelid(index)),
1163+
0, 0, 0);
11641164
if (!HeapTupleIsValid(htup))
11651165
elog(ERROR, "initGISTstate: index %u not found",
11661166
RelationGetRelid(index));
1167+
itupform = (Form_pg_index) GETSTRUCT(htup);
11671168
giststate->haskeytype = itupform->indhaskeytype;
1169+
indexrelid = itupform->indexrelid;
1170+
ReleaseSysCache(htup);
1171+
11681172
if (giststate->haskeytype)
11691173
{
11701174
/* key type is different -- is it byval? */
1171-
htup = SearchSysCacheTuple(ATTNUM,
1172-
ObjectIdGetDatum(itupform->indexrelid),
1173-
UInt16GetDatum(FirstOffsetNumber),
1174-
0, 0);
1175+
htup = SearchSysCache(ATTNUM,
1176+
ObjectIdGetDatum(indexrelid),
1177+
UInt16GetDatum(FirstOffsetNumber),
1178+
0, 0);
11751179
if (!HeapTupleIsValid(htup))
1176-
{
11771180
elog(ERROR, "initGISTstate: no attribute tuple %u %d",
1178-
itupform->indexrelid, FirstOffsetNumber);
1179-
return;
1180-
}
1181+
indexrelid, FirstOffsetNumber);
11811182
giststate->keytypbyval = (((Form_pg_attribute) htup)->attbyval);
1183+
ReleaseSysCache(htup);
11821184
}
11831185
else
11841186
giststate->keytypbyval = FALSE;
1185-
return;
11861187
}
11871188

11881189

0 commit comments

Comments
 (0)