mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Move TupleTableSlots boolean member into one flag variable.
There's several reasons for this change: 1) It reduces the total size of TupleTableSlot / reduces alignment padding, making the commonly accessed members fit into a single cacheline (but we currently do not force proper alignment, so that's not yet guaranteed to be helpful) 2) Combining the booleans into a flag allows to combine read/writes from memory. 3) With the upcoming slot abstraction changes, it allows to have core and extended flags, in a memory efficient way. Author: Ashutosh Bapat and Andres Freund Discussion: https://postgr.es/m/20180220224318.gw4oe5jadhpmcdnm@alap3.anarazel.de
This commit is contained in:
		@@ -1391,7 +1391,7 @@ slot_deform_tuple(TupleTableSlot *slot, int natts)
 | 
			
		||||
	{
 | 
			
		||||
		/* Restore state from previous execution */
 | 
			
		||||
		off = slot->tts_off;
 | 
			
		||||
		slow = slot->tts_slow;
 | 
			
		||||
		slow = TTS_SLOW(slot);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tp = (char *) tup + tup->t_hoff;
 | 
			
		||||
@@ -1452,7 +1452,10 @@ slot_deform_tuple(TupleTableSlot *slot, int natts)
 | 
			
		||||
	 */
 | 
			
		||||
	slot->tts_nvalid = attnum;
 | 
			
		||||
	slot->tts_off = off;
 | 
			
		||||
	slot->tts_slow = slow;
 | 
			
		||||
	if (slow)
 | 
			
		||||
		slot->tts_flags |= TTS_FLAG_SLOW;
 | 
			
		||||
	else
 | 
			
		||||
		slot->tts_flags &= ~TTS_FLAG_SLOW;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
@@ -101,11 +101,10 @@ MakeTupleTableSlot(TupleDesc tupleDesc)
 | 
			
		||||
 | 
			
		||||
	slot = palloc0(sz);
 | 
			
		||||
	slot->type = T_TupleTableSlot;
 | 
			
		||||
	slot->tts_isempty = true;
 | 
			
		||||
	slot->tts_shouldFree = false;
 | 
			
		||||
	slot->tts_shouldFreeMin = false;
 | 
			
		||||
	slot->tts_flags |= TTS_FLAG_EMPTY;
 | 
			
		||||
	if (tupleDesc != NULL)
 | 
			
		||||
		slot->tts_flags |= TTS_FLAG_FIXED;
 | 
			
		||||
	slot->tts_tuple = NULL;
 | 
			
		||||
	slot->tts_fixedTupleDescriptor = tupleDesc != NULL;
 | 
			
		||||
	slot->tts_tupleDescriptor = tupleDesc;
 | 
			
		||||
	slot->tts_mcxt = CurrentMemoryContext;
 | 
			
		||||
	slot->tts_buffer = InvalidBuffer;
 | 
			
		||||
@@ -176,7 +175,7 @@ ExecResetTupleTable(List *tupleTable,	/* tuple table */
 | 
			
		||||
		/* If shouldFree, release memory occupied by the slot itself */
 | 
			
		||||
		if (shouldFree)
 | 
			
		||||
		{
 | 
			
		||||
			if (!slot->tts_fixedTupleDescriptor)
 | 
			
		||||
			if (!TTS_FIXED(slot))
 | 
			
		||||
			{
 | 
			
		||||
				if (slot->tts_values)
 | 
			
		||||
					pfree(slot->tts_values);
 | 
			
		||||
@@ -224,7 +223,7 @@ ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
 | 
			
		||||
	ExecClearTuple(slot);
 | 
			
		||||
	if (slot->tts_tupleDescriptor)
 | 
			
		||||
		ReleaseTupleDesc(slot->tts_tupleDescriptor);
 | 
			
		||||
	if (!slot->tts_fixedTupleDescriptor)
 | 
			
		||||
	if (!TTS_FIXED(slot))
 | 
			
		||||
	{
 | 
			
		||||
		if (slot->tts_values)
 | 
			
		||||
			pfree(slot->tts_values);
 | 
			
		||||
@@ -254,7 +253,7 @@ void
 | 
			
		||||
ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */
 | 
			
		||||
					  TupleDesc tupdesc)	/* new tuple descriptor */
 | 
			
		||||
{
 | 
			
		||||
	Assert(!slot->tts_fixedTupleDescriptor);
 | 
			
		||||
	Assert(!TTS_FIXED(slot));
 | 
			
		||||
 | 
			
		||||
	/* For safety, make sure slot is empty before changing it */
 | 
			
		||||
	ExecClearTuple(slot);
 | 
			
		||||
@@ -325,17 +324,23 @@ ExecStoreHeapTuple(HeapTuple tuple,
 | 
			
		||||
	/*
 | 
			
		||||
	 * Free any old physical tuple belonging to the slot.
 | 
			
		||||
	 */
 | 
			
		||||
	if (slot->tts_shouldFree)
 | 
			
		||||
	if (TTS_SHOULDFREE(slot))
 | 
			
		||||
	{
 | 
			
		||||
		heap_freetuple(slot->tts_tuple);
 | 
			
		||||
	if (slot->tts_shouldFreeMin)
 | 
			
		||||
		slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
 | 
			
		||||
	}
 | 
			
		||||
	if (TTS_SHOULDFREEMIN(slot))
 | 
			
		||||
	{
 | 
			
		||||
		heap_free_minimal_tuple(slot->tts_mintuple);
 | 
			
		||||
		slot->tts_flags &= ~TTS_FLAG_SHOULDFREEMIN;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Store the new tuple into the specified slot.
 | 
			
		||||
	 */
 | 
			
		||||
	slot->tts_isempty = false;
 | 
			
		||||
	slot->tts_shouldFree = shouldFree;
 | 
			
		||||
	slot->tts_shouldFreeMin = false;
 | 
			
		||||
	slot->tts_flags &= ~TTS_FLAG_EMPTY;
 | 
			
		||||
	if (shouldFree)
 | 
			
		||||
		slot->tts_flags |= TTS_FLAG_SHOULDFREE;
 | 
			
		||||
	slot->tts_tuple = tuple;
 | 
			
		||||
	slot->tts_mintuple = NULL;
 | 
			
		||||
 | 
			
		||||
@@ -382,17 +387,21 @@ ExecStoreBufferHeapTuple(HeapTuple tuple,
 | 
			
		||||
	/*
 | 
			
		||||
	 * Free any old physical tuple belonging to the slot.
 | 
			
		||||
	 */
 | 
			
		||||
	if (slot->tts_shouldFree)
 | 
			
		||||
	if (TTS_SHOULDFREE(slot))
 | 
			
		||||
	{
 | 
			
		||||
		heap_freetuple(slot->tts_tuple);
 | 
			
		||||
	if (slot->tts_shouldFreeMin)
 | 
			
		||||
		slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
 | 
			
		||||
	}
 | 
			
		||||
	if (TTS_SHOULDFREEMIN(slot))
 | 
			
		||||
	{
 | 
			
		||||
		heap_free_minimal_tuple(slot->tts_mintuple);
 | 
			
		||||
		slot->tts_flags &= ~TTS_FLAG_SHOULDFREEMIN;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Store the new tuple into the specified slot.
 | 
			
		||||
	 */
 | 
			
		||||
	slot->tts_isempty = false;
 | 
			
		||||
	slot->tts_shouldFree = false;
 | 
			
		||||
	slot->tts_shouldFreeMin = false;
 | 
			
		||||
	slot->tts_flags &= ~TTS_FLAG_EMPTY;
 | 
			
		||||
	slot->tts_tuple = tuple;
 | 
			
		||||
	slot->tts_mintuple = NULL;
 | 
			
		||||
 | 
			
		||||
@@ -442,10 +451,16 @@ ExecStoreMinimalTuple(MinimalTuple mtup,
 | 
			
		||||
	/*
 | 
			
		||||
	 * Free any old physical tuple belonging to the slot.
 | 
			
		||||
	 */
 | 
			
		||||
	if (slot->tts_shouldFree)
 | 
			
		||||
	if (TTS_SHOULDFREE(slot))
 | 
			
		||||
	{
 | 
			
		||||
		heap_freetuple(slot->tts_tuple);
 | 
			
		||||
	if (slot->tts_shouldFreeMin)
 | 
			
		||||
		slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
 | 
			
		||||
	}
 | 
			
		||||
	if (TTS_SHOULDFREEMIN(slot))
 | 
			
		||||
	{
 | 
			
		||||
		heap_free_minimal_tuple(slot->tts_mintuple);
 | 
			
		||||
		slot->tts_flags &= ~TTS_FLAG_SHOULDFREEMIN;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Drop the pin on the referenced buffer, if there is one.
 | 
			
		||||
@@ -458,9 +473,9 @@ ExecStoreMinimalTuple(MinimalTuple mtup,
 | 
			
		||||
	/*
 | 
			
		||||
	 * Store the new tuple into the specified slot.
 | 
			
		||||
	 */
 | 
			
		||||
	slot->tts_isempty = false;
 | 
			
		||||
	slot->tts_shouldFree = false;
 | 
			
		||||
	slot->tts_shouldFreeMin = shouldFree;
 | 
			
		||||
	slot->tts_flags &= ~TTS_FLAG_EMPTY;
 | 
			
		||||
	if (shouldFree)
 | 
			
		||||
		slot->tts_flags |= TTS_FLAG_SHOULDFREEMIN;
 | 
			
		||||
	slot->tts_tuple = &slot->tts_minhdr;
 | 
			
		||||
	slot->tts_mintuple = mtup;
 | 
			
		||||
 | 
			
		||||
@@ -493,15 +508,19 @@ ExecClearTuple(TupleTableSlot *slot)	/* slot in which to store tuple */
 | 
			
		||||
	/*
 | 
			
		||||
	 * Free the old physical tuple if necessary.
 | 
			
		||||
	 */
 | 
			
		||||
	if (slot->tts_shouldFree)
 | 
			
		||||
	if (TTS_SHOULDFREE(slot))
 | 
			
		||||
	{
 | 
			
		||||
		heap_freetuple(slot->tts_tuple);
 | 
			
		||||
	if (slot->tts_shouldFreeMin)
 | 
			
		||||
		slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
 | 
			
		||||
	}
 | 
			
		||||
	if (TTS_SHOULDFREEMIN(slot))
 | 
			
		||||
	{
 | 
			
		||||
		heap_free_minimal_tuple(slot->tts_mintuple);
 | 
			
		||||
		slot->tts_flags &= ~TTS_FLAG_SHOULDFREEMIN;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	slot->tts_tuple = NULL;
 | 
			
		||||
	slot->tts_mintuple = NULL;
 | 
			
		||||
	slot->tts_shouldFree = false;
 | 
			
		||||
	slot->tts_shouldFreeMin = false;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Drop the pin on the referenced buffer, if there is one.
 | 
			
		||||
@@ -514,7 +533,7 @@ ExecClearTuple(TupleTableSlot *slot)	/* slot in which to store tuple */
 | 
			
		||||
	/*
 | 
			
		||||
	 * Mark it empty.
 | 
			
		||||
	 */
 | 
			
		||||
	slot->tts_isempty = true;
 | 
			
		||||
	slot->tts_flags |= TTS_FLAG_EMPTY;
 | 
			
		||||
	slot->tts_nvalid = 0;
 | 
			
		||||
 | 
			
		||||
	return slot;
 | 
			
		||||
@@ -539,9 +558,9 @@ ExecStoreVirtualTuple(TupleTableSlot *slot)
 | 
			
		||||
	 */
 | 
			
		||||
	Assert(slot != NULL);
 | 
			
		||||
	Assert(slot->tts_tupleDescriptor != NULL);
 | 
			
		||||
	Assert(slot->tts_isempty);
 | 
			
		||||
	Assert(TTS_EMPTY(slot));
 | 
			
		||||
 | 
			
		||||
	slot->tts_isempty = false;
 | 
			
		||||
	slot->tts_flags &= ~TTS_FLAG_EMPTY;
 | 
			
		||||
	slot->tts_nvalid = slot->tts_tupleDescriptor->natts;
 | 
			
		||||
 | 
			
		||||
	return slot;
 | 
			
		||||
@@ -595,7 +614,7 @@ ExecCopySlotTuple(TupleTableSlot *slot)
 | 
			
		||||
	 * sanity checks
 | 
			
		||||
	 */
 | 
			
		||||
	Assert(slot != NULL);
 | 
			
		||||
	Assert(!slot->tts_isempty);
 | 
			
		||||
	Assert(!TTS_EMPTY(slot));
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If we have a physical tuple (either format) then just copy it.
 | 
			
		||||
@@ -627,7 +646,7 @@ ExecCopySlotMinimalTuple(TupleTableSlot *slot)
 | 
			
		||||
	 * sanity checks
 | 
			
		||||
	 */
 | 
			
		||||
	Assert(slot != NULL);
 | 
			
		||||
	Assert(!slot->tts_isempty);
 | 
			
		||||
	Assert(!TTS_EMPTY(slot));
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If we have a physical tuple then just copy it.  Prefer to copy
 | 
			
		||||
@@ -675,7 +694,7 @@ ExecFetchSlotTuple(TupleTableSlot *slot)
 | 
			
		||||
	 * sanity checks
 | 
			
		||||
	 */
 | 
			
		||||
	Assert(slot != NULL);
 | 
			
		||||
	Assert(!slot->tts_isempty);
 | 
			
		||||
	Assert(!TTS_EMPTY(slot));
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If we have a regular physical tuple then just return it.
 | 
			
		||||
@@ -724,7 +743,8 @@ ExecFetchSlotMinimalTuple(TupleTableSlot *slot)
 | 
			
		||||
	 * sanity checks
 | 
			
		||||
	 */
 | 
			
		||||
	Assert(slot != NULL);
 | 
			
		||||
	Assert(!slot->tts_isempty);
 | 
			
		||||
	Assert(!TTS_EMPTY(slot));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If we have a minimal physical tuple (local or not) then just return it.
 | 
			
		||||
@@ -741,7 +761,7 @@ ExecFetchSlotMinimalTuple(TupleTableSlot *slot)
 | 
			
		||||
	 */
 | 
			
		||||
	oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
 | 
			
		||||
	slot->tts_mintuple = ExecCopySlotMinimalTuple(slot);
 | 
			
		||||
	slot->tts_shouldFreeMin = true;
 | 
			
		||||
	slot->tts_flags |= TTS_FLAG_SHOULDFREEMIN;
 | 
			
		||||
	MemoryContextSwitchTo(oldContext);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
@@ -797,13 +817,13 @@ ExecMaterializeSlot(TupleTableSlot *slot)
 | 
			
		||||
	 * sanity checks
 | 
			
		||||
	 */
 | 
			
		||||
	Assert(slot != NULL);
 | 
			
		||||
	Assert(!slot->tts_isempty);
 | 
			
		||||
	Assert(!TTS_EMPTY(slot));
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * 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)
 | 
			
		||||
	if (slot->tts_tuple && TTS_SHOULDFREE(slot))
 | 
			
		||||
		return slot->tts_tuple;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
@@ -815,7 +835,7 @@ ExecMaterializeSlot(TupleTableSlot *slot)
 | 
			
		||||
	 */
 | 
			
		||||
	oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
 | 
			
		||||
	slot->tts_tuple = ExecCopySlotTuple(slot);
 | 
			
		||||
	slot->tts_shouldFree = true;
 | 
			
		||||
	slot->tts_flags |= TTS_FLAG_SHOULDFREE;
 | 
			
		||||
	MemoryContextSwitchTo(oldContext);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
@@ -842,7 +862,7 @@ ExecMaterializeSlot(TupleTableSlot *slot)
 | 
			
		||||
	 * storage, we must not pfree it now, since callers might have already
 | 
			
		||||
	 * fetched datum pointers referencing it.)
 | 
			
		||||
	 */
 | 
			
		||||
	if (!slot->tts_shouldFreeMin)
 | 
			
		||||
	if (!TTS_SHOULDFREEMIN(slot))
 | 
			
		||||
		slot->tts_mintuple = NULL;
 | 
			
		||||
 | 
			
		||||
	return slot->tts_tuple;
 | 
			
		||||
 
 | 
			
		||||
@@ -1080,7 +1080,7 @@ prepare_projection_slot(AggState *aggstate, TupleTableSlot *slot, int currentSet
 | 
			
		||||
 | 
			
		||||
		aggstate->grouped_cols = grouped_cols;
 | 
			
		||||
 | 
			
		||||
		if (slot->tts_isempty)
 | 
			
		||||
		if (TTS_EMPTY(slot))
 | 
			
		||||
		{
 | 
			
		||||
			/*
 | 
			
		||||
			 * Force all values to be NULL if working on an empty input tuple
 | 
			
		||||
 
 | 
			
		||||
@@ -699,7 +699,7 @@ ExecDelete(ModifyTableState *mtstate,
 | 
			
		||||
		 * RETURNING expressions might reference the tableoid column, so
 | 
			
		||||
		 * initialize t_tableOid before evaluating them.
 | 
			
		||||
		 */
 | 
			
		||||
		if (slot->tts_isempty)
 | 
			
		||||
		if (TTS_EMPTY(slot))
 | 
			
		||||
			ExecStoreAllNullTuple(slot);
 | 
			
		||||
		tuple = ExecMaterializeSlot(slot);
 | 
			
		||||
		tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,7 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc, int natts)
 | 
			
		||||
	LLVMValueRef v_tts_values;
 | 
			
		||||
	LLVMValueRef v_tts_nulls;
 | 
			
		||||
	LLVMValueRef v_slotoffp;
 | 
			
		||||
	LLVMValueRef v_slowp;
 | 
			
		||||
	LLVMValueRef v_flagsp;
 | 
			
		||||
	LLVMValueRef v_nvalidp;
 | 
			
		||||
	LLVMValueRef v_nvalid;
 | 
			
		||||
	LLVMValueRef v_maxatt;
 | 
			
		||||
@@ -168,7 +168,7 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc, int natts)
 | 
			
		||||
						  "tts_ISNULL");
 | 
			
		||||
 | 
			
		||||
	v_slotoffp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_OFF, "");
 | 
			
		||||
	v_slowp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_SLOW, "");
 | 
			
		||||
	v_flagsp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_FLAGS, "");
 | 
			
		||||
	v_nvalidp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_NVALID, "");
 | 
			
		||||
 | 
			
		||||
	v_tupleheaderp =
 | 
			
		||||
@@ -690,11 +690,14 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc, int natts)
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		LLVMValueRef v_off = LLVMBuildLoad(b, v_offp, "");
 | 
			
		||||
		LLVMValueRef v_flags;
 | 
			
		||||
 | 
			
		||||
		LLVMBuildStore(b, l_int16_const(natts), v_nvalidp);
 | 
			
		||||
		v_off = LLVMBuildTrunc(b, v_off, LLVMInt32Type(), "");
 | 
			
		||||
		LLVMBuildStore(b, v_off, v_slotoffp);
 | 
			
		||||
		LLVMBuildStore(b, l_int8_const(1), v_slowp);
 | 
			
		||||
		v_flags = LLVMBuildLoad(b, v_flagsp, "tts_flags");
 | 
			
		||||
		v_flags = LLVMBuildOr(b, v_flags, l_int16_const(TTS_FLAG_SLOW), "");
 | 
			
		||||
		LLVMBuildStore(b, v_flags, v_flagsp);
 | 
			
		||||
		LLVMBuildRetVoid(b);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -292,7 +292,7 @@ llvm_compile_expr(ExprState *state)
 | 
			
		||||
						if (!desc &&
 | 
			
		||||
							is &&
 | 
			
		||||
							is->ps_ResultTupleSlot &&
 | 
			
		||||
							is->ps_ResultTupleSlot->tts_fixedTupleDescriptor)
 | 
			
		||||
							TTS_FIXED(is->ps_ResultTupleSlot))
 | 
			
		||||
							desc = is->ps_ResultTupleSlot->tts_tupleDescriptor;
 | 
			
		||||
					}
 | 
			
		||||
					else if (opcode == EEOP_OUTER_FETCHSOME)
 | 
			
		||||
@@ -304,7 +304,7 @@ llvm_compile_expr(ExprState *state)
 | 
			
		||||
						if (!desc &&
 | 
			
		||||
							os &&
 | 
			
		||||
							os->ps_ResultTupleSlot &&
 | 
			
		||||
							os->ps_ResultTupleSlot->tts_fixedTupleDescriptor)
 | 
			
		||||
							TTS_FIXED(os->ps_ResultTupleSlot))
 | 
			
		||||
							desc = os->ps_ResultTupleSlot->tts_tupleDescriptor;
 | 
			
		||||
					}
 | 
			
		||||
					else
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user