#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.