mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-30 23:11:15 +02:00
1. Fix md memory leak:
mdunlink() and mdclose() (too !!!) now free MdfdVec for relation and add it to free list, so it may be re-used for another relation later. 2. Fix VFD-manager memory leak (found by Massimo ... and me): mdunlink() has to call FileUnlink() to free allocation for fileName and add the Vfd slot to the free list.
This commit is contained in:
parent
ff8ce5230d
commit
19269069dc
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.12 1997/05/06 02:03:20 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.13 1997/05/22 17:08:33 vadim Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -42,25 +42,29 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct _MdfdVec {
|
typedef struct _MdfdVec {
|
||||||
int mdfd_vfd; /* fd number in vfd pool */
|
int mdfd_vfd; /* fd number in vfd pool */
|
||||||
uint16 mdfd_flags; /* clean, dirty */
|
uint16 mdfd_flags; /* clean, dirty, free */
|
||||||
int mdfd_lstbcnt; /* most recent block count */
|
int mdfd_lstbcnt; /* most recent block count */
|
||||||
struct _MdfdVec *mdfd_chain; /* for large relations */
|
int mdfd_nextFree; /* next free vector */
|
||||||
|
struct _MdfdVec *mdfd_chain; /* for large relations */
|
||||||
} MdfdVec;
|
} MdfdVec;
|
||||||
|
|
||||||
static int Nfds = 100;
|
static int Nfds = 100;
|
||||||
static MdfdVec *Md_fdvec = (MdfdVec *) NULL;
|
static MdfdVec *Md_fdvec = (MdfdVec *) NULL;
|
||||||
|
static int Md_Free = -1;
|
||||||
static int CurFd = 0;
|
static int CurFd = 0;
|
||||||
static MemoryContext MdCxt;
|
static MemoryContext MdCxt;
|
||||||
|
|
||||||
#define MDFD_DIRTY (uint16) 0x01
|
#define MDFD_DIRTY (uint16) 0x01
|
||||||
|
#define MDFD_FREE (uint16) 0x02
|
||||||
|
|
||||||
#define RELSEG_SIZE 262144 /* (2 ** 31) / 8192 -- 2GB file */
|
#define RELSEG_SIZE 262144 /* (2 ** 31) / 8192 -- 2GB file */
|
||||||
|
|
||||||
/* routines declared here */
|
/* routines declared here */
|
||||||
static MdfdVec *_mdfd_openseg(Relation reln, int segno, int oflags);
|
static MdfdVec *_mdfd_openseg(Relation reln, int segno, int oflags);
|
||||||
static MdfdVec *_mdfd_getseg(Relation reln, int blkno, int oflag);
|
static MdfdVec *_mdfd_getseg(Relation reln, int blkno, int oflag);
|
||||||
static int _fdvec_ext(void);
|
static int _fdvec_alloc (void);
|
||||||
|
static void _fdvec_free (int);
|
||||||
static BlockNumber _mdnblocks(File file, Size blcksz);
|
static BlockNumber _mdnblocks(File file, Size blcksz);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -78,6 +82,7 @@ int
|
|||||||
mdinit()
|
mdinit()
|
||||||
{
|
{
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
|
int i;
|
||||||
|
|
||||||
MdCxt = (MemoryContext) CreateGlobalMemory("MdSmgr");
|
MdCxt = (MemoryContext) CreateGlobalMemory("MdSmgr");
|
||||||
if (MdCxt == (MemoryContext) NULL)
|
if (MdCxt == (MemoryContext) NULL)
|
||||||
@ -90,7 +95,16 @@ mdinit()
|
|||||||
if (Md_fdvec == (MdfdVec *) NULL)
|
if (Md_fdvec == (MdfdVec *) NULL)
|
||||||
return (SM_FAIL);
|
return (SM_FAIL);
|
||||||
|
|
||||||
memset(Md_fdvec, 0, Nfds * sizeof(MdfdVec));
|
memset(Md_fdvec, 0, Nfds * sizeof(MdfdVec));
|
||||||
|
|
||||||
|
/* Set free list */
|
||||||
|
for (i = 0; i < Nfds; i++ )
|
||||||
|
{
|
||||||
|
Md_fdvec[i].mdfd_nextFree = i + 1;
|
||||||
|
Md_fdvec[i].mdfd_flags = MDFD_FREE;
|
||||||
|
}
|
||||||
|
Md_Free = 0;
|
||||||
|
Md_fdvec[Nfds - 1].mdfd_nextFree = -1;
|
||||||
|
|
||||||
return (SM_SUCCESS);
|
return (SM_SUCCESS);
|
||||||
}
|
}
|
||||||
@ -124,18 +138,15 @@ mdcreate(Relation reln)
|
|||||||
if ( fd < 0 )
|
if ( fd < 0 )
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfd = _fdvec_alloc ();
|
||||||
|
if ( vfd < 0 )
|
||||||
|
return (-1);
|
||||||
|
|
||||||
if (CurFd >= Nfds) {
|
Md_fdvec[vfd].mdfd_vfd = fd;
|
||||||
if (_fdvec_ext() == SM_FAIL)
|
Md_fdvec[vfd].mdfd_flags = (uint16) 0;
|
||||||
return (-1);
|
Md_fdvec[vfd].mdfd_chain = (MdfdVec *) NULL;
|
||||||
}
|
Md_fdvec[vfd].mdfd_lstbcnt = 0;
|
||||||
|
|
||||||
Md_fdvec[CurFd].mdfd_vfd = fd;
|
|
||||||
Md_fdvec[CurFd].mdfd_flags = (uint16) 0;
|
|
||||||
Md_fdvec[CurFd].mdfd_chain = (MdfdVec *) NULL;
|
|
||||||
Md_fdvec[CurFd].mdfd_lstbcnt = 0;
|
|
||||||
|
|
||||||
vfd = CurFd++;
|
|
||||||
|
|
||||||
return (vfd);
|
return (vfd);
|
||||||
}
|
}
|
||||||
@ -175,7 +186,9 @@ mdunlink(Relation reln)
|
|||||||
Md_fdvec[fd].mdfd_flags = (uint16) 0;
|
Md_fdvec[fd].mdfd_flags = (uint16) 0;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo(MdCxt);
|
oldcxt = MemoryContextSwitchTo(MdCxt);
|
||||||
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL; ) {
|
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL; )
|
||||||
|
{
|
||||||
|
FileUnlink(v->mdfd_vfd);
|
||||||
ov = v;
|
ov = v;
|
||||||
v = v->mdfd_chain;
|
v = v->mdfd_chain;
|
||||||
if (ov != &Md_fdvec[fd])
|
if (ov != &Md_fdvec[fd])
|
||||||
@ -184,6 +197,8 @@ mdunlink(Relation reln)
|
|||||||
Md_fdvec[fd].mdfd_chain = (MdfdVec *) NULL;
|
Md_fdvec[fd].mdfd_chain = (MdfdVec *) NULL;
|
||||||
(void) MemoryContextSwitchTo(oldcxt);
|
(void) MemoryContextSwitchTo(oldcxt);
|
||||||
|
|
||||||
|
_fdvec_free (fd);
|
||||||
|
|
||||||
return (SM_SUCCESS);
|
return (SM_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,11 +250,6 @@ mdopen(Relation reln)
|
|||||||
int fd;
|
int fd;
|
||||||
int vfd;
|
int vfd;
|
||||||
|
|
||||||
if (CurFd >= Nfds) {
|
|
||||||
if (_fdvec_ext() == SM_FAIL)
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
path = relpath(&(reln->rd_rel->relname.data[0]));
|
path = relpath(&(reln->rd_rel->relname.data[0]));
|
||||||
|
|
||||||
fd = FileNameOpenFile(path, O_RDWR, 0600);
|
fd = FileNameOpenFile(path, O_RDWR, 0600);
|
||||||
@ -248,23 +258,28 @@ mdopen(Relation reln)
|
|||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
fd = FileNameOpenFile(path, O_RDWR|O_CREAT|O_EXCL, 0600);
|
fd = FileNameOpenFile(path, O_RDWR|O_CREAT|O_EXCL, 0600);
|
||||||
|
|
||||||
Md_fdvec[CurFd].mdfd_vfd = fd;
|
vfd = _fdvec_alloc ();
|
||||||
Md_fdvec[CurFd].mdfd_flags = (uint16) 0;
|
if ( vfd < 0 )
|
||||||
Md_fdvec[CurFd].mdfd_chain = (MdfdVec *) NULL;
|
return (-1);
|
||||||
Md_fdvec[CurFd].mdfd_lstbcnt = _mdnblocks(fd, BLCKSZ);
|
|
||||||
|
Md_fdvec[vfd].mdfd_vfd = fd;
|
||||||
|
Md_fdvec[vfd].mdfd_flags = (uint16) 0;
|
||||||
|
Md_fdvec[vfd].mdfd_chain = (MdfdVec *) NULL;
|
||||||
|
Md_fdvec[vfd].mdfd_lstbcnt = _mdnblocks(fd, BLCKSZ);
|
||||||
|
|
||||||
#ifdef DIAGNOSTIC
|
#ifdef DIAGNOSTIC
|
||||||
if (Md_fdvec[CurFd].mdfd_lstbcnt > RELSEG_SIZE)
|
if (Md_fdvec[vfd].mdfd_lstbcnt > RELSEG_SIZE)
|
||||||
elog(FATAL, "segment too big on relopen!");
|
elog(FATAL, "segment too big on relopen!");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
vfd = CurFd++;
|
|
||||||
|
|
||||||
return (vfd);
|
return (vfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mdclose() -- Close the specified relation.
|
* mdclose() -- Close the specified relation
|
||||||
|
*
|
||||||
|
* AND FREE fd vector! It may be re-used for other relation!
|
||||||
|
* reln should be flushed from cache after closing !..
|
||||||
*
|
*
|
||||||
* Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
|
* Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
|
||||||
*/
|
*/
|
||||||
@ -272,28 +287,40 @@ int
|
|||||||
mdclose(Relation reln)
|
mdclose(Relation reln)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
MdfdVec *v;
|
MdfdVec *v, *ov;
|
||||||
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
fd = RelationGetFile(reln);
|
fd = RelationGetFile(reln);
|
||||||
|
|
||||||
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL; v = v->mdfd_chain) {
|
oldcxt = MemoryContextSwitchTo(MdCxt);
|
||||||
|
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL; )
|
||||||
|
{
|
||||||
|
/* if not closed already */
|
||||||
|
if ( v->mdfd_vfd >= 0 )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We sync the file descriptor so that we don't need to reopen it at
|
||||||
|
* transaction commit to force changes to disk.
|
||||||
|
*/
|
||||||
|
|
||||||
/* may be closed already */
|
FileSync(v->mdfd_vfd);
|
||||||
if (v->mdfd_vfd < 0)
|
FileClose(v->mdfd_vfd);
|
||||||
continue;
|
|
||||||
|
|
||||||
/*
|
/* mark this file descriptor as clean in our private table */
|
||||||
* We sync the file descriptor so that we don't need to reopen it at
|
v->mdfd_flags &= ~MDFD_DIRTY;
|
||||||
* transaction commit to force changes to disk.
|
}
|
||||||
*/
|
/* Now free vector */
|
||||||
|
ov = v;
|
||||||
FileSync(v->mdfd_vfd);
|
v = v->mdfd_chain;
|
||||||
FileClose(v->mdfd_vfd);
|
if (ov != &Md_fdvec[fd])
|
||||||
|
pfree(ov);
|
||||||
/* mark this file descriptor as clean in our private table */
|
|
||||||
v->mdfd_flags &= ~MDFD_DIRTY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(void) MemoryContextSwitchTo(oldcxt);
|
||||||
|
Md_fdvec[fd].mdfd_chain = (MdfdVec *) NULL;
|
||||||
|
|
||||||
|
_fdvec_free (fd);
|
||||||
|
|
||||||
return (SM_SUCCESS);
|
return (SM_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,31 +632,77 @@ mdabort()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* _fdvec_ext() -- Extend the md file descriptor vector.
|
* _fdvec_alloc () -- grab a free (or new) md file descriptor vector.
|
||||||
*
|
*
|
||||||
* The file descriptor vector must be large enough to hold at least
|
|
||||||
* 'fd' entries.
|
|
||||||
*/
|
*/
|
||||||
static
|
static
|
||||||
int _fdvec_ext()
|
int _fdvec_alloc ()
|
||||||
{
|
{
|
||||||
MdfdVec *nvec;
|
MdfdVec *nvec;
|
||||||
|
int fdvec, i;
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
|
|
||||||
|
if ( Md_Free >= 0 ) /* get from free list */
|
||||||
|
{
|
||||||
|
fdvec = Md_Free;
|
||||||
|
Md_Free = Md_fdvec[fdvec].mdfd_nextFree;
|
||||||
|
Assert ( Md_fdvec[fdvec].mdfd_flags == MDFD_FREE );
|
||||||
|
Md_fdvec[fdvec].mdfd_flags = 0;
|
||||||
|
if ( fdvec >= CurFd )
|
||||||
|
{
|
||||||
|
Assert ( fdvec == CurFd );
|
||||||
|
CurFd++;
|
||||||
|
}
|
||||||
|
return (fdvec);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Must allocate more room */
|
||||||
|
|
||||||
|
if ( Nfds != CurFd )
|
||||||
|
elog (FATAL, "_fdvec_alloc error");
|
||||||
|
|
||||||
Nfds *= 2;
|
Nfds *= 2;
|
||||||
|
|
||||||
oldcxt = MemoryContextSwitchTo(MdCxt);
|
oldcxt = MemoryContextSwitchTo(MdCxt);
|
||||||
|
|
||||||
nvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
|
nvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
|
||||||
memset(nvec, 0, Nfds * sizeof(MdfdVec));
|
memset(nvec, 0, Nfds * sizeof(MdfdVec));
|
||||||
memmove(nvec, (char *) Md_fdvec, (Nfds / 2) * sizeof(MdfdVec));
|
memmove(nvec, (char *) Md_fdvec, CurFd * sizeof(MdfdVec));
|
||||||
pfree(Md_fdvec);
|
pfree(Md_fdvec);
|
||||||
|
|
||||||
(void) MemoryContextSwitchTo(oldcxt);
|
(void) MemoryContextSwitchTo(oldcxt);
|
||||||
|
|
||||||
Md_fdvec = nvec;
|
Md_fdvec = nvec;
|
||||||
|
|
||||||
return (SM_SUCCESS);
|
/* Set new free list */
|
||||||
|
for (i = CurFd; i < Nfds; i++ )
|
||||||
|
{
|
||||||
|
Md_fdvec[i].mdfd_nextFree = i + 1;
|
||||||
|
Md_fdvec[i].mdfd_flags = MDFD_FREE;
|
||||||
|
}
|
||||||
|
Md_fdvec[Nfds - 1].mdfd_nextFree = -1;
|
||||||
|
Md_Free = CurFd + 1;
|
||||||
|
|
||||||
|
fdvec = CurFd;
|
||||||
|
CurFd++;
|
||||||
|
Md_fdvec[fdvec].mdfd_flags = 0;
|
||||||
|
|
||||||
|
return (fdvec);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _fdvec_free () -- free md file descriptor vector.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void _fdvec_free (int fdvec)
|
||||||
|
{
|
||||||
|
|
||||||
|
Assert ( Md_Free < 0 || Md_fdvec[Md_Free].mdfd_flags == MDFD_FREE );
|
||||||
|
Md_fdvec[fdvec].mdfd_nextFree = Md_Free;
|
||||||
|
Md_fdvec[fdvec].mdfd_flags = MDFD_FREE;
|
||||||
|
Md_Free = fdvec;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static MdfdVec *
|
static MdfdVec *
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.5 1996/11/27 07:25:52 vadim Exp $
|
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.6 1997/05/22 17:08:35 vadim Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -189,6 +189,13 @@ smgropen(int16 which, Relation reln)
|
|||||||
/*
|
/*
|
||||||
* smgrclose() -- Close a relation.
|
* smgrclose() -- Close a relation.
|
||||||
*
|
*
|
||||||
|
* NOTE: mdclose frees fd vector! It may be re-used for other relation!
|
||||||
|
* reln should be flushed from cache after closing !..
|
||||||
|
* Currently, smgrclose is calling by
|
||||||
|
* relcache.c:RelationPurgeLocalRelation() only.
|
||||||
|
* It would be nice to have smgrfree(), but because of
|
||||||
|
* smgrclose is called from single place... - vadim 05/22/97
|
||||||
|
*
|
||||||
* Returns SM_SUCCESS on success, aborts on failure.
|
* Returns SM_SUCCESS on success, aborts on failure.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
Loading…
Reference in New Issue
Block a user