Files
openGauss-server/src/include/vecexecutor/vecstore.h
2023-02-21 20:30:35 -08:00

352 lines
9.9 KiB
C++

/*
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* ---------------------------------------------------------------------------------------
*
* vecstore.h
*
*
* IDENTIFICATION
* src/include/vecexecutor/vecstore.h
*
* ---------------------------------------------------------------------------------------
*/
#ifndef VECSTORE_H
#define VECSTORE_H
#include "executor/executor.h"
#include "nodes/execnodes.h"
#include "pgstat.h"
#include "storage/buf/buffile.h"
#include "utils/memutils.h"
#include "utils/memprot.h"
#include "utils/datum.h"
#include "vecexecutor/vectorbatch.h"
#include "workload/workload.h"
/* BatchStore is an opaque type whose details are not known outside
* batchstore.cpp.
* If the first sort column is text or numeric type, allocate one
* more Datum to store the prefixal data for fast compare.
*/
typedef struct MultiColumns {
Datum* m_values;
uint8* m_nulls;
int idx;
int size;
int GetLen(int colNum);
} MultiColumns;
/*
* The data of those column to be sorted or unsorted
*/
typedef struct MultiColumnsData {
MultiColumns* m_memValues;
/*
* The number of columns
*/
int m_colNum;
/*
* The capacity of storing row in memory
*/
int m_capacity;
/*
* The current row number in memory
*/
int m_memRowNum;
/*
* Initialize variables
*/
void Init(int capacity);
bool HasFreeSlot();
void PutValue(MultiColumns val);
inline MultiColumns* GetValue(int row);
} MultiColumnsData;
class VecStore : public BaseObject {
public:
char* GetData(int colNum, MultiColumns* multiColumn);
void SetData(char* dataPtr, int size, MultiColumns* multiColumn);
void InitColInfo(VectorBatch* batch);
bool HasFreeSlot();
void PutValue(MultiColumns multiColumn);
void UseMem(int64 size);
void FreeMem(int64 size);
bool LackMem();
bool GrowMemValueSlots(char* opname, int planid, MemoryContext context);
void AppendBatch(VectorBatch* batch, MultiColumns& multiColumn, int curRow, bool isfree = true);
/*
* abbreSortOptimize used to mark whether allocate one more Datum for
* fast compare of two data(text or numeric type)
*/
template <bool abbreSortOptimize>
MultiColumns CopyMultiColumn(VectorBatch* batch, int row)
{
MultiColumns multiColValue;
m_colNum = batch->m_cols;
if (abbreSortOptimize)
multiColValue.m_values = (ScalarValue*)palloc((batch->m_cols + 1) * sizeof(Datum));
else
multiColValue.m_values = (ScalarValue*)palloc(batch->m_cols * sizeof(Datum));
UseMem(GetMemoryChunkSpace(multiColValue.m_values));
multiColValue.m_nulls = (uint8*)palloc(batch->m_cols * sizeof(uint8));
UseMem(GetMemoryChunkSpace(multiColValue.m_nulls));
if (m_addWidth)
m_colWidth += batch->m_cols * sizeof(Datum) + batch->m_cols * sizeof(uint8);
multiColValue.size = 0;
uint8 flag;
/*
* When faced with NULL, we just skip, in the following produce, we do the same thing.
*/
for (int col = 0; col < batch->m_cols; ++col) {
Form_pg_attribute attr = &tupDesc->attrs[col];
flag = batch->m_arr[col].m_flag[row];
multiColValue.m_nulls[col] = flag;
multiColValue.size += sizeof(uint8);
if (!IS_NULL(flag)) {
if (NeedDecode(col)) {
ScalarValue val = batch->m_arr[col].m_vals[row];
Datum v = ScalarVector::Decode(val);
int typlen = 0;
if (batch->m_arr[col].m_desc.typeId == NAMEOID) {
typlen = datumGetSize(v, false, -2);
} else {
typlen = VARSIZE_ANY(v);
}
multiColValue.m_values[col] = datumCopy(v, attr->attbyval, typlen);
if (m_addWidth)
m_colWidth += typlen;
char* p = DatumGetPointer(multiColValue.m_values[col]);
UseMem(GetMemoryChunkSpace(p));
multiColValue.size += datumGetSize(v, attr->attbyval, typlen);
} else {
multiColValue.m_values[col] = PointerGetDatum(batch->m_arr[col].m_vals[row]);
multiColValue.size += sizeof(Datum);
}
}
}
return multiColValue;
}
FORCE_INLINE bool NeedDecode(int col)
{
if (m_colInfo[col].m_desc.encoded)
return true;
return false;
}
void FreeMultiColumn(MultiColumns* pMultiColumn);
public:
MultiColumnsData m_storeColumns;
/*
* remaining memory allowed, in bytes
*/
int64 m_availMem;
/*
* total memory allowed, in bytes
*/
int64 m_allowedMem;
ScalarVector* m_colInfo;
int m_colNum;
TupleDesc tupDesc;
int64 m_lastFetchCursor;
int64 m_curFetchCursor;
int64 m_colWidth;
bool m_addWidth;
bool m_sysBusy;
int64 m_maxMem;
int m_spreadNum;
int m_planId;
int m_dop;
};
inline bool MultiColumnsData::HasFreeSlot()
{
return m_memRowNum < m_capacity - 1;
}
inline void MultiColumnsData::PutValue(MultiColumns val)
{
m_memValues[m_memRowNum] = val;
++m_memRowNum;
}
inline int MultiColumns::GetLen(int colNum)
{
return size;
}
inline MultiColumns* MultiColumnsData::GetValue(int row)
{
return m_memValues + row;
}
inline void VecStore::UseMem(int64 size)
{
m_availMem -= size;
}
inline void VecStore::FreeMem(int64 size)
{
m_availMem += size;
}
inline bool VecStore::LackMem()
{
int64 usedMem = m_allowedMem - m_availMem;
if (m_availMem < 0 || gs_sysmemory_busy(usedMem * m_dop, true))
return true;
return false;
}
inline bool VecStore::HasFreeSlot()
{
return m_storeColumns.HasFreeSlot();
}
inline bool VecStore::GrowMemValueSlots(char* opname, int planid, MemoryContext context)
{
double grow_ratio =
Min(DEFAULT_GROW_RATIO, ((double)(MaxAllocSize / sizeof(MultiColumns))) / (double)m_storeColumns.m_capacity);
double unspread_ratio = grow_ratio;
bool need_spread = false;
int64 mem_used = m_allowedMem - m_availMem;
if (m_availMem < mem_used)
unspread_ratio = Min(unspread_ratio, (double)m_allowedMem / mem_used);
/* No grow of rows, so return */
if (m_storeColumns.m_capacity * unspread_ratio <= m_storeColumns.m_capacity) {
if (m_maxMem < m_allowedMem)
return false;
else
need_spread = true;
} else
grow_ratio = unspread_ratio;
if (gs_sysmemory_busy((m_allowedMem - m_availMem) * m_dop, true)) {
m_sysBusy = true;
AllocSet sortContext = (AllocSet)context;
sortContext->maxSpaceSize = m_allowedMem - m_availMem;
m_allowedMem = m_allowedMem - m_availMem;
MEMCTL_LOG(LOG,
"%s(%d) early spilled, workmem: %ldKB, freemem: %ldKB.",
opname,
planid,
m_allowedMem / 1024L,
m_availMem / 1024L);
pgstat_add_warning_early_spill();
return false;
}
/* For concurrent case, we don't allow sort/materialize to spread a lot */
if (need_spread && (m_spreadNum < 2 || g_instance.wlm_cxt->stat_manager.comp_count == 1)) {
if (m_availMem < 0)
m_allowedMem -= m_availMem;
int64 spreadMem = Min(Min(dywlm_client_get_memory() * 1024L, m_allowedMem), m_maxMem - m_allowedMem);
if (spreadMem <= m_allowedMem * MEM_AUTO_SPREAD_MIN_RATIO) {
MEMCTL_LOG(LOG,
"%s(%d) auto mem spread %ldKB failed, and work mem is %ldKB.",
opname,
planid,
spreadMem / 1024L,
m_allowedMem / 1024L);
if (m_spreadNum > 0) {
pgstat_add_warning_spill_on_memory_spread();
}
return false;
}
grow_ratio = Min(grow_ratio, 1 + (double)spreadMem / m_allowedMem);
m_allowedMem += spreadMem;
m_availMem = spreadMem;
AllocSet sortContext = (AllocSet)context;
sortContext->maxSpaceSize += spreadMem;
m_spreadNum++;
MEMCTL_LOG(DEBUG2,
"%s(%d) auto mem spread %ldKB succeed, and work mem is %ldKB.",
opname,
planid,
spreadMem / 1024L,
m_allowedMem / 1024L);
}
/* if there's no more space after grow, then fail */
if (m_storeColumns.m_capacity * grow_ratio <= m_storeColumns.m_capacity) {
MEMCTL_LOG(LOG, "%s(%d) mem limit reached.", opname, planid);
return false;
}
if (!gs_sysmemory_avail(mem_used * (grow_ratio - 1))) {
MEMCTL_LOG(LOG,
"%s(%d) mem lack, workmem: %ldKB, freemem: %ldKB,"
"usedmem: %ldKB, grow ratio: %.2f.",
opname,
planid,
m_allowedMem / 1024L,
m_availMem / 1024L,
mem_used / 1024L,
grow_ratio);
return false;
}
FreeMem(GetMemoryChunkSpace(m_storeColumns.m_memValues));
m_storeColumns.m_capacity *= grow_ratio;
m_storeColumns.m_memValues =
(MultiColumns*)repalloc(m_storeColumns.m_memValues, m_storeColumns.m_capacity * sizeof(MultiColumns));
UseMem(GetMemoryChunkSpace(m_storeColumns.m_memValues));
if (m_availMem < 0)
return false;
return true;
}
inline void VecStore::PutValue(MultiColumns multiColValue)
{
m_storeColumns.PutValue(multiColValue);
}
#endif /* VECSTORE_H */