mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			143 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			143 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*-------------------------------------------------------------------------
 | 
						|
 *
 | 
						|
 * 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);
 | 
						|
}
 |