diff options
author | Vadim B. Mikheev <vadim4o@yahoo.com> | 2000-10-20 11:01:21 +0000 |
---|---|---|
committer | Vadim B. Mikheev <vadim4o@yahoo.com> | 2000-10-20 11:01:21 +0000 |
commit | b58c0411bad414a5dbde8b38f615867c68adf55c (patch) | |
tree | e50db15a8b3ea5dd2cf9d54ef433835bbdae1358 /src/backend/access/transam | |
parent | e18a862d46fa3169c238a6b4a98a783c9a7896f9 (diff) | |
download | postgresql-b58c0411bad414a5dbde8b38f615867c68adf55c.tar.gz postgresql-b58c0411bad414a5dbde8b38f615867c68adf55c.zip |
redo/undo support functions and cleanups.
Diffstat (limited to 'src/backend/access/transam')
-rw-r--r-- | src/backend/access/transam/xact.c | 107 | ||||
-rw-r--r-- | src/backend/access/transam/xlog.c | 14 | ||||
-rw-r--r-- | src/backend/access/transam/xlogutils.c | 288 |
3 files changed, 391 insertions, 18 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 1e50b9e3e7f..681d8565176 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.72 2000/10/11 21:28:17 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.73 2000/10/20 11:01:04 vadim Exp $ * * NOTES * Transaction aborts can now occur two ways: @@ -154,6 +154,8 @@ */ #include "postgres.h" +#include <sys/time.h> + #include "access/nbtree.h" #include "catalog/heap.h" #include "catalog/index.h" @@ -215,6 +217,19 @@ TransactionState CurrentTransactionState = &CurrentTransactionStateData; int DefaultXactIsoLevel = XACT_READ_COMMITTED; int XactIsoLevel; +#ifdef XLOG +#include "access/xlogutils.h" + +int CommitDelay; + +void xact_redo(XLogRecPtr lsn, XLogRecord *record); +void xact_undo(XLogRecPtr lsn, XLogRecord *record); + +static void (*_RollbackFunc)(void*) = NULL; +static void *_RollbackData = NULL; + +#endif + /* ---------------- * info returned when the system is disabled * @@ -676,6 +691,28 @@ RecordTransactionCommit() */ TransactionIdCommit(xid); +#ifdef XLOG + { + xl_xact_commit xlrec; + struct timeval delay; + XLogRecPtr recptr; + + xlrec.xtime = time(NULL); + /* + * MUST SAVE ARRAY OF RELFILENODE-s TO DROP + */ + recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, + (char*) &xlrec, SizeOfXactCommit, NULL, 0); + + /* + * Sleep before commit! So we can flush more than one + * commit records per single fsync. + */ + delay.tv_sec = 0; + delay.tv_usec = CommitDelay; + (void) select(0, NULL, NULL, NULL, &delay); + } +#endif /* * Now write the log info to the disk too. */ @@ -785,6 +822,18 @@ RecordTransactionAbort() if (SharedBufferChanged && !TransactionIdDidCommit(xid)) TransactionIdAbort(xid); +#ifdef XLOG + if (SharedBufferChanged) + { + xl_xact_abort xlrec; + XLogRecPtr recptr; + + xlrec.xtime = time(NULL); + recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, + (char*) &xlrec, SizeOfXactAbort, NULL, 0); + } +#endif + /* * Tell bufmgr and smgr to release resources. */ @@ -1123,10 +1172,13 @@ AbortTransaction() AtEOXact_SPI(); AtEOXact_nbtree(); AtAbort_Cache(); - AtAbort_Locks(); AtAbort_Memory(); AtEOXact_Files(); + /* Here we'll rollback xaction changes */ + + AtAbort_Locks(); + SharedBufferChanged = false; /* safest place to do it */ /* ---------------- @@ -1663,3 +1715,54 @@ IsTransactionBlock() return false; } + +#ifdef XLOG + +void +xact_redo(XLogRecPtr lsn, XLogRecord *record) +{ + uint8 info = record->xl_info & ~XLR_INFO_MASK; + + if (info == XLOG_XACT_COMMIT) + { + xl_xact_commit *xlrec = (xl_xact_commit*) XLogRecGetData(record); + + XLogMarkCommitted(record->xl_xid); + /* MUST REMOVE FILES OF ALL DROPPED RELATIONS */ + } + else if (info == XLOG_XACT_ABORT) + { + XLogMarkAborted(record->xl_xid); + } + else + elog(STOP, "xact_redo: unknown op code %u", info); +} + +void +xact_undo(XLogRecPtr lsn, XLogRecord *record) +{ + uint8 info = record->xl_info & ~XLR_INFO_MASK; + + if (info == XLOG_XACT_COMMIT) /* shouldn't be called by XLOG */ + elog(STOP, "xact_undo: can't undo committed xaction"); + else if (info != XLOG_XACT_ABORT) + elog(STOP, "xact_redo: unknown op code %u", info); +} + +void +XactPushRollback(void (*func) (void *), void* data) +{ + if (_RollbackFunc != NULL) + elog(STOP, "XactPushRollback: already installed"); + + _RollbackFunc = func; + _RollbackData = data; +} + +void +XactPopRollback(void) +{ + _RollbackFunc = NULL; +} + +#endif diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index f04b9cae2eb..8c3cd117cb9 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.17 2000/07/04 01:49:43 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.18 2000/10/20 11:01:04 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -40,6 +40,7 @@ char ControlFilePath[MAXPGPATH]; uint32 XLOGbuffers = 0; XLogRecPtr MyLastRecPtr = {0, 0}; bool StopIfError = false; +bool InRecovery = false; SPINLOCK ControlFileLockId; SPINLOCK XidGenLockId; @@ -163,17 +164,6 @@ typedef struct CheckPoint #define NextBufIdx(curridx) \ ((curridx == XLogCtl->XLogCacheBlck) ? 0 : (curridx + 1)) -#define XLByteLT(left, right) \ - (right.xlogid > left.xlogid || \ - (right.xlogid == left.xlogid && right.xrecoff > left.xrecoff)) - -#define XLByteLE(left, right) \ - (right.xlogid > left.xlogid || \ - (right.xlogid == left.xlogid && right.xrecoff >= left.xrecoff)) - -#define XLByteEQ(left, right) \ - (right.xlogid == left.xlogid && right.xrecoff == left.xrecoff) - #define InitXLBuffer(curridx) (\ XLogCtl->xlblocks[curridx].xrecoff = \ (XLogCtl->xlblocks[Insert->curridx].xrecoff == XLogFileSize) ? \ diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c index 8f44fabaa54..a507c39bc24 100644 --- a/src/backend/access/transam/xlogutils.c +++ b/src/backend/access/transam/xlogutils.c @@ -1,6 +1,6 @@ /*------------------------------------------------------------------------- * - * xlog.c + * xlogutils.c * * * Portions Copyright (c) 1996-2000, PostgreSQL, Inc @@ -9,12 +9,26 @@ *------------------------------------------------------------------------- */ +#ifdef XLOG + #include "postgres.h" #include "access/xlog.h" #include "access/xact.h" +#include "storage/bufpage.h" +#include "storage/bufmgr.h" +#include "storage/smgr.h" +#include "access/htup.h" +#include "access/xlogutils.h" +#include "catalog/pg_database.h" -#ifdef XLOG +/* + * --------------------------------------------------------------- + * + * Index support functions + * + *---------------------------------------------------------------- + */ /* * Check if specified heap tuple was inserted by given @@ -59,7 +73,8 @@ XLogIsOwnerOfTuple(RelFileNode hnode, ItemPointer iptr, htup = (HeapTupleHeader) PageGetItem(page, lp); - if (PageGetSUI(page) != ThisStartUpID || htup->t_xmin != xid || htup->t_cmin != cid) + Assert(PageGetSUI(page) == ThisStartUpID); + if (htup->t_xmin != xid || htup->t_cmin != cid) { UnlockAndReleaseBuffer(buffer); return(-1); @@ -70,6 +85,8 @@ XLogIsOwnerOfTuple(RelFileNode hnode, ItemPointer iptr, } /* + * MUST BE CALLED ONLY ON RECOVERY. + * * Check if exists valid (inserted by not aborted xaction) heap tuple * for given item pointer */ @@ -98,6 +115,14 @@ XLogIsValidTuple(RelFileNode hnode, ItemPointer iptr) UnlockAndReleaseBuffer(buffer); return(false); } + + if (PageGetSUI(page) != ThisStartUpID) + { + Assert(PageGetSUI(page) < ThisStartUpID); + UnlockAndReleaseBuffer(buffer); + return(true); + } + lp = PageGetItemId(page, ItemPointerGetOffsetNumber(iptr)); if (!ItemIdIsUsed(lp) || ItemIdDeleted(lp)) { @@ -107,7 +132,9 @@ XLogIsValidTuple(RelFileNode hnode, ItemPointer iptr) htup = (HeapTupleHeader) PageGetItem(page, lp); - if (XLogIsAborted(PageGetSUI(page), htup->t_xmin)) + /* MUST CHECK WASN'T TUPLE INSERTED IN PREV STARTUP */ + + if (XLogIsAborted(htup->t_xmin)) { UnlockAndReleaseBuffer(buffer); return(false); @@ -117,4 +144,257 @@ XLogIsValidTuple(RelFileNode hnode, ItemPointer iptr) return(true); } +/* + * --------------------------------------------------------------- + * + * Transaction support functions for recovery + * + * On recovery we create tmp file to know what xactions were + * committed/aborted (2 bits per xaction). + * + *---------------------------------------------------------------- + */ + +bool +XLogIsAborted(TransactionId xid) +{ + return(false); +} + +bool +XLogIsCommitted(TransactionId xid) +{ + return(true); +} + +void +XLogMarkAborted(TransactionId xid) +{ + return; +} + +void +XLogMarkCommitted(TransactionId xid) +{ + return; +} + + +/* + * --------------------------------------------------------------- + * + * Storage related support functions + * + *---------------------------------------------------------------- + */ + +Buffer +XLogReadBuffer(bool extend, Relation reln, BlockNumber blkno) +{ + BlockNumber lastblock = RelationGetNumberOfBlocks(reln); + Buffer buffer; + + if (blkno >= lastblock) + { + buffer = InvalidBuffer; + if (extend) /* we do this in recovery only - no locks */ + { + Assert(InRecovery); + while (lastblock <= blkno) + { + buffer = ReadBuffer(reln, P_NEW); + lastblock++; + } + } + if (buffer != InvalidBuffer) + LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); + return(buffer); + } + + buffer = ReadBuffer(reln, blkno); + if (buffer != InvalidBuffer) + LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); + return(buffer); +} + +/* + * "Relation" cache + */ + +typedef struct XLogRelDesc +{ + RelationData reldata; + struct XLogRelDesc *lessRecently; + struct XLogRelDesc *moreRecently; +} XLogRelDesc; + +typedef struct XLogRelCacheEntry +{ + RelFileNode rnode; + XLogRelDesc *rdesc; +} XLogRelCacheEntry; + +static HTAB *_xlrelcache; +static XLogRelDesc *_xlrelarr = NULL; +static Form_pg_class _xlpgcarr = NULL; +static int _xlast = 0; +static int _xlcnt = 0; +#define _XLOG_INITRELCACHESIZE 32 +#define _XLOG_MAXRELCACHESIZE 512 + +void +XLogCloseRelationCache(void) +{ + int i; + + if (!_xlrelarr) + return; + + for (i = 1; i < _xlast; i++) + { + Relation reln = &(_xlrelarr[i].reldata); + if (reln->rd_fd >= 0) + smgrclose(DEFAULT_SMGR, reln); + } + + free(_xlrelarr); + free(_xlpgcarr); + + hash_destroy(_xlrelcache); + _xlrelarr = NULL; +} + +static void +_xl_init_rel_cache(void) +{ + HASHCTL ctl; + + _xlcnt = _XLOG_INITRELCACHESIZE; + _xlast = 0; + _xlrelarr = (XLogRelDesc*) malloc(sizeof(XLogRelDesc) * _xlcnt); + memset(_xlrelarr, 0, sizeof(XLogRelDesc) * _xlcnt); + _xlpgcarr = (Form_pg_class) malloc(sizeof(FormData_pg_class) * _xlcnt); + memset(_xlpgcarr, 0, sizeof(XLogRelDesc) * _xlcnt); + + memset(&ctl, 0, (int) sizeof(ctl)); + ctl.keysize = sizeof(RelFileNode); + ctl.datasize = sizeof(XLogRelDesc*); + ctl.hash = tag_hash; + + _xlrelcache = hash_create(_XLOG_INITRELCACHESIZE, &ctl, + HASH_ELEM | HASH_FUNCTION); +} + +static XLogRelDesc* +_xl_new_reldesc(void) +{ + _xlast++; + if (_xlast < _xlcnt) + { + _xlrelarr[_xlast].reldata.rd_rel = &(_xlpgcarr[_xlast]); + return(&(_xlrelarr[_xlast])); + } + + if ( 2 * _xlcnt <= _XLOG_MAXRELCACHESIZE) + { + _xlrelarr = (XLogRelDesc*) realloc(_xlrelarr, + 2 * sizeof(XLogRelDesc) * _xlcnt); + memset(&(_xlrelarr[_xlcnt]), 0, sizeof(XLogRelDesc) * _xlcnt); + _xlpgcarr = (Form_pg_class) realloc(_xlpgcarr, + 2 * sizeof(FormData_pg_class) * _xlcnt); + memset(&(_xlpgcarr[_xlcnt]), 0, sizeof(FormData_pg_class) * _xlcnt); + _xlcnt += _xlcnt; + _xlrelarr[_xlast].reldata.rd_rel = &(_xlpgcarr[_xlast]); + return(&(_xlrelarr[_xlast])); + } + else /* reuse */ + { + XLogRelCacheEntry *hentry; + bool found; + XLogRelDesc *res = _xlrelarr[0].moreRecently; + Form_pg_class tpgc = res->reldata.rd_rel; + + res->lessRecently->moreRecently = res->moreRecently; + res->moreRecently->lessRecently = res->lessRecently; + + hentry = (XLogRelCacheEntry*) hash_search(_xlrelcache, + (char*)&(res->reldata.rd_node), HASH_REMOVE, &found); + + if (hentry == NULL) + elog(STOP, "XLogOpenRelation: can't delete from cache"); + if (!found) + elog(STOP, "XLogOpenRelation: file was not found in cache"); + + if (res->reldata.rd_fd >= 0) + smgrclose(DEFAULT_SMGR, &(res->reldata)); + + memset(res, 0, sizeof(XLogRelDesc)); + memset(tpgc, 0, sizeof(FormData_pg_class)); + res->reldata.rd_rel = tpgc; + + _xlast--; + return(res); + } +} + +Relation +XLogOpenRelation(bool redo, RmgrId rmid, RelFileNode rnode) +{ + XLogRelDesc *res; + XLogRelCacheEntry *hentry; + bool found; + + if (!_xlrelarr) + _xl_init_rel_cache(); + + hentry = (XLogRelCacheEntry*) + hash_search(_xlrelcache, (char*)&rnode, HASH_FIND, &found); + + if (hentry == NULL) + elog(STOP, "XLogOpenRelation: error in cache"); + + if (found) + { + res = hentry->rdesc; + + res->lessRecently->moreRecently = res->moreRecently; + res->moreRecently->lessRecently = res->lessRecently; + } + else + { + res = _xl_new_reldesc(); + + sprintf(RelationGetPhysicalRelationName(&(res->reldata)), "%u", rnode.relNode); + + /* unexisting DB id */ + res->reldata.rd_lockInfo.lockRelId.dbId = RecoveryDb; + res->reldata.rd_lockInfo.lockRelId.relId = rnode.relNode; + res->reldata.rd_node = rnode; + + hentry = (XLogRelCacheEntry*) + hash_search(_xlrelcache, (char*)&rnode, HASH_ENTER, &found); + + if (hentry == NULL) + elog(STOP, "XLogOpenRelation: can't insert into cache"); + + if (found) + elog(STOP, "XLogOpenRelation: file found on insert into cache"); + + hentry->rdesc = res; + + res->reldata.rd_unlinked = true; /* look smgropen */ + res->reldata.rd_fd = smgropen(DEFAULT_SMGR, &(res->reldata)); + } + + res->moreRecently = &(_xlrelarr[0]); + res->lessRecently = _xlrelarr[0].lessRecently; + _xlrelarr[0].lessRecently = res; + res->lessRecently->moreRecently = res; + + if (res->reldata.rd_fd < 0) /* file doesn't exist */ + return(NULL); + + return(&(res->reldata)); +} + #endif |