combocid.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 283 行

C
283
字号
/*------------------------------------------------------------------------- * * combocid.c *	  Combo command ID support routines * * Before version 8.3, HeapTupleHeaderData had separate fields for cmin * and cmax.  To reduce the header size, cmin and cmax are now overlayed * in the same field in the header.  That usually works because you rarely * insert and delete a tuple in the same transaction, and we don't need * either field to remain valid after the originating transaction exits. * To make it work when the inserting transaction does delete the tuple, * we create a "combo" command ID and store that in the tuple header * instead of cmin and cmax. The combo command ID can be mapped to the * real cmin and cmax using a backend-private array, which is managed by * this module. * * To allow reusing existing combo cids, we also keep a hash table that * maps cmin,cmax pairs to combo cids.	This keeps the data structure size * reasonable in most cases, since the number of unique pairs used by any * one transaction is likely to be small. * * With a 32-bit combo command id we can represent 2^32 distinct cmin,cmax * combinations. In the most perverse case where each command deletes a tuple * generated by every previous command, the number of combo command ids * required for N commands is N*(N+1)/2.  That means that in the worst case, * that's enough for 92682 commands.  In practice, you'll run out of memory * and/or disk space way before you reach that limit. * * The array and hash table are kept in TopTransactionContext, and are * destroyed at the end of each transaction. * * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/utils/time/combocid.c,v 1.4.2.1 2008/09/01 18:53:03 heikki Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/htup.h"#include "access/xact.h"#include "utils/combocid.h"#include "utils/hsearch.h"#include "utils/memutils.h"/* Hash table to lookup combo cids by cmin and cmax */static HTAB *comboHash = NULL;/* Key and entry structures for the hash table */typedef struct{	CommandId	cmin;	CommandId	cmax;} ComboCidKeyData;typedef ComboCidKeyData *ComboCidKey;typedef struct{	ComboCidKeyData key;	CommandId	combocid;} ComboCidEntryData;typedef ComboCidEntryData *ComboCidEntry;/* Initial size of the hash table */#define CCID_HASH_SIZE			100/* * An array of cmin,cmax pairs, indexed by combo command id. * To convert a combo cid to cmin and cmax, you do a simple array lookup. */static ComboCidKey comboCids = NULL;static int	usedComboCids = 0;	/* number of elements in comboCids */static int	sizeComboCids = 0;	/* allocated size of array *//* Initial size of the array */#define CCID_ARRAY_SIZE			100/* prototypes for internal functions */static CommandId GetComboCommandId(CommandId cmin, CommandId cmax);static CommandId GetRealCmin(CommandId combocid);static CommandId GetRealCmax(CommandId combocid);/**** External API ****//* * GetCmin and GetCmax assert that they are only called in situations where * they make sense, that is, can deliver a useful answer.  If you have * reason to examine a tuple's t_cid field from a transaction other than * the originating one, use HeapTupleHeaderGetRawCommandId() directly. */CommandIdHeapTupleHeaderGetCmin(HeapTupleHeader tup){	CommandId	cid = HeapTupleHeaderGetRawCommandId(tup);	Assert(!(tup->t_infomask & HEAP_MOVED));	Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tup)));	if (tup->t_infomask & HEAP_COMBOCID)		return GetRealCmin(cid);	else		return cid;}CommandIdHeapTupleHeaderGetCmax(HeapTupleHeader tup){	CommandId	cid = HeapTupleHeaderGetRawCommandId(tup);	/* We do not store cmax when locking a tuple */	Assert(!(tup->t_infomask & (HEAP_MOVED | HEAP_IS_LOCKED)));	Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tup)));	if (tup->t_infomask & HEAP_COMBOCID)		return GetRealCmax(cid);	else		return cid;}/* * Given a tuple we are about to delete, determine the correct value to store * into its t_cid field. * * If we don't need a combo CID, *cmax is unchanged and *iscombo is set to * FALSE.  If we do need one, *cmax is replaced by a combo CID and *iscombo * is set to TRUE. * * The reason this is separate from the actual HeapTupleHeaderSetCmax() * operation is that this could fail due to out-of-memory conditions.  Hence * we need to do this before entering the critical section that actually * changes the tuple in shared buffers. */voidHeapTupleHeaderAdjustCmax(HeapTupleHeader tup,						  CommandId *cmax,						  bool *iscombo){	/*	 * If we're marking a tuple deleted that was inserted by (any	 * subtransaction of) our transaction, we need to use a combo command id.	 * Test for HEAP_XMIN_COMMITTED first, because it's cheaper than a	 * TransactionIdIsCurrentTransactionId call.	 */	if (!(tup->t_infomask & HEAP_XMIN_COMMITTED) &&		TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tup)))	{		CommandId	cmin = HeapTupleHeaderGetCmin(tup);		*cmax = GetComboCommandId(cmin, *cmax);		*iscombo = true;	}	else	{		*iscombo = false;	}}/* * Combo command ids are only interesting to the inserting and deleting * transaction, so we can forget about them at the end of transaction. */voidAtEOXact_ComboCid(void){	/*	 * Don't bother to pfree. These are allocated in TopTransactionContext, so	 * they're going to go away at the end of transaction anyway.	 */	comboHash = NULL;	comboCids = NULL;	usedComboCids = 0;	sizeComboCids = 0;}/**** Internal routines ****//* * Get a combo command id that maps to cmin and cmax. * * We try to reuse old combo command ids when possible. */static CommandIdGetComboCommandId(CommandId cmin, CommandId cmax){	CommandId	combocid;	ComboCidKeyData key;	ComboCidEntry entry;	bool		found;	/*	 * Create the hash table and array the first time we need to use combo	 * cids in the transaction.	 */	if (comboHash == NULL)	{		HASHCTL		hash_ctl;		memset(&hash_ctl, 0, sizeof(hash_ctl));		hash_ctl.keysize = sizeof(ComboCidKeyData);		hash_ctl.entrysize = sizeof(ComboCidEntryData);		hash_ctl.hash = tag_hash;		hash_ctl.hcxt = TopTransactionContext;		comboHash = hash_create("Combo CIDs",								CCID_HASH_SIZE,								&hash_ctl,								HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);		comboCids = (ComboCidKeyData *)			MemoryContextAlloc(TopTransactionContext,							   sizeof(ComboCidKeyData) * CCID_ARRAY_SIZE);		sizeComboCids = CCID_ARRAY_SIZE;		usedComboCids = 0;	}	/* Lookup or create a hash entry with the desired cmin/cmax */	/* We assume there is no struct padding in ComboCidKeyData! */	key.cmin = cmin;	key.cmax = cmax;	entry = (ComboCidEntry) hash_search(comboHash,										(void *) &key,										HASH_ENTER,										&found);	if (found)	{		/* Reuse an existing combo cid */		return entry->combocid;	}	/*	 * We have to create a new combo cid. Check that there's room for it in	 * the array, and grow it if there isn't.	 */	if (usedComboCids >= sizeComboCids)	{		/* We need to grow the array */		int			newsize = sizeComboCids * 2;		comboCids = (ComboCidKeyData *)			repalloc(comboCids, sizeof(ComboCidKeyData) * newsize);		sizeComboCids = newsize;	}	combocid = usedComboCids;	comboCids[combocid].cmin = cmin;	comboCids[combocid].cmax = cmax;	usedComboCids++;	entry->combocid = combocid;	return combocid;}static CommandIdGetRealCmin(CommandId combocid){	Assert(combocid < usedComboCids);	return comboCids[combocid].cmin;}static CommandIdGetRealCmax(CommandId combocid){	Assert(combocid < usedComboCids);	return comboCids[combocid].cmax;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?