Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion contrib/hstore/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ DATA = hstore--1.4.sql \
hstore--1.5--1.6.sql \
hstore--1.4--1.5.sql \
hstore--1.3--1.4.sql hstore--1.2--1.3.sql \
hstore--1.1--1.2.sql hstore--1.0--1.1.sql
hstore--1.1--1.2.sql
PGFILEDESC = "hstore - key/value pair data type"

HEADERS = hstore.h
Expand Down
7 changes: 0 additions & 7 deletions contrib/hstore/hstore--1.0--1.1.sql

This file was deleted.

4 changes: 3 additions & 1 deletion doc/src/sgml/catalogs.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -10226,7 +10226,8 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
and general database objects (identified by class OID and object OID,
in the same way as in <structname>pg_description</structname> or
<structname>pg_depend</structname>). Also, the right to extend a
relation is represented as a separate lockable object.
relation is represented as a separate lockable object, as is the right to
update <structname>pg_database</structname>.<structfield>datfrozenxid</structfield>.
Also, <quote>advisory</quote> locks can be taken on numbers that have
user-defined meanings.
</para>
Expand Down Expand Up @@ -10254,6 +10255,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
Type of the lockable object:
<literal>relation</literal>,
<literal>extend</literal>,
<literal>frozenid</literal>,
<literal>page</literal>,
<literal>tuple</literal>,
<literal>transactionid</literal>,
Expand Down
16 changes: 16 additions & 0 deletions doc/src/sgml/monitoring.sgml
Original file line number Diff line number Diff line change
Expand Up @@ -1742,6 +1742,12 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser
<entry><literal>extend</literal></entry>
<entry>Waiting to extend a relation.</entry>
</row>
<row>
<entry><literal>frozenid</literal></entry>
<entry>Waiting to
update <structname>pg_database</structname>.<structfield>datfrozenxid</structfield>
and <structname>pg_database</structname>.<structfield>datminmxid</structfield>.</entry>
</row>
<row>
<entry><literal>object</literal></entry>
<entry>Waiting to acquire a lock on a non-relation database object.</entry>
Expand Down Expand Up @@ -1910,6 +1916,11 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser
<entry><literal>NotifyQueue</literal></entry>
<entry>Waiting to read or update <command>NOTIFY</command> messages.</entry>
</row>
<row>
<entry><literal>NotifyQueueTail</literal></entry>
<entry>Waiting to update limit on <command>NOTIFY</command> message
storage.</entry>
</row>
<row>
<entry><literal>NotifySLRU</literal></entry>
<entry>Waiting to access the <command>NOTIFY</command> message SLRU
Expand Down Expand Up @@ -2086,6 +2097,11 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser
<entry><literal>WALWrite</literal></entry>
<entry>Waiting for WAL buffers to be written to disk.</entry>
</row>
<row>
<entry><literal>WrapLimitsVacuum</literal></entry>
<entry>Waiting to update limits on transaction id and multixact
consumption.</entry>
</row>
<row>
<entry><literal>XactBuffer</literal></entry>
<entry>Waiting for I/O on a transaction status SLRU buffer.</entry>
Expand Down
324 changes: 171 additions & 153 deletions doc/src/sgml/ref/pg_basebackup.sgml

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions src/backend/access/heap/heapam.c
Original file line number Diff line number Diff line change
Expand Up @@ -6920,8 +6920,6 @@ HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
* updated/deleted by the inserting transaction.
*
* Look for a committed hint bit, or if no xmin bit is set, check clog.
* This needs to work on both primary and standby, where it is used to
* assess btree delete records.
*/
if (HeapTupleHeaderXminCommitted(tuple) ||
(!HeapTupleHeaderXminInvalid(tuple) && TransactionIdDidCommit(xmin)))
Expand Down
11 changes: 5 additions & 6 deletions src/backend/access/transam/README
Original file line number Diff line number Diff line change
Expand Up @@ -635,12 +635,11 @@ be reconstructed later following a crash and the action is simply a way
of optimising for performance. When a hint is written we use
MarkBufferDirtyHint() to mark the block dirty.

If the buffer is clean and checksums are in use then
MarkBufferDirtyHint() inserts an XLOG_FPI record to ensure that we
take a full page image that includes the hint. We do this to avoid
a partial page write, when we write the dirtied page. WAL is not
written during recovery, so we simply skip dirtying blocks because
of hints when in recovery.
If the buffer is clean and checksums are in use then MarkBufferDirtyHint()
inserts an XLOG_FPI_FOR_HINT record to ensure that we take a full page image
that includes the hint. We do this to avoid a partial page write, when we
write the dirtied page. WAL is not written during recovery, so we simply skip
dirtying blocks because of hints when in recovery.

If you do decide to optimise away a WAL record, then any calls to
MarkBufferDirty() must be replaced by MarkBufferDirtyHint(),
Expand Down
8 changes: 8 additions & 0 deletions src/backend/access/transam/slru.c
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,14 @@ SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)

/*
* Remove all segments before the one holding the passed page number
*
* All SLRUs prevent concurrent calls to this function, either with an LWLock
* or by calling it only as part of a checkpoint. Mutual exclusion must begin
* before computing cutoffPage. Mutual exclusion must end after any limit
* update that would permit other backends to write fresh data into the
* segment immediately preceding the one containing cutoffPage. Otherwise,
* when the SLRU is quite full, SimpleLruTruncate() might delete that segment
* after it has accrued freshly-written data.
*/
void
SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
Expand Down
4 changes: 2 additions & 2 deletions src/backend/access/transam/subtrans.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,8 @@ ExtendSUBTRANS(TransactionId newestXact)
/*
* Remove all SUBTRANS segments before the one holding the passed transaction ID
*
* This is normally called during checkpoint, with oldestXact being the
* oldest TransactionXmin of any running transaction.
* oldestXact is the oldest TransactionXmin of any running transaction. This
* is called only during checkpoint.
*/
void
TruncateSUBTRANS(TransactionId oldestXact)
Expand Down
13 changes: 7 additions & 6 deletions src/backend/access/transam/varsup.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,12 +367,13 @@ SetTransactionIdLimit(TransactionId oldest_datfrozenxid, Oid oldest_datoid)
* We'll refuse to continue assigning XIDs in interactive mode once we get
* within 3M transactions of data loss. This leaves lots of room for the
* DBA to fool around fixing things in a standalone backend, while not
* being significant compared to total XID space. (Note that since
* vacuuming requires one transaction per table cleaned, we had better be
* sure there's lots of XIDs left...) Also, at default BLCKSZ, this
* leaves two completely-idle segments. In the event of edge-case bugs
* involving page or segment arithmetic, idle segments render the bugs
* unreachable outside of single-user mode.
* being significant compared to total XID space. (VACUUM requires an XID
* if it truncates at wal_level!=minimal. "VACUUM (ANALYZE)", which a DBA
* might do by reflex, assigns an XID. Hence, we had better be sure
* there's lots of XIDs left...) Also, at default BLCKSZ, this leaves two
* completely-idle segments. In the event of edge-case bugs involving
* page or segment arithmetic, idle segments render the bugs unreachable
* outside of single-user mode.
*/
xidStopLimit = xidWrapLimit - 3000000;
if (xidStopLimit < FirstNormalTransactionId)
Expand Down
48 changes: 31 additions & 17 deletions src/backend/commands/async.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,19 +244,22 @@ typedef struct QueueBackendStatus
/*
* Shared memory state for LISTEN/NOTIFY (excluding its SLRU stuff)
*
* The AsyncQueueControl structure is protected by the NotifyQueueLock.
* The AsyncQueueControl structure is protected by the NotifyQueueLock and
* NotifyQueueTailLock.
*
* When holding the lock in SHARED mode, backends may only inspect their own
* entries as well as the head and tail pointers. Consequently we can allow a
* backend to update its own record while holding only SHARED lock (since no
* other backend will inspect it).
* When holding NotifyQueueLock in SHARED mode, backends may only inspect
* their own entries as well as the head and tail pointers. Consequently we
* can allow a backend to update its own record while holding only SHARED lock
* (since no other backend will inspect it).
*
* When holding the lock in EXCLUSIVE mode, backends can inspect the entries
* of other backends and also change the head and tail pointers.
* When holding NotifyQueueLock in EXCLUSIVE mode, backends can inspect the
* entries of other backends and also change the head pointer. When holding
* both NotifyQueueLock and NotifyQueueTailLock in EXCLUSIVE mode, backends
* can change the tail pointer.
*
* NotifySLRULock is used as the control lock for the pg_notify SLRU buffers.
* In order to avoid deadlocks, whenever we need both locks, we always first
* get NotifyQueueLock and then NotifySLRULock.
* In order to avoid deadlocks, whenever we need multiple locks, we first get
* NotifyQueueTailLock, then NotifyQueueLock, and lastly NotifySLRULock.
*
* Each backend uses the backend[] array entry with index equal to its
* BackendId (which can range from 1 to MaxBackends). We rely on this to make
Expand Down Expand Up @@ -299,13 +302,10 @@ static SlruCtlData NotifyCtlData;
#define QUEUE_FULL_WARN_INTERVAL 5000 /* warn at most once every 5s */

/*
* slru.c currently assumes that all filenames are four characters of hex
* digits. That means that we can use segments 0000 through FFFF.
* Each segment contains SLRU_PAGES_PER_SEGMENT pages which gives us
* the pages from 0 to SLRU_PAGES_PER_SEGMENT * 0x10000 - 1.
*
* It's of course possible to enhance slru.c, but this gives us so much
* space already that it doesn't seem worth the trouble.
* Use segments 0000 through FFFF. Each contains SLRU_PAGES_PER_SEGMENT pages
* which gives us the pages from 0 to SLRU_PAGES_PER_SEGMENT * 0x10000 - 1.
* We could use as many segments as SlruScanDirectory() allows, but this gives
* us so much space already that it doesn't seem worth the trouble.
*
* The most data we can have in the queue at a time is QUEUE_MAX_PAGE/2
* pages, because more than that would confuse slru.c into thinking there
Expand Down Expand Up @@ -2177,6 +2177,10 @@ asyncQueueAdvanceTail(void)
int newtailpage;
int boundary;

/* Restrict task to one backend per cluster; see SimpleLruTruncate(). */
LWLockAcquire(NotifyQueueTailLock, LW_EXCLUSIVE);

/* Compute the new tail. */
LWLockAcquire(NotifyQueueLock, LW_EXCLUSIVE);
min = QUEUE_HEAD;
for (BackendId i = QUEUE_FIRST_LISTENER; i > 0; i = QUEUE_NEXT_LISTENER(i))
Expand All @@ -2185,7 +2189,6 @@ asyncQueueAdvanceTail(void)
min = QUEUE_POS_MIN(min, QUEUE_BACKEND_POS(i));
}
oldtailpage = QUEUE_POS_PAGE(QUEUE_TAIL);
QUEUE_TAIL = min;
LWLockRelease(NotifyQueueLock);

/*
Expand All @@ -2205,6 +2208,17 @@ asyncQueueAdvanceTail(void)
*/
SimpleLruTruncate(NotifyCtl, newtailpage);
}

/*
* Advertise the new tail. This changes asyncQueueIsFull()'s verdict for
* the segment immediately prior to the new tail, allowing fresh data into
* that segment.
*/
LWLockAcquire(NotifyQueueLock, LW_EXCLUSIVE);
QUEUE_TAIL = min;
LWLockRelease(NotifyQueueLock);

LWLockRelease(NotifyQueueTailLock);
}

/*
Expand Down
23 changes: 18 additions & 5 deletions src/backend/commands/vacuum.c
Original file line number Diff line number Diff line change
Expand Up @@ -949,11 +949,11 @@ vacuum_set_xid_limits(Relation rel,
/*
* We can always ignore processes running lazy vacuum. This is because we
* use these values only for deciding which tuples we must keep in the
* tables. Since lazy vacuum doesn't write its XID anywhere, it's safe to
* ignore it. In theory it could be problematic to ignore lazy vacuums in
* a full vacuum, but keep in mind that only one vacuum process can be
* working on a particular table at any time, and that each vacuum is
* always an independent transaction.
* tables. Since lazy vacuum doesn't write its XID anywhere (usually no
* XID assigned), it's safe to ignore it. In theory it could be
* problematic to ignore lazy vacuums in a full vacuum, but keep in mind
* that only one vacuum process can be working on a particular table at
* any time, and that each vacuum is always an independent transaction.
*/
*oldestXmin = GetOldestNonRemovableTransactionId(rel);

Expand Down Expand Up @@ -1361,6 +1361,14 @@ vac_update_datfrozenxid(void)
bool bogus = false;
bool dirty = false;

/*
* Restrict this task to one backend per database. This avoids race
* conditions that would move datfrozenxid or datminmxid backward. It
* avoids calling vac_truncate_clog() with a datfrozenxid preceding a
* datfrozenxid passed to an earlier vac_truncate_clog() call.
*/
LockDatabaseFrozenIds(ExclusiveLock);

/*
* Initialize the "min" calculation with
* GetOldestNonRemovableTransactionId(), which is a reasonable
Expand Down Expand Up @@ -1551,6 +1559,9 @@ vac_truncate_clog(TransactionId frozenXID,
bool bogus = false;
bool frozenAlreadyWrapped = false;

/* Restrict task to one backend per cluster; see SimpleLruTruncate(). */
LWLockAcquire(WrapLimitsVacuumLock, LW_EXCLUSIVE);

/* init oldest datoids to sync with my frozenXID/minMulti values */
oldestxid_datoid = MyDatabaseId;
minmulti_datoid = MyDatabaseId;
Expand Down Expand Up @@ -1660,6 +1671,8 @@ vac_truncate_clog(TransactionId frozenXID,
*/
SetTransactionIdLimit(frozenXID, oldestxid_datoid);
SetMultiXactIdLimit(minMulti, minmulti_datoid, false);

LWLockRelease(WrapLimitsVacuumLock);
}


Expand Down
2 changes: 1 addition & 1 deletion src/backend/storage/buffer/bufmgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -3578,7 +3578,7 @@ IncrBufferRefCount(Buffer buffer)
* This is essentially the same as MarkBufferDirty, except:
*
* 1. The caller does not write WAL; so if checksums are enabled, we may need
* to write an XLOG_FPI WAL record to protect against torn pages.
* to write an XLOG_FPI_FOR_HINT WAL record to protect against torn pages.
* 2. The caller might have only share-lock instead of exclusive-lock on the
* buffer's content lock.
* 3. This function does not guarantee that the buffer is always marked dirty
Expand Down
20 changes: 20 additions & 0 deletions src/backend/storage/lmgr/lmgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,21 @@ UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
LockRelease(&tag, lockmode, false);
}

/*
* LockDatabaseFrozenIds
*
* This allows one backend per database to execute vac_update_datfrozenxid().
*/
void
LockDatabaseFrozenIds(LOCKMODE lockmode)
{
LOCKTAG tag;

SET_LOCKTAG_DATABASE_FROZEN_IDS(tag, MyDatabaseId);

(void) LockAcquire(&tag, lockmode, false, false);
}

/*
* LockPage
*
Expand Down Expand Up @@ -1098,6 +1113,11 @@ DescribeLockTag(StringInfo buf, const LOCKTAG *tag)
tag->locktag_field2,
tag->locktag_field1);
break;
case LOCKTAG_DATABASE_FROZEN_IDS:
appendStringInfo(buf,
_("pg_database.datfrozenxid of database %u"),
tag->locktag_field1);
break;
case LOCKTAG_PAGE:
appendStringInfo(buf,
_("page %u of relation %u of database %u"),
Expand Down
3 changes: 3 additions & 0 deletions src/backend/storage/lmgr/lwlocknames.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,6 @@ MultiXactTruncationLock 41
OldSnapshotTimeMapLock 42
LogicalRepWorkerLock 43
XactTruncationLock 44
# 45 was XactTruncationLock until removal of BackendRandomLock
WrapLimitsVacuumLock 46
NotifyQueueTailLock 47
24 changes: 0 additions & 24 deletions src/backend/utils/adt/float.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,18 +271,6 @@ float4in(PG_FUNCTION_ARGS)
errmsg("invalid input syntax for type %s: \"%s\"",
"real", orig_num)));
}
#ifdef HAVE_BUGGY_SOLARIS_STRTOD
else
{
/*
* Many versions of Solaris have a bug wherein strtod sets endptr to
* point one byte beyond the end of the string when given "inf" or
* "infinity".
*/
if (endptr != num && endptr[-1] == '\0')
endptr--;
}
#endif /* HAVE_BUGGY_SOLARIS_STRTOD */

/* skip trailing whitespace */
while (*endptr != '\0' && isspace((unsigned char) *endptr))
Expand Down Expand Up @@ -499,18 +487,6 @@ float8in_internal_opt_error(char *num, char **endptr_p,
type_name, orig_string))),
have_error);
}
#ifdef HAVE_BUGGY_SOLARIS_STRTOD
else
{
/*
* Many versions of Solaris have a bug wherein strtod sets endptr to
* point one byte beyond the end of the string when given "inf" or
* "infinity".
*/
if (endptr != num && endptr[-1] == '\0')
endptr--;
}
#endif /* HAVE_BUGGY_SOLARIS_STRTOD */

/* skip trailing whitespace */
while (*endptr != '\0' && isspace((unsigned char) *endptr))
Expand Down
12 changes: 12 additions & 0 deletions src/backend/utils/adt/lockfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
const char *const LockTagTypeNames[] = {
"relation",
"extend",
"frozenid",
"page",
"tuple",
"transactionid",
Expand Down Expand Up @@ -254,6 +255,17 @@ pg_lock_status(PG_FUNCTION_ARGS)
nulls[8] = true;
nulls[9] = true;
break;
case LOCKTAG_DATABASE_FROZEN_IDS:
values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
nulls[2] = true;
nulls[3] = true;
nulls[4] = true;
nulls[5] = true;
nulls[6] = true;
nulls[7] = true;
nulls[8] = true;
nulls[9] = true;
break;
case LOCKTAG_PAGE:
values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
Expand Down
Loading