概述
PostgreSQL12对比PostgreSQL11,无论在功能上和代码上都有很大的变化,下面分析一下TupleTableSlot这个数据结构在两个版本的不同
首先看看数据结构
PostgreSQL11.5
typedef struct TupleTableSlot
{
NodeTag type;
bool tts_isempty; /* true = slot is empty */
bool tts_shouldFree; /* should pfree tts_tuple? */
bool tts_shouldFreeMin; /* should pfree tts_mintuple? */
#define FIELDNO_TUPLETABLESLOT_SLOW 4
bool tts_slow; /* saved state for slot_deform_tuple */
#define FIELDNO_TUPLETABLESLOT_TUPLE 5
HeapTuple tts_tuple; /* physical tuple, or NULL if virtual */
#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 6
TupleDesc tts_tupleDescriptor; /* slot's tuple descriptor */
MemoryContext tts_mcxt; /* slot itself is in this context */
Buffer tts_buffer; /* tuple's buffer, or InvalidBuffer */
#define FIELDNO_TUPLETABLESLOT_NVALID 9
int tts_nvalid; /* # of valid values in tts_values */
#define FIELDNO_TUPLETABLESLOT_VALUES 10
Datum *tts_values; /* current per-attribute values */
#define FIELDNO_TUPLETABLESLOT_ISNULL 11
bool *tts_isnull; /* current per-attribute isnull flags */
MinimalTuple tts_mintuple; /* minimal tuple, or NULL if none */
HeapTupleData tts_minhdr; /* workspace for minimal-tuple-only case */
#define FIELDNO_TUPLETABLESLOT_OFF 14
uint32 tts_off; /* saved state for slot_deform_tuple */
bool tts_fixedTupleDescriptor; /* descriptor can't be changed */
} TupleTableSlot;
PostgreSQL12.1
typedef struct TupleTableSlot
{
NodeTag type;
#define FIELDNO_TUPLETABLESLOT_FLAGS 1
uint16 tts_flags; /* Boolean states */
#define FIELDNO_TUPLETABLESLOT_NVALID 2
AttrNumber tts_nvalid; /* # of valid values in tts_values */
const TupleTableSlotOps *const tts_ops; /* implementation of slot */
#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 4
TupleDesc tts_tupleDescriptor; /* slot's tuple descriptor */
#define FIELDNO_TUPLETABLESLOT_VALUES 5
Datum *tts_values; /* current per-attribute values */
#define FIELDNO_TUPLETABLESLOT_ISNULL 6
bool *tts_isnull; /* current per-attribute isnull flags */
MemoryContext tts_mcxt; /* slot itself is in this context */
ItemPointerData tts_tid; /* stored tuple's tid */
Oid tts_tableOid; /* table oid of tuple */
} TupleTableSlot;
两个版本的TupleTableSlot数据结构差别较大,先是解释一下TupleTableSlot的作用。
HeapTuple有四种类型(物理/内存/精简/虚拟),TupleTableSlot是用来管理HeapTuple的一个数据结构,对上述四种类型的HeapTuple提供了统一的对外表示。
在11.5版本里,TupleTableSlot使用较多的成员变量来标识tuple的不同状态,例如tts_isempty,tts_shouldFree等,在12.1里,使用tts_flags来标识个各种状态并使用逻辑位与的方法来获取状态。
#define TTS_FLAG_EMPTY (1 << 1)
#define TTS_EMPTY(slot) (((slot)->tts_flags & TTS_FLAG_EMPTY) != 0)
/* should pfree tuple "owned" by the slot? */
#define TTS_FLAG_SHOULDFREE (1 << 2)
#define TTS_SHOULDFREE(slot) (((slot)->tts_flags & TTS_FLAG_SHOULDFREE) != 0)
/* saved state for slot_deform_heap_tuple */
#define TTS_FLAG_SLOW (1 << 3)
#define TTS_SLOW(slot) (((slot)->tts_flags & TTS_FLAG_SLOW) != 0)
/* fixed tuple descriptor */
#define TTS_FLAG_FIXED (1 << 4)
#define TTS_FIXED(slot) (((slot)->tts_flags & TTS_FLAG_FIXED) != 0)
在11.5版本里,对TupleTableSlot是直接编写函数对TupleTableSlot进行操作,但在12.1里,使用成员变量TupleTableSlotOps来提供TupleTableSlot的操作函数。这有点类似面向对象的设计,同时能把数据与操作方法有效隔离。
TupleTableSlotOps数据结构
/* routines for a TupleTableSlot implementation */
struct TupleTableSlotOps
{
/* Minimum size of the slot */
size_t base_slot_size;
/* Initialization. */
void (*init)(TupleTableSlot *slot);
/* Destruction. */
void (*release)(TupleTableSlot *slot);
/*
* Clear the contents of the slot. Only the contents are expected to be
* cleared and not the tuple descriptor. Typically an implementation of
* this callback should free the memory allocated for the tuple contained
* in the slot.
*/
void (*clear)(TupleTableSlot *slot);
/*
* Fill up first natts entries of tts_values and tts_isnull arrays with
* values from the tuple contained in the slot. The function may be called
* with natts more than the number of attributes available in the tuple,
* in which case it should set tts_nvalid to the number of returned
* columns.
*/
void (*getsomeattrs)(TupleTableSlot *slot, int natts);
/*
* Returns value of the given system attribute as a datum and sets isnull
* to false, if it's not NULL. Throws an error if the slot type does not
* support system attributes.
*/
Datum (*getsysattr)(TupleTableSlot *slot, int attnum, bool *isnull);
/*
* Make the contents of the slot solely depend on the slot, and not on
* underlying resources (like another memory context, buffers, etc).
*/
void (*materialize)(TupleTableSlot *slot);
/*
* Copy the contents of the source slot into the destination slot's own
* context. Invoked using callback of the destination slot.
*/
void (*copyslot) (TupleTableSlot *dstslot, TupleTableSlot *srcslot);
/*
* Return a heap tuple "owned" by the slot. It is slot's responsibility to
* free the memory consumed by the heap tuple. If the slot can not "own" a
* heap tuple, it should not implement this callback and should set it as
* NULL.
*/
HeapTuple (*get_heap_tuple)(TupleTableSlot *slot);
/*
* Return a minimal tuple "owned" by the slot. It is slot's responsibility
* to free the memory consumed by the minimal tuple. If the slot can not
* "own" a minimal tuple, it should not implement this callback and should
* set it as NULL.
*/
MinimalTuple (*get_minimal_tuple)(TupleTableSlot *slot);
/*
* Return a copy of heap tuple representing the contents of the slot. The
* copy needs to be palloc'd in the current memory context. The slot
* itself is expected to remain unaffected. It is *not* expected to have
* meaningful "system columns" in the copy. The copy is not be "owned" by
* the slot i.e. the caller has to take responsibilty to free memory
* consumed by the slot.
*/
HeapTuple (*copy_heap_tuple)(TupleTableSlot *slot);
/*
* Return a copy of minimal tuple representing the contents of the slot. The
* copy needs to be palloc'd in the current memory context. The slot
* itself is expected to remain unaffected. It is *not* expected to have
* meaningful "system columns" in the copy. The copy is not be "owned" by
* the slot i.e. the caller has to take responsibilty to free memory
* consumed by the slot.
*/
MinimalTuple (*copy_minimal_tuple)(TupleTableSlot *slot);
};
可以看到,TupleTableSlotOps是一系列对TupleTableSlot操作函数的函数指针,据说PostgreSQL13支持可插拔式的存储引擎,这有可能是为这一特性做的重构。
两个版本对TupleTableSlot的操作例子
PostgreSQL11.5 ExecMaterializeSlot函数
HeapTuple
ExecMaterializeSlot(TupleTableSlot *slot)
{
MemoryContext oldContext;
/*
* sanity checks
*/
Assert(slot != NULL);
Assert(!slot->tts_isempty);
/*
* If we have a regular physical tuple, and it's locally palloc'd, we have
* nothing to do.
*/
if (slot->tts_tuple && slot->tts_shouldFree)
return slot->tts_tuple;
/*
* Otherwise, copy or build a physical tuple, and store it into the slot.
*
* We may be called in a context that is shorter-lived than the tuple
* slot, but we have to ensure that the materialized tuple will survive
* anyway.
*/
oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
slot->tts_tuple = ExecCopySlotTuple(slot);
slot->tts_shouldFree = true;
MemoryContextSwitchTo(oldContext);
/*
* Drop the pin on the referenced buffer, if there is one.
*/
if (BufferIsValid(slot->tts_buffer))
ReleaseBuffer(slot->tts_buffer);
slot->tts_buffer = InvalidBuffer;
/*
* Mark extracted state invalid. This is important because the slot is
* not supposed to depend any more on the previous external data; we
* mustn't leave any dangling pass-by-reference datums in tts_values.
* However, we have not actually invalidated any such datums, if there
* happen to be any previously fetched from the slot. (Note in particular
* that we have not pfree'd tts_mintuple, if there is one.)
*/
slot->tts_nvalid = 0;
/*
* On the same principle of not depending on previous remote storage,
* forget the mintuple if it's not local storage. (If it is local
* storage, we must not pfree it now, since callers might have already
* fetched datum pointers referencing it.)
*/
if (!slot->tts_shouldFreeMin)
slot->tts_mintuple = NULL;
return slot->tts_tuple;
}
PostgreSQL12.1 ExecMaterializeSlot函数
static inline void
ExecMaterializeSlot(TupleTableSlot *slot)
{
slot->tts_ops->materialize(slot);
}
可以看到在12.1里对TupleTableSlot的操作代码非常简洁,所有的逻辑都由TupleTableSlot->tts_ops->materialize指针指向的函数来处理。
最后
以上就是傻傻泥猴桃为你收集整理的源码分析-TupleTableSlot的全部内容,希望文章能够帮你解决源码分析-TupleTableSlot所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复