1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-27 12:41:57 +03:00

Remove the "snapshot too old" feature.

Remove the old_snapshot_threshold setting and mechanism for producing
the error "snapshot too old", originally added by commit 848ef42b.
Unfortunately it had a number of known problems in terms of correctness
and performance, mostly reported by Andres in the course of his work on
snapshot scalability.  We agreed to remove it, after a long period
without an active plan to fix it.

This is certainly a desirable feature, and someone might propose a new
or improved implementation in the future.

Reported-by: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/CACG%3DezYV%2BEvO135fLRdVn-ZusfVsTY6cH1OZqWtezuEYH6ciQA%40mail.gmail.com
Discussion: https://postgr.es/m/20200401064008.qob7bfnnbu4w5cw4%40alap3.anarazel.de
Discussion: https://postgr.es/m/CA%2BTgmoY%3Daqf0zjTD%2B3dUWYkgMiNDegDLFjo%2B6ze%3DWtpik%2B3XqA%40mail.gmail.com
This commit is contained in:
Thomas Munro
2023-09-05 18:26:12 +12:00
parent aa0d350456
commit f691f5b80a
50 changed files with 21 additions and 1425 deletions

View File

@ -29,7 +29,6 @@ SUBDIRS = \
lo \
ltree \
oid2name \
old_snapshot \
pageinspect \
passwordcheck \
pg_buffercache \

View File

@ -132,7 +132,6 @@ blgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
LockBuffer(buffer, BUFFER_LOCK_SHARE);
page = BufferGetPage(buffer);
TestForOldSnapshot(scan->xs_snapshot, scan->indexRelation, page);
if (!PageIsNew(page) && !BloomPageIsDeleted(page))
{

View File

@ -37,7 +37,6 @@ subdir('lo')
subdir('ltree')
subdir('ltree_plpython')
subdir('oid2name')
subdir('old_snapshot')
subdir('pageinspect')
subdir('passwordcheck')
subdir('pg_buffercache')

View File

@ -1,21 +0,0 @@
# contrib/old_snapshot/Makefile
MODULE_big = old_snapshot
OBJS = \
$(WIN32RES) \
time_mapping.o
EXTENSION = old_snapshot
DATA = old_snapshot--1.0.sql
PGFILEDESC = "old_snapshot - utilities in support of old_snapshot_threshold"
ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
else
subdir = contrib/old_snapshot
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif

View File

@ -1,23 +0,0 @@
# Copyright (c) 2022-2023, PostgreSQL Global Development Group
old_snapshot_sources = files(
'time_mapping.c',
)
if host_system == 'windows'
old_snapshot_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
'--NAME', 'old_snapshot',
'--FILEDESC', 'old_snapshot - utilities in support of old_snapshot_threshold',])
endif
old_snapshot = shared_module('old_snapshot',
old_snapshot_sources,
kwargs: contrib_mod_args,
)
contrib_targets += old_snapshot
install_data(
'old_snapshot.control',
'old_snapshot--1.0.sql',
kwargs: contrib_data_args,
)

View File

@ -1,14 +0,0 @@
/* contrib/old_snapshot/old_snapshot--1.0.sql */
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION old_snapshot" to load this file. \quit
-- Show visibility map and page-level visibility information for each block.
CREATE FUNCTION pg_old_snapshot_time_mapping(array_offset OUT int4,
end_timestamp OUT timestamptz,
newest_xmin OUT xid)
RETURNS SETOF record
AS 'MODULE_PATHNAME', 'pg_old_snapshot_time_mapping'
LANGUAGE C STRICT;
-- XXX. Do we want REVOKE commands here?

View File

@ -1,5 +0,0 @@
# old_snapshot extension
comment = 'utilities in support of old_snapshot_threshold'
default_version = '1.0'
module_pathname = '$libdir/old_snapshot'
relocatable = true

View File

@ -1,142 +0,0 @@
/*-------------------------------------------------------------------------
*
* time_mapping.c
* time to XID mapping information
*
* Copyright (c) 2020-2023, PostgreSQL Global Development Group
*
* contrib/old_snapshot/time_mapping.c
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "funcapi.h"
#include "storage/lwlock.h"
#include "utils/old_snapshot.h"
#include "utils/snapmgr.h"
#include "utils/timestamp.h"
/*
* Backend-private copy of the information from oldSnapshotControl which relates
* to the time to XID mapping, plus an index so that we can iterate.
*
* Note that the length of the xid_by_minute array is given by
* OLD_SNAPSHOT_TIME_MAP_ENTRIES (which is not a compile-time constant).
*/
typedef struct
{
int current_index;
int head_offset;
TimestampTz head_timestamp;
int count_used;
TransactionId xid_by_minute[FLEXIBLE_ARRAY_MEMBER];
} OldSnapshotTimeMapping;
#define NUM_TIME_MAPPING_COLUMNS 3
PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(pg_old_snapshot_time_mapping);
static OldSnapshotTimeMapping *GetOldSnapshotTimeMapping(void);
static HeapTuple MakeOldSnapshotTimeMappingTuple(TupleDesc tupdesc,
OldSnapshotTimeMapping *mapping);
/*
* SQL-callable set-returning function.
*/
Datum
pg_old_snapshot_time_mapping(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
OldSnapshotTimeMapping *mapping;
if (SRF_IS_FIRSTCALL())
{
MemoryContext oldcontext;
TupleDesc tupdesc;
funcctx = SRF_FIRSTCALL_INIT();
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
mapping = GetOldSnapshotTimeMapping();
funcctx->user_fctx = mapping;
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
funcctx->tuple_desc = tupdesc;
MemoryContextSwitchTo(oldcontext);
}
funcctx = SRF_PERCALL_SETUP();
mapping = (OldSnapshotTimeMapping *) funcctx->user_fctx;
while (mapping->current_index < mapping->count_used)
{
HeapTuple tuple;
tuple = MakeOldSnapshotTimeMappingTuple(funcctx->tuple_desc, mapping);
++mapping->current_index;
SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
}
SRF_RETURN_DONE(funcctx);
}
/*
* Get the old snapshot time mapping data from shared memory.
*/
static OldSnapshotTimeMapping *
GetOldSnapshotTimeMapping(void)
{
OldSnapshotTimeMapping *mapping;
mapping = palloc(offsetof(OldSnapshotTimeMapping, xid_by_minute)
+ sizeof(TransactionId) * OLD_SNAPSHOT_TIME_MAP_ENTRIES);
mapping->current_index = 0;
LWLockAcquire(OldSnapshotTimeMapLock, LW_SHARED);
mapping->head_offset = oldSnapshotControl->head_offset;
mapping->head_timestamp = oldSnapshotControl->head_timestamp;
mapping->count_used = oldSnapshotControl->count_used;
for (int i = 0; i < OLD_SNAPSHOT_TIME_MAP_ENTRIES; ++i)
mapping->xid_by_minute[i] = oldSnapshotControl->xid_by_minute[i];
LWLockRelease(OldSnapshotTimeMapLock);
return mapping;
}
/*
* Convert one entry from the old snapshot time mapping to a HeapTuple.
*/
static HeapTuple
MakeOldSnapshotTimeMappingTuple(TupleDesc tupdesc, OldSnapshotTimeMapping *mapping)
{
Datum values[NUM_TIME_MAPPING_COLUMNS];
bool nulls[NUM_TIME_MAPPING_COLUMNS];
int array_position;
TimestampTz timestamp;
/*
* Figure out the array position corresponding to the current index.
*
* Index 0 means the oldest entry in the mapping, which is stored at
* mapping->head_offset. Index 1 means the next-oldest entry, which is a
* the following index, and so on. We wrap around when we reach the end of
* the array.
*/
array_position = (mapping->head_offset + mapping->current_index)
% OLD_SNAPSHOT_TIME_MAP_ENTRIES;
/*
* No explicit timestamp is stored for any entry other than the oldest
* one, but each entry corresponds to 1-minute period, so we can just add.
*/
timestamp = TimestampTzPlusMilliseconds(mapping->head_timestamp,
mapping->current_index * 60000);
/* Initialize nulls and values arrays. */
memset(nulls, 0, sizeof(nulls));
values[0] = Int32GetDatum(array_position);
values[1] = TimestampTzGetDatum(timestamp);
values[2] = TransactionIdGetDatum(mapping->xid_by_minute[array_position]);
return heap_form_tuple(tupdesc, values, nulls);
}