diff --git a/src/backend/access/transam/rmgr.c b/src/backend/access/transam/rmgr.c index 31a9a1a39d7193dc054f59df917f95d23f803685..ca8b77de573533f2e8d8d6ecc604f4d1ab8555b1 100644 --- a/src/backend/access/transam/rmgr.c +++ b/src/backend/access/transam/rmgr.c @@ -7,8 +7,7 @@ #include "access/xact.h" #include "access/xlog.h" #include "storage/smgr.h" - -#ifdef XLOG +#include "commands/sequence.h" RmgrData RmgrTable[] = { {"XLOG", xlog_redo, xlog_undo, xlog_desc}, @@ -25,15 +24,7 @@ RmgrData RmgrTable[] = { {"Btree", btree_redo, btree_undo, btree_desc}, {"Hash", hash_redo, hash_undo, hash_desc}, {"Rtree", rtree_redo, rtree_undo, rtree_desc}, -{"Gist", gist_redo, gist_undo, gist_desc} +{"Gist", gist_redo, gist_undo, gist_desc}, +{"Sequence", seq_redo, seq_undo, seq_desc} }; -#else /* not XLOG */ - -/* - * This is a dummy, but don't write RmgrTable[] = {} here, - * that's not accepted by some compilers. -- petere - */ -RmgrData RmgrTable[1]; - -#endif /* not XLOG */ diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index f1d264f130d43b92d9aadc4322d04064167becca..df679d277de75391a8cfff7ad347408a6ed2767c 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.84 2000/11/21 21:15:57 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.85 2000/11/30 01:47:31 vadim Exp $ * * NOTES * Transaction aborts can now occur two ways: @@ -222,7 +222,7 @@ int XactIsoLevel; #ifdef XLOG #include "access/xlogutils.h" -int CommitDelay = 5; /* 1/200 sec */ +int CommitDelay = 5; /* 1/200000 sec */ static void (*_RollbackFunc)(void*) = NULL; static void *_RollbackData = NULL; diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index c70dbc7b4fbe8edef792a7ab01f1a542c52a10bf..b96159b41446f3d687c4c1147dcbdb1b2894a93e 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.36 2000/11/28 23:27:54 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.37 2000/11/30 01:47:31 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -240,17 +240,26 @@ static bool InRedo = false; XLogRecPtr XLogInsert(RmgrId rmid, uint8 info, char *hdr, uint32 hdrlen, char *buf, uint32 buflen) { - XLogCtlInsert *Insert = &XLogCtl->Insert; - XLogRecord *record; - XLogSubRecord *subrecord; - XLogRecPtr RecPtr; - uint32 len = hdrlen + buflen, - freespace, - wlen; - uint16 curridx; - bool updrqst = false; + XLogCtlInsert *Insert = &XLogCtl->Insert; + XLogRecord *record; + XLogSubRecord *subrecord; + XLogRecPtr RecPtr; + uint32 len = hdrlen + buflen, + freespace, + wlen; + uint16 curridx; + bool updrqst = false; + bool no_tran = (rmid == RM_XLOG_ID) ? true : false; + + if (info & XLR_INFO_MASK) + { + if ((info & XLR_INFO_MASK) != XLOG_NO_TRAN) + elog(STOP, "XLogInsert: invalid info mask %02X", + (info & XLR_INFO_MASK)); + no_tran = true; + info &= ~XLR_INFO_MASK; + } - Assert(!(info & XLR_INFO_MASK)); if (len == 0 || len > MAXLOGRECSZ) elog(STOP, "XLogInsert: invalid record len %u", len); @@ -324,13 +333,14 @@ XLogInsert(RmgrId rmid, uint8 info, char *hdr, uint32 hdrlen, char *buf, uint32 freespace -= SizeOfXLogRecord; record = (XLogRecord *) Insert->currpos; record->xl_prev = Insert->PrevRecord; - if (rmid != RM_XLOG_ID) - record->xl_xact_prev = MyLastRecPtr; - else + if (no_tran) { record->xl_xact_prev.xlogid = 0; record->xl_xact_prev.xrecoff = 0; } + else + record->xl_xact_prev = MyLastRecPtr; + record->xl_xid = GetCurrentTransactionId(); record->xl_len = (len > freespace) ? freespace : len; record->xl_info = (len > freespace) ? @@ -340,7 +350,7 @@ XLogInsert(RmgrId rmid, uint8 info, char *hdr, uint32 hdrlen, char *buf, uint32 RecPtr.xrecoff = XLogCtl->xlblocks[curridx].xrecoff - BLCKSZ + Insert->currpos - ((char *) Insert->currpage); - if (MyLastRecPtr.xrecoff == 0 && rmid != RM_XLOG_ID) + if (MyLastRecPtr.xrecoff == 0 && !no_tran) { SpinAcquire(SInvalLock); MyProc->logRec = RecPtr; diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index d6a6b1b4300cdaa526d25dd3d68311224c625e61..210657cdf067900ec2f527d258c37b828e3e5b36 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -22,19 +22,12 @@ #define SEQ_MAXVALUE ((int4)0x7FFFFFFF) #define SEQ_MINVALUE -(SEQ_MAXVALUE) -typedef struct FormData_pg_sequence -{ - NameData sequence_name; - int4 last_value; - int4 increment_by; - int4 max_value; - int4 min_value; - int4 cache_value; - char is_cycled; - char is_called; -} FormData_pg_sequence; - -typedef FormData_pg_sequence *Form_pg_sequence; +/* + * We don't want to log each fetching values from sequences, + * so we pre-log a few fetches in advance. In the event of + * crash we can lose as much as we pre-logged. + */ +#define SEQ_LOG_VALS 32 typedef struct sequence_magic { @@ -138,6 +131,11 @@ DefineSequence(CreateSeqStmt *seq) coldef->colname = "cache_value"; value[i - 1] = Int32GetDatum(new.cache_value); break; + case SEQ_COL_LOG: + typnam->name = "int4"; + coldef->colname = "log_cnt"; + value[i - 1] = Int32GetDatum((int32)1); + break; case SEQ_COL_CYCLE: typnam->name = "char"; coldef->colname = "is_cycled"; @@ -196,10 +194,14 @@ nextval(PG_FUNCTION_ARGS) int32 incby, maxv, minv, - cache; + cache, + log, + fetch, + last; int32 result, next, rescnt = 0; + bool logit = false; if (pg_aclcheck(seqname, GetUserId(), ACL_WR) != ACLCHECK_OK) elog(ERROR, "%s.nextval: you don't have permissions to set sequence %s", @@ -219,16 +221,27 @@ nextval(PG_FUNCTION_ARGS) seq = read_info("nextval", elm, &buf); /* lock page' buffer and * read tuple */ - next = result = seq->last_value; + last = next = result = seq->last_value; incby = seq->increment_by; maxv = seq->max_value; minv = seq->min_value; - cache = seq->cache_value; + fetch = cache = seq->cache_value; + log = seq->log_cnt; if (seq->is_called != 't') + { rescnt++; /* last_value if not called */ + fetch--; + log--; + } - while (rescnt < cache) /* try to fetch cache numbers */ + if (log < fetch) + { + fetch = log = fetch - log + SEQ_LOG_VALS; + logit = true; + } + + while (fetch) /* try to fetch cache [+ log ] numbers */ { /* @@ -242,7 +255,7 @@ nextval(PG_FUNCTION_ARGS) (maxv < 0 && next + incby > maxv)) { if (rescnt > 0) - break; /* stop caching */ + break; /* stop fetching */ if (seq->is_cycled != 't') elog(ERROR, "%s.nextval: got MAXVALUE (%d)", elm->name, maxv); @@ -258,7 +271,7 @@ nextval(PG_FUNCTION_ARGS) (minv >= 0 && next + incby < minv)) { if (rescnt > 0) - break; /* stop caching */ + break; /* stop fetching */ if (seq->is_cycled != 't') elog(ERROR, "%s.nextval: got MINVALUE (%d)", elm->name, minv); @@ -267,17 +280,43 @@ nextval(PG_FUNCTION_ARGS) else next += incby; } - rescnt++; /* got result */ - if (rescnt == 1) /* if it's first one - */ - result = next; /* it's what to return */ + fetch--; + if (rescnt < cache) + { + log--; + rescnt++; + last = next; + if (rescnt == 1) /* if it's first result - */ + result = next; /* it's what to return */ + } } /* save info in local cache */ elm->last = result; /* last returned number */ - elm->cached = next; /* last cached number */ + elm->cached = last; /* last fetched number */ + + if (logit) + { + xl_seq_rec xlrec; + XLogRecPtr recptr; + + if (fetch) /* not all numbers were fetched */ + log -= fetch; + + xlrec.node = elm->rel->rd_node; + xlrec.value = next; + + recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG|XLOG_NO_TRAN, + (char*) &xlrec, sizeof(xlrec), NULL, 0); + + PageSetLSN(BufferGetPage(buf), recptr); + PageSetSUI(BufferGetPage(buf), ThisStartUpID); + } /* save info in sequence relation */ - seq->last_value = next; /* last fetched number */ + seq->last_value = last; /* last fetched number */ + Assert(log >= 0); + seq->log_cnt = log; /* how much is logged */ seq->is_called = 't'; LockBuffer(buf, BUFFER_LOCK_UNLOCK); @@ -349,6 +388,21 @@ do_setval(char *seqname, int32 next, bool iscalled) /* save info in sequence relation */ seq->last_value = next; /* last fetched number */ seq->is_called = iscalled ? 't' : 'f'; + seq->log_cnt = (iscalled) ? 0 : 1; + + { + xl_seq_rec xlrec; + XLogRecPtr recptr; + + xlrec.node = elm->rel->rd_node; + xlrec.value = next; + + recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_SET|XLOG_NO_TRAN, + (char*) &xlrec, sizeof(xlrec), NULL, 0); + + PageSetLSN(BufferGetPage(buf), recptr); + PageSetSUI(BufferGetPage(buf), ThisStartUpID); + } LockBuffer(buf, BUFFER_LOCK_UNLOCK); @@ -638,7 +692,6 @@ init_params(CreateSeqStmt *seq, Form_pg_sequence new) } - static int get_param(DefElem *def) { @@ -651,3 +704,80 @@ get_param(DefElem *def) elog(ERROR, "DefineSequence: \"%s\" is to be integer", def->defname); return -1; } + +void seq_redo(XLogRecPtr lsn, XLogRecord *record) +{ + uint8 info = record->xl_info & ~XLR_INFO_MASK; + Relation reln; + Buffer buffer; + Page page; + ItemId lp; + HeapTupleData tuple; + Form_pg_sequence seq; + xl_seq_rec *xlrec; + + if (info != XLOG_SEQ_LOG && info != XLOG_SEQ_SET) + elog(STOP, "seq_redo: unknown op code %u", info); + + xlrec = (xl_seq_rec*) XLogRecGetData(record); + + reln = XLogOpenRelation(true, RM_SEQ_ID, xlrec->node); + if (!RelationIsValid(reln)) + return; + + buffer = XLogReadBuffer(false, reln, 0); + if (!BufferIsValid(buffer)) + elog(STOP, "seq_redo: can't read block of %u/%u", + xlrec->node.tblNode, xlrec->node.relNode); + + page = (Page) BufferGetPage(buffer); + if (PageIsNew((PageHeader) page) || + ((sequence_magic *) PageGetSpecialPointer(page))->magic != SEQ_MAGIC) + elog(STOP, "seq_redo: uninitialized page of %u/%u", + xlrec->node.tblNode, xlrec->node.relNode); + + if (XLByteLE(lsn, PageGetLSN(page))) + { + UnlockAndReleaseBuffer(buffer); + return; + } + + lp = PageGetItemId(page, FirstOffsetNumber); + Assert(ItemIdIsUsed(lp)); + tuple.t_data = (HeapTupleHeader) PageGetItem((Page) page, lp); + + seq = (Form_pg_sequence) GETSTRUCT(&tuple); + + seq->last_value = xlrec->value; /* last logged value */ + seq->is_called = 't'; + seq->log_cnt = 0; + + PageSetLSN(page, lsn); + PageSetSUI(page, ThisStartUpID); + UnlockAndWriteBuffer(buffer); + + return; +} + +void seq_undo(XLogRecPtr lsn, XLogRecord *record) +{ +} + +void seq_desc(char *buf, uint8 xl_info, char* rec) +{ + uint8 info = xl_info & ~XLR_INFO_MASK; + xl_seq_rec *xlrec = (xl_seq_rec*) rec; + + if (info == XLOG_SEQ_LOG) + strcat(buf, "log: "); + else if (info == XLOG_SEQ_SET) + strcat(buf, "set: "); + else + { + strcat(buf, "UNKNOWN"); + return; + } + + sprintf(buf + strlen(buf), "node %u/%u; value %d", + xlrec->node.tblNode, xlrec->node.relNode, xlrec->value); +} diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 398fb25bf6818d7fb7eb9cb946f45a562c767383..046c304e24d99bc2a2055648c277033a53a561f0 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -4,7 +4,7 @@ * Support for grand unified configuration scheme, including SET * command, configuration file, and command line options. * - * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.24 2000/11/29 20:59:53 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.25 2000/11/30 01:47:32 vadim Exp $ * * Copyright 2000 by PostgreSQL Global Development Group * Written by Peter Eisentraut <peter_e@gmx.net>. @@ -39,6 +39,8 @@ extern bool Log_connections; extern int CheckPointTimeout; extern int XLOGbuffers; extern int XLOG_DEBUG; +extern int CommitDelay; + #ifdef ENABLE_SYSLOG extern char *Syslog_facility; extern char *Syslog_ident; @@ -266,15 +268,18 @@ ConfigureNamesInt[] = {"unix_socket_permissions", PGC_POSTMASTER, &Unix_socket_permissions, 0777, 0000, 0777}, - {"checkpoint_timeout", PGC_POSTMASTER, &CheckPointTimeout, + {"checkpoint_timeout", PGC_POSTMASTER, &CheckPointTimeout, 300, 30, 1800}, - {"wal_buffers", PGC_POSTMASTER, &XLOGbuffers, + {"wal_buffers", PGC_POSTMASTER, &XLOGbuffers, 8, 4, INT_MAX}, - {"wal_debug", PGC_POSTMASTER, &XLOG_DEBUG, + {"wal_debug", PGC_SUSET, &XLOG_DEBUG, 0, 0, 16}, + {"commit_delay", PGC_USERSET, &CommitDelay, + 5, 0, 1000}, + {NULL, 0, NULL, 0, 0, 0} }; diff --git a/src/include/access/htup.h b/src/include/access/htup.h index 177176e434ab62eddb644886a727808128fcdd80..6484abf36d8eebc158df46429c1b65b7a17b1079 100644 --- a/src/include/access/htup.h +++ b/src/include/access/htup.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: htup.h,v 1.39 2000/11/14 21:04:32 tgl Exp $ + * $Id: htup.h,v 1.40 2000/11/30 01:47:32 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -186,9 +186,9 @@ extern long heap_sysoffset[]; */ typedef struct HeapTupleData { - uint32 t_len; /* length of *t_data */ + uint32 t_len; /* length of *t_data */ ItemPointerData t_self; /* SelfItemPointer */ - Oid t_tableOid; /* table the tuple came from */ + Oid t_tableOid; /* table the tuple came from */ MemoryContext t_datamcxt; /* mcxt in which allocated */ HeapTupleHeader t_data; /* -> tuple header and data */ } HeapTupleData; diff --git a/src/include/access/rmgr.h b/src/include/access/rmgr.h index 221c52d2f2b5ea7bf0c9e1579a0abf74bfedfa24..af721e9fe763df848f735cc5e4d3e182a771b287 100644 --- a/src/include/access/rmgr.h +++ b/src/include/access/rmgr.h @@ -21,6 +21,7 @@ typedef uint8 RmgrId; #define RM_HASH_ID 12 #define RM_RTREE_ID 13 #define RM_GIST_ID 14 -#define RM_MAX_ID RM_GIST_ID +#define RM_SEQ_ID 15 +#define RM_MAX_ID RM_SEQ_ID #endif /* RMGR_H */ diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 4654296e116eefd1ef3c8ab75a9fa3b11927e3c4..785ac94c9b20a48d015dee294126dd850cdd8b00 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -3,7 +3,7 @@ * * PostgreSQL transaction log manager * - * $Header: /cvsroot/pgsql/src/include/access/xlog.h,v 1.11 2000/11/25 20:33:53 tgl Exp $ + * $Header: /cvsroot/pgsql/src/include/access/xlog.h,v 1.12 2000/11/30 01:47:32 vadim Exp $ */ #ifndef XLOG_H #define XLOG_H @@ -54,6 +54,12 @@ typedef struct XLogSubRecord #define XLR_TO_BE_CONTINUED 0x01 #define XLR_INFO_MASK 0x0F +/* + * Sometimes we log records which are out of transaction control. + * Rmgr may use flag below for this purpose. + */ +#define XLOG_NO_TRAN XLR_INFO_MASK + #define XLOG_PAGE_MAGIC 0x17345168 typedef struct XLogPageHeaderData diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 85e4c02b53317a8cb92d99a230eedb27fa3ca4e5..93958d5ec059ea0fbdda8a66f226453056fdc5f7 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: catversion.h,v 1.64 2000/11/25 20:33:53 tgl Exp $ + * $Id: catversion.h,v 1.65 2000/11/30 01:47:33 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200011251 +#define CATALOG_VERSION_NO 200011291 #endif diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h index 0429d2295324b28721d5cf6691a55a73d8385f5a..415364862b23190d4e37b2ddebe76b8376c8e011 100644 --- a/src/include/commands/sequence.h +++ b/src/include/commands/sequence.h @@ -10,6 +10,22 @@ #define SEQUENCE_H #include "nodes/parsenodes.h" +#include "access/xlog.h" + +typedef struct FormData_pg_sequence +{ + NameData sequence_name; + int4 last_value; + int4 increment_by; + int4 max_value; + int4 min_value; + int4 cache_value; + int4 log_cnt; + char is_cycled; + char is_called; +} FormData_pg_sequence; + +typedef FormData_pg_sequence *Form_pg_sequence; /* * Columns of a sequence relation @@ -21,12 +37,23 @@ #define SEQ_COL_MAXVALUE 4 #define SEQ_COL_MINVALUE 5 #define SEQ_COL_CACHE 6 -#define SEQ_COL_CYCLE 7 -#define SEQ_COL_CALLED 8 +#define SEQ_COL_LOG 7 +#define SEQ_COL_CYCLE 8 +#define SEQ_COL_CALLED 9 #define SEQ_COL_FIRSTCOL SEQ_COL_NAME #define SEQ_COL_LASTCOL SEQ_COL_CALLED +/* XLOG stuff */ +#define XLOG_SEQ_LOG 0x00 +#define XLOG_SEQ_SET 0x10 + +typedef struct xl_seq_rec +{ + RelFileNode node; + int4 value; /* last logged value */ +} xl_seq_rec; + extern Datum nextval(PG_FUNCTION_ARGS); extern Datum currval(PG_FUNCTION_ARGS); extern Datum setval(PG_FUNCTION_ARGS); @@ -35,4 +62,8 @@ extern Datum setval_and_iscalled(PG_FUNCTION_ARGS); extern void DefineSequence(CreateSeqStmt *stmt); extern void CloseSequences(void); +extern void seq_redo(XLogRecPtr lsn, XLogRecord *rptr); +extern void seq_undo(XLogRecPtr lsn, XLogRecord *rptr); +extern void seq_desc(char *buf, uint8 xl_info, char* rec); + #endif /* SEQUENCE_H */