#include "postgres.h"#include "access/xlog.h"#include "access/xlogutils.h"#include "catalog/catalog.h"#include "common/relpath.h"#include "storage/smgr.h"#include "utils/guc.h"#include "utils/hsearch.h"#include "utils/rel.h"
Go to the source code of this file.
| typedef FakeRelCacheEntryData* FakeRelCacheEntry |
Definition at line 378 of file xlogutils.c.
| typedef struct xl_invalid_page xl_invalid_page |
| typedef struct xl_invalid_page_key xl_invalid_page_key |
| Relation CreateFakeRelcacheEntry | ( | RelFileNode | rnode | ) |
Definition at line 393 of file xlogutils.c.
References Assert, LockRelId::dbId, RelFileNode::dbNode, InRecovery, LockInfoData::lockRelId, palloc0(), FakeRelCacheEntryData::pgc, RelationData::rd_backend, RelationData::rd_lockInfo, RelationData::rd_node, RelationData::rd_rel, RelationData::rd_smgr, RelationGetRelationName, LockRelId::relId, and RelFileNode::relNode.
Referenced by btree_xlog_cleanup(), ginContinueSplit(), heap_xlog_delete(), heap_xlog_insert(), heap_xlog_multi_insert(), heap_xlog_update(), heap_xlog_visible(), and smgr_redo().
{
FakeRelCacheEntry fakeentry;
Relation rel;
Assert(InRecovery);
/* Allocate the Relation struct and all related space in one block. */
fakeentry = palloc0(sizeof(FakeRelCacheEntryData));
rel = (Relation) fakeentry;
rel->rd_rel = &fakeentry->pgc;
rel->rd_node = rnode;
/* We will never be working with temp rels during recovery */
rel->rd_backend = InvalidBackendId;
/* It must be a permanent table if we're in recovery. */
rel->rd_rel->relpersistence = RELPERSISTENCE_PERMANENT;
/* We don't know the name of the relation; use relfilenode instead */
sprintf(RelationGetRelationName(rel), "%u", rnode.relNode);
/*
* We set up the lockRelId in case anything tries to lock the dummy
* relation. Note that this is fairly bogus since relNode may be
* different from the relation's OID. It shouldn't really matter though,
* since we are presumably running by ourselves and can't have any lock
* conflicts ...
*/
rel->rd_lockInfo.lockRelId.dbId = rnode.dbNode;
rel->rd_lockInfo.lockRelId.relId = rnode.relNode;
rel->rd_smgr = NULL;
return rel;
}
| static void forget_invalid_pages | ( | RelFileNode | node, | |
| ForkNumber | forkno, | |||
| BlockNumber | minblkno | |||
| ) | [static] |
Definition at line 139 of file xlogutils.c.
References xl_invalid_page_key::blkno, client_min_messages, DEBUG2, elog, ERROR, xl_invalid_page_key::forkno, HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), xl_invalid_page::key, log_min_messages, xl_invalid_page_key::node, NULL, pfree(), RelFileNodeEquals, and relpathperm.
Referenced by XLogDropRelation(), and XLogTruncateRelation().
{
HASH_SEQ_STATUS status;
xl_invalid_page *hentry;
if (invalid_page_tab == NULL)
return; /* nothing to do */
hash_seq_init(&status, invalid_page_tab);
while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL)
{
if (RelFileNodeEquals(hentry->key.node, node) &&
hentry->key.forkno == forkno &&
hentry->key.blkno >= minblkno)
{
if (log_min_messages <= DEBUG2 || client_min_messages <= DEBUG2)
{
char *path = relpathperm(hentry->key.node, forkno);
elog(DEBUG2, "page %u of relation %s has been dropped",
hentry->key.blkno, path);
pfree(path);
}
if (hash_search(invalid_page_tab,
(void *) &hentry->key,
HASH_REMOVE, NULL) == NULL)
elog(ERROR, "hash table corrupted");
}
}
}
| static void forget_invalid_pages_db | ( | Oid | dbid | ) | [static] |
Definition at line 174 of file xlogutils.c.
References xl_invalid_page_key::blkno, client_min_messages, RelFileNode::dbNode, DEBUG2, elog, ERROR, xl_invalid_page_key::forkno, HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), xl_invalid_page::key, log_min_messages, xl_invalid_page_key::node, NULL, pfree(), and relpathperm.
Referenced by XLogDropDatabase().
{
HASH_SEQ_STATUS status;
xl_invalid_page *hentry;
if (invalid_page_tab == NULL)
return; /* nothing to do */
hash_seq_init(&status, invalid_page_tab);
while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL)
{
if (hentry->key.node.dbNode == dbid)
{
if (log_min_messages <= DEBUG2 || client_min_messages <= DEBUG2)
{
char *path = relpathperm(hentry->key.node, hentry->key.forkno);
elog(DEBUG2, "page %u of relation %s has been dropped",
hentry->key.blkno, path);
pfree(path);
}
if (hash_search(invalid_page_tab,
(void *) &hentry->key,
HASH_REMOVE, NULL) == NULL)
elog(ERROR, "hash table corrupted");
}
}
}
| void FreeFakeRelcacheEntry | ( | Relation | fakerel | ) |
Definition at line 434 of file xlogutils.c.
References pfree().
Referenced by btree_xlog_cleanup(), ginContinueSplit(), heap_xlog_delete(), heap_xlog_insert(), heap_xlog_multi_insert(), heap_xlog_update(), heap_xlog_visible(), and smgr_redo().
{
pfree(fakerel);
}
| static void log_invalid_page | ( | RelFileNode | node, | |
| ForkNumber | forkno, | |||
| BlockNumber | blkno, | |||
| bool | present | |||
| ) | [static] |
Definition at line 74 of file xlogutils.c.
References xl_invalid_page_key::blkno, client_min_messages, DEBUG1, elog, HASHCTL::entrysize, xl_invalid_page_key::forkno, HASHCTL::hash, hash_create(), HASH_ELEM, HASH_FUNCTION, hash_search(), HASHCTL::keysize, log_min_messages, xl_invalid_page_key::node, NULL, PANIC, xl_invalid_page::present, reachedConsistency, report_invalid_page(), and WARNING.
Referenced by XLogReadBufferExtended().
{
xl_invalid_page_key key;
xl_invalid_page *hentry;
bool found;
/*
* Once recovery has reached a consistent state, the invalid-page table
* should be empty and remain so. If a reference to an invalid page is
* found after consistency is reached, PANIC immediately. This might seem
* aggressive, but it's better than letting the invalid reference linger
* in the hash table until the end of recovery and PANIC there, which
* might come only much later if this is a standby server.
*/
if (reachedConsistency)
{
report_invalid_page(WARNING, node, forkno, blkno, present);
elog(PANIC, "WAL contains references to invalid pages");
}
/*
* Log references to invalid pages at DEBUG1 level. This allows some
* tracing of the cause (note the elog context mechanism will tell us
* something about the XLOG record that generated the reference).
*/
if (log_min_messages <= DEBUG1 || client_min_messages <= DEBUG1)
report_invalid_page(DEBUG1, node, forkno, blkno, present);
if (invalid_page_tab == NULL)
{
/* create hash table when first needed */
HASHCTL ctl;
memset(&ctl, 0, sizeof(ctl));
ctl.keysize = sizeof(xl_invalid_page_key);
ctl.entrysize = sizeof(xl_invalid_page);
ctl.hash = tag_hash;
invalid_page_tab = hash_create("XLOG invalid-page table",
100,
&ctl,
HASH_ELEM | HASH_FUNCTION);
}
/* we currently assume xl_invalid_page_key contains no padding */
key.node = node;
key.forkno = forkno;
key.blkno = blkno;
hentry = (xl_invalid_page *)
hash_search(invalid_page_tab, (void *) &key, HASH_ENTER, &found);
if (!found)
{
/* hash_search already filled in the key */
hentry->present = present;
}
else
{
/* repeat reference ... leave "present" as it was */
}
}
| static void report_invalid_page | ( | int | elevel, | |
| RelFileNode | node, | |||
| ForkNumber | forkno, | |||
| BlockNumber | blkno, | |||
| bool | present | |||
| ) | [static] |
Definition at line 58 of file xlogutils.c.
References elog, pfree(), and relpathperm.
Referenced by log_invalid_page(), and XLogCheckInvalidPages().
| void XLogCheckInvalidPages | ( | void | ) |
Definition at line 217 of file xlogutils.c.
References xl_invalid_page_key::blkno, elog, xl_invalid_page_key::forkno, hash_destroy(), hash_seq_init(), hash_seq_search(), xl_invalid_page::key, xl_invalid_page_key::node, NULL, PANIC, xl_invalid_page::present, report_invalid_page(), and WARNING.
Referenced by CheckRecoveryConsistency().
{
HASH_SEQ_STATUS status;
xl_invalid_page *hentry;
bool foundone = false;
if (invalid_page_tab == NULL)
return; /* nothing to do */
hash_seq_init(&status, invalid_page_tab);
/*
* Our strategy is to emit WARNING messages for all remaining entries and
* only PANIC after we've dumped all the available info.
*/
while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL)
{
report_invalid_page(WARNING, hentry->key.node, hentry->key.forkno,
hentry->key.blkno, hentry->present);
foundone = true;
}
if (foundone)
elog(PANIC, "WAL contains references to invalid pages");
hash_destroy(invalid_page_tab);
invalid_page_tab = NULL;
}
| void XLogDropDatabase | ( | Oid | dbid | ) |
Definition at line 457 of file xlogutils.c.
References forget_invalid_pages_db(), and smgrcloseall().
Referenced by dbase_redo().
{
/*
* This is unnecessarily heavy-handed, as it will close SMgrRelation
* objects for other databases as well. DROP DATABASE occurs seldom enough
* that it's not worth introducing a variant of smgrclose for just this
* purpose. XXX: Or should we rather leave the smgr entries dangling?
*/
smgrcloseall();
forget_invalid_pages_db(dbid);
}
| void XLogDropRelation | ( | RelFileNode | rnode, | |
| ForkNumber | forknum | |||
| ) |
Definition at line 446 of file xlogutils.c.
References forget_invalid_pages().
Referenced by xact_redo_abort(), and xact_redo_commit_internal().
{
forget_invalid_pages(rnode, forknum, 0);
}
| bool XLogHaveInvalidPages | ( | void | ) |
Definition at line 207 of file xlogutils.c.
References hash_get_num_entries(), and NULL.
Referenced by RecoveryRestartPoint().
{
if (invalid_page_tab != NULL &&
hash_get_num_entries(invalid_page_tab) > 0)
return true;
return false;
}
| Buffer XLogReadBuffer | ( | RelFileNode | rnode, | |
| BlockNumber | blkno, | |||
| bool | init | |||
| ) |
Definition at line 264 of file xlogutils.c.
References buf, BUFFER_LOCK_EXCLUSIVE, BufferIsValid, LockBuffer(), MAIN_FORKNUM, RBM_NORMAL, RBM_ZERO, and XLogReadBufferExtended().
Referenced by _bt_restore_meta(), btree_xlog_cleanup(), btree_xlog_delete(), btree_xlog_delete_get_latestRemovedXid(), btree_xlog_delete_page(), btree_xlog_insert(), btree_xlog_newroot(), btree_xlog_split(), ginContinueSplit(), ginRedoCreateIndex(), ginRedoCreatePTree(), ginRedoDeleteListPages(), ginRedoDeletePage(), ginRedoInsert(), ginRedoInsertListPage(), ginRedoSplit(), ginRedoUpdateMetapage(), ginRedoVacuumPage(), gistRedoClearFollowRight(), gistRedoCreateIndex(), gistRedoPageSplitRecord(), gistRedoPageUpdateRecord(), heap_xlog_delete(), heap_xlog_freeze(), heap_xlog_inplace(), heap_xlog_insert(), heap_xlog_lock(), heap_xlog_lock_updated(), heap_xlog_multi_insert(), heap_xlog_update(), seq_redo(), spgRedoAddLeaf(), spgRedoAddNode(), spgRedoCreateIndex(), spgRedoMoveLeafs(), spgRedoPickSplit(), spgRedoSplitTuple(), spgRedoVacuumLeaf(), spgRedoVacuumRedirect(), and spgRedoVacuumRoot().
{
Buffer buf;
buf = XLogReadBufferExtended(rnode, MAIN_FORKNUM, blkno,
init ? RBM_ZERO : RBM_NORMAL);
if (BufferIsValid(buf))
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
return buf;
}
| Buffer XLogReadBufferExtended | ( | RelFileNode | rnode, | |
| ForkNumber | forknum, | |||
| BlockNumber | blkno, | |||
| ReadBufferMode | mode | |||
| ) |
Definition at line 293 of file xlogutils.c.
References Assert, BufferGetBlockNumber(), BufferGetPage, InRecovery, InvalidBackendId, InvalidBuffer, log_invalid_page(), NULL, P_NEW, PageIsNew, RBM_NORMAL, ReadBufferWithoutRelcache(), ReleaseBuffer(), smgrcreate(), smgrnblocks(), and smgropen().
Referenced by btree_xlog_vacuum(), heap_xlog_clean(), heap_xlog_newpage(), heap_xlog_visible(), RestoreBackupBlockContents(), XLogReadBuffer(), and XLogRecordPageWithFreeSpace().
{
BlockNumber lastblock;
Buffer buffer;
SMgrRelation smgr;
Assert(blkno != P_NEW);
/* Open the relation at smgr level */
smgr = smgropen(rnode, InvalidBackendId);
/*
* Create the target file if it doesn't already exist. This lets us cope
* if the replay sequence contains writes to a relation that is later
* deleted. (The original coding of this routine would instead suppress
* the writes, but that seems like it risks losing valuable data if the
* filesystem loses an inode during a crash. Better to write the data
* until we are actually told to delete the file.)
*/
smgrcreate(smgr, forknum, true);
lastblock = smgrnblocks(smgr, forknum);
if (blkno < lastblock)
{
/* page exists in file */
buffer = ReadBufferWithoutRelcache(rnode, forknum, blkno,
mode, NULL);
}
else
{
/* hm, page doesn't exist in file */
if (mode == RBM_NORMAL)
{
log_invalid_page(rnode, forknum, blkno, false);
return InvalidBuffer;
}
/* OK to extend the file */
/* we do this in recovery only - no rel-extension lock needed */
Assert(InRecovery);
buffer = InvalidBuffer;
while (blkno >= lastblock)
{
if (buffer != InvalidBuffer)
ReleaseBuffer(buffer);
buffer = ReadBufferWithoutRelcache(rnode, forknum,
P_NEW, mode, NULL);
lastblock++;
}
Assert(BufferGetBlockNumber(buffer) == blkno);
}
if (mode == RBM_NORMAL)
{
/* check that page has been initialized */
Page page = (Page) BufferGetPage(buffer);
/*
* We assume that PageIsNew is safe without a lock. During recovery,
* there should be no other backends that could modify the buffer at
* the same time.
*/
if (PageIsNew(page))
{
ReleaseBuffer(buffer);
log_invalid_page(rnode, forknum, blkno, true);
return InvalidBuffer;
}
}
return buffer;
}
| void XLogTruncateRelation | ( | RelFileNode | rnode, | |
| ForkNumber | forkNum, | |||
| BlockNumber | nblocks | |||
| ) |
Definition at line 476 of file xlogutils.c.
References forget_invalid_pages().
Referenced by smgr_redo().
{
forget_invalid_pages(rnode, forkNum, nblocks);
}
HTAB* invalid_page_tab = NULL [static] |
Definition at line 53 of file xlogutils.c.
1.7.1