mirror of
https://github.com/postgres/postgres.git
synced 2025-09-02 04:21:28 +03:00
Theses buffer leaks are caused by indexes that are kept open between
calls. Outside a transaction, the backend detects them as buffer leaks; it sends a NOTICE, and frees them. This sometimes cause a segmentation fault (at least on Linux). These indexes are initialized on the first lo_read/lo_write/lo_tell call, and (normally) closed on a lo_close call. Thus the buffer leaks appear when lo direct access functions are used, and not with lo_import/lo_export functions (libpq version calls lo_close before ending the command, and the backend version uses another path). The included patches (against recent snapshot, and against 6.3.2) cause indexes to be closed on transaction end (that is on explicit 'END' statment, or on command termination outside trasaction blocks), thus preventing the buffer leaks while increasing performance inside transactions. Some (all?) 'classic' memory leaks are also removed. I hope it will be ok. --- Pascal ANDRE, graduated from Ecole Centrale Paris andre@via.ecp.fr
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.30 1998/06/15 19:29:16 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.31 1998/07/21 04:17:24 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -60,6 +60,19 @@
|
||||
* for data.
|
||||
*/
|
||||
|
||||
/*
|
||||
* In order to prevent buffer leak on transaction commit, large object
|
||||
* scan index handling has been modified. Indexes are persistant inside
|
||||
* a transaction but may be closed between two calls to this API (when
|
||||
* transaction is committed while object is opened, or when no
|
||||
* transaction is active). Scan indexes are thus now reinitialized using
|
||||
* the object current offset. [PA]
|
||||
*
|
||||
* Some cleanup has been also done for non freed memory.
|
||||
*
|
||||
* For subsequent notes, [PA] is Pascal Andr<64> <andre@via.ecp.fr>
|
||||
*/
|
||||
|
||||
#define IFREESPC(p) (PageGetFreeSpace(p) - sizeof(HeapTupleData) - sizeof(struct varlena) - sizeof(int32))
|
||||
#define IMAXBLK 8092
|
||||
#define IMINBLK 512
|
||||
@@ -261,8 +274,11 @@ inv_close(LargeObjectDesc *obj_desc)
|
||||
{
|
||||
Assert(PointerIsValid(obj_desc));
|
||||
|
||||
if (obj_desc->iscan != (IndexScanDesc) NULL)
|
||||
if (obj_desc->iscan != (IndexScanDesc) NULL) {
|
||||
index_endscan(obj_desc->iscan);
|
||||
pfree(obj_desc->iscan);
|
||||
obj_desc->iscan = NULL;
|
||||
}
|
||||
|
||||
heap_close(obj_desc->heap_r);
|
||||
index_close(obj_desc->index_r);
|
||||
@@ -546,6 +562,28 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
|
||||
return (nwritten);
|
||||
}
|
||||
|
||||
/*
|
||||
* inv_cleanindex --
|
||||
* Clean opened indexes for large objects, and clears current result.
|
||||
* This is necessary on transaction commit in order to prevent buffer
|
||||
* leak.
|
||||
* This function must be called for each opened large object.
|
||||
* [ PA, 7/17/98 ]
|
||||
*/
|
||||
void
|
||||
inv_cleanindex(LargeObjectDesc *obj_desc)
|
||||
{
|
||||
Assert(PointerIsValid(obj_desc));
|
||||
|
||||
if (obj_desc->iscan == (IndexScanDesc) NULL) return;
|
||||
|
||||
index_endscan(obj_desc->iscan);
|
||||
pfree(obj_desc->iscan);
|
||||
obj_desc->iscan = (IndexScanDesc) NULL;
|
||||
|
||||
ItemPointerSetInvalid(&(obj_desc->htid));
|
||||
}
|
||||
|
||||
/*
|
||||
* inv_fetchtup -- Fetch an inversion file system block.
|
||||
*
|
||||
@@ -591,8 +629,13 @@ inv_fetchtup(LargeObjectDesc *obj_desc, Buffer *bufP)
|
||||
{
|
||||
ScanKeyData skey;
|
||||
|
||||
/*
|
||||
* As scan index may be prematurely closed (on commit),
|
||||
* we must use object current offset (was 0) to
|
||||
* reinitialize the entry [ PA ].
|
||||
*/
|
||||
ScanKeyEntryInitialize(&skey, 0x0, 1, F_INT4GE,
|
||||
Int32GetDatum(0));
|
||||
Int32GetDatum(obj_desc->offset));
|
||||
obj_desc->iscan =
|
||||
index_beginscan(obj_desc->index_r,
|
||||
(bool) 0, (uint16) 1,
|
||||
@@ -622,7 +665,7 @@ inv_fetchtup(LargeObjectDesc *obj_desc, Buffer *bufP)
|
||||
|
||||
/* remember this tid -- we may need it for later reads/writes */
|
||||
ItemPointerCopy(&(res->heap_iptr), &(obj_desc->htid));
|
||||
|
||||
pfree(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1179,6 +1222,7 @@ _inv_getsize(Relation hreln, TupleDesc hdesc, Relation ireln)
|
||||
if (res == (RetrieveIndexResult) NULL)
|
||||
{
|
||||
index_endscan(iscan);
|
||||
pfree(iscan);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -1192,11 +1236,13 @@ _inv_getsize(Relation hreln, TupleDesc hdesc, Relation ireln)
|
||||
ReleaseBuffer(buf);
|
||||
|
||||
htup = heap_fetch(hreln, false, &(res->heap_iptr), &buf);
|
||||
pfree(res);
|
||||
|
||||
} while (!HeapTupleIsValid(htup));
|
||||
|
||||
/* don't need the index scan anymore */
|
||||
index_endscan(iscan);
|
||||
pfree(iscan);
|
||||
|
||||
/* get olastbyte attribute */
|
||||
d = heap_getattr(htup, 1, hdesc, &isNull);
|
||||
|
Reference in New Issue
Block a user