mirror of
https://github.com/postgres/postgres.git
synced 2025-07-07 00:36:50 +03:00
Another go-round on making GetRawDatabaseInfo behave as well as it can,
given the fundamental restriction of not looking at transaction commit data in pg_log. Use code that is actually based on tqual.c rather than ad-hoc tests. Also write the tuple fetch loop using standard access macros rather than ad-hoc code.
This commit is contained in:
@ -8,13 +8,12 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/misc/Attic/database.c,v 1.41 2000/11/14 18:37:45 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/misc/Attic/database.c,v 1.42 2001/01/14 22:21:05 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -28,6 +27,9 @@
|
|||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
|
||||||
|
static bool PhonyHeapTupleSatisfiesNow(HeapTupleHeader tuple);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ExpandDatabasePath resolves a proposed database path (obtained from
|
* ExpandDatabasePath resolves a proposed database path (obtained from
|
||||||
* pg_database.datpath) to a full absolute path for further consumption.
|
* pg_database.datpath) to a full absolute path for further consumption.
|
||||||
@ -136,11 +138,9 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
|
|||||||
{
|
{
|
||||||
int dbfd;
|
int dbfd;
|
||||||
int nbytes;
|
int nbytes;
|
||||||
int max,
|
int pathlen;
|
||||||
i;
|
|
||||||
HeapTupleData tup;
|
HeapTupleData tup;
|
||||||
Page pg;
|
Page pg;
|
||||||
PageHeader ph;
|
|
||||||
char *dbfname;
|
char *dbfname;
|
||||||
Form_pg_database tup_db;
|
Form_pg_database tup_db;
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((dbfd = open(dbfname, O_RDONLY | PG_BINARY, 0)) < 0)
|
if ((dbfd = open(dbfname, O_RDONLY | PG_BINARY, 0)) < 0)
|
||||||
elog(FATAL, "cannot open %s: %s", dbfname, strerror(errno));
|
elog(FATAL, "cannot open %s: %m", dbfname);
|
||||||
|
|
||||||
pfree(dbfname);
|
pfree(dbfname);
|
||||||
|
|
||||||
@ -179,38 +179,38 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
|
|||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
pg = (Page) palloc(BLCKSZ);
|
pg = (Page) palloc(BLCKSZ);
|
||||||
ph = (PageHeader) pg;
|
|
||||||
|
|
||||||
while ((nbytes = read(dbfd, pg, BLCKSZ)) == BLCKSZ)
|
while ((nbytes = read(dbfd, pg, BLCKSZ)) == BLCKSZ)
|
||||||
{
|
{
|
||||||
max = PageGetMaxOffsetNumber(pg);
|
OffsetNumber max = PageGetMaxOffsetNumber(pg);
|
||||||
|
OffsetNumber lineoff;
|
||||||
|
|
||||||
/* look at each tuple on the page */
|
/* look at each tuple on the page */
|
||||||
for (i = 0; i < max; i++)
|
for (lineoff = FirstOffsetNumber; lineoff <= max; lineoff++)
|
||||||
{
|
{
|
||||||
int offset;
|
ItemId lpp = PageGetItemId(pg, lineoff);
|
||||||
|
|
||||||
/* if it's a freed tuple, ignore it */
|
/* if it's a freed tuple, ignore it */
|
||||||
if (!(ph->pd_linp[i].lp_flags & LP_USED))
|
if (!ItemIdIsUsed(lpp))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* get a pointer to the tuple itself */
|
/* get a pointer to the tuple itself */
|
||||||
offset = (int) ph->pd_linp[i].lp_off;
|
|
||||||
tup.t_datamcxt = NULL;
|
tup.t_datamcxt = NULL;
|
||||||
tup.t_data = (HeapTupleHeader) (((char *) pg) + offset);
|
tup.t_data = (HeapTupleHeader) PageGetItem(pg, lpp);
|
||||||
|
|
||||||
/*
|
/*--------------------
|
||||||
* if the tuple has been deleted (the database was destroyed),
|
* Check to see if tuple is valid (committed).
|
||||||
* skip this tuple. XXX warning, will robinson: violation of
|
*
|
||||||
* transaction semantics happens right here. we should check
|
* XXX warning, will robinson: violation of transaction semantics
|
||||||
* to be sure that the xact that deleted this tuple actually
|
* happens right here. We cannot really determine if the tuple
|
||||||
* committed. Only way to do that at init time is to paw over
|
* is valid without checking transaction commit status, and the
|
||||||
* the log relation by hand, too. Instead we take the
|
* only way to do that at init time is to paw over pg_log by hand,
|
||||||
* conservative assumption that if someone tried to delete it,
|
* too. Instead of checking, we assume that the inserting
|
||||||
* it's gone. The other side of the coin is that we might
|
* transaction committed, and that any deleting transaction did
|
||||||
* accept a tuple that was stored and never committed. All in
|
* also, unless shown otherwise by on-row commit status bits.
|
||||||
* all, this code is pretty shaky. We will cross-check our
|
*
|
||||||
* result in ReverifyMyDatabase() in postinit.c.
|
* All in all, this code is pretty shaky. We will cross-check
|
||||||
|
* our result in ReverifyMyDatabase() in postinit.c.
|
||||||
*
|
*
|
||||||
* NOTE: if a bogus tuple in pg_database prevents connection to a
|
* NOTE: if a bogus tuple in pg_database prevents connection to a
|
||||||
* valid database, a fix is to connect to another database and
|
* valid database, a fix is to connect to another database and
|
||||||
@ -220,12 +220,10 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
|
|||||||
* XXX wouldn't it be better to let new backends read the
|
* XXX wouldn't it be better to let new backends read the
|
||||||
* database OID from a flat file, handled the same way we
|
* database OID from a flat file, handled the same way we
|
||||||
* handle the password relation?
|
* handle the password relation?
|
||||||
|
*--------------------
|
||||||
*/
|
*/
|
||||||
if (tup.t_data->t_infomask & HEAP_XMIN_INVALID)
|
if (! PhonyHeapTupleSatisfiesNow(tup.t_data))
|
||||||
continue; /* inserting xact known aborted */
|
continue;
|
||||||
if (TransactionIdIsValid((TransactionId) tup.t_data->t_xmax) &&
|
|
||||||
!(tup.t_data->t_infomask & HEAP_XMAX_INVALID))
|
|
||||||
continue; /* deleting xact happened, not known aborted */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Okay, see if this is the one we want.
|
* Okay, see if this is the one we want.
|
||||||
@ -236,9 +234,11 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
|
|||||||
{
|
{
|
||||||
/* Found it; extract the OID and the database path. */
|
/* Found it; extract the OID and the database path. */
|
||||||
*db_id = tup.t_data->t_oid;
|
*db_id = tup.t_data->t_oid;
|
||||||
strncpy(path, VARDATA(&(tup_db->datpath)),
|
pathlen = VARSIZE(&(tup_db->datpath)) - VARHDRSZ;
|
||||||
(VARSIZE(&(tup_db->datpath)) - VARHDRSZ));
|
if (pathlen >= MAXPGPATH)
|
||||||
*(path + VARSIZE(&(tup_db->datpath)) - VARHDRSZ) = '\0';
|
pathlen = MAXPGPATH-1; /* pure paranoia */
|
||||||
|
strncpy(path, VARDATA(&(tup_db->datpath)), pathlen);
|
||||||
|
path[pathlen] = '\0';
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -251,4 +251,37 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
|
|||||||
done:
|
done:
|
||||||
close(dbfd);
|
close(dbfd);
|
||||||
pfree(pg);
|
pfree(pg);
|
||||||
} /* GetRawDatabaseInfo() */
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PhonyHeapTupleSatisfiesNow --- cut-down tuple time qual test
|
||||||
|
*
|
||||||
|
* This is a simplified version of HeapTupleSatisfiesNow() that does not
|
||||||
|
* depend on having transaction commit info available. Any transaction
|
||||||
|
* that touched the tuple is assumed committed unless later marked invalid.
|
||||||
|
* (While we could think about more complex rules, this seems appropriate
|
||||||
|
* for examining pg_database, since both CREATE DATABASE and DROP DATABASE
|
||||||
|
* are non-roll-back-able.)
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
PhonyHeapTupleSatisfiesNow(HeapTupleHeader tuple)
|
||||||
|
{
|
||||||
|
if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
|
||||||
|
{
|
||||||
|
if (tuple->t_infomask & HEAP_XMIN_INVALID)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (tuple->t_infomask & HEAP_MOVED_OFF)
|
||||||
|
return false;
|
||||||
|
/* else assume committed */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* assume xmax transaction committed */
|
||||||
|
if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user