本篇内容介绍了“PostgreSQL中fsm_search函数有什么作用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
一、数据结构
宏定义
包括FSM页面的叶子节点数/非叶子节点数/FSM树深度等等.
#define MaxFSMRequestSize MaxHeapTupleSize
#define MaxHeapTupleSize (BLCKSZ - MAXALIGN(SizeOfPageHeaderData + sizeof(ItemIdData)))
#define FSM_CAT_STEP (BLCKSZ / FSM_CATEGORIES)
#define FSM_CATEGORIES 256
//块大小为8K则FSM_CAT_STEP = 32
#define SlotsPerFSMPage LeafNodesPerPage
#define LeafNodesPerPage (NodesPerPage - NonLeafNodesPerPage) = 8156 - 4095 = 4061
#define NodesPerPage (BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - \
offsetof(FSMPageData, fp_nodes)) = 8192 - 32 - 4 = 8156
#define NonLeafNodesPerPage (BLCKSZ / 2 - 1) = 4095
#define FSM_TREE_DEPTH ((SlotsPerFSMPage >= 1626) ? 3 : 4)
FSMAddress
内部的FSM处理过程以逻辑地址scheme的方式工作,树的每一个层次都可以认为是一个独立的地址文件.
typedef struct
{
//层次
int level;
//该层次内的页编号
int logpageno;
} FSMAddress;
//根页地址
static const FSMAddress FSM_ROOT_ADDRESS = {FSM_ROOT_LEVEL, 0};
FSMPage
FSM page数据结构.详细可参看src/backend/storage/freespace/README.
typedef struct
{
int fp_next_slot;
uint8 fp_nodes[FLEXIBLE_ARRAY_MEMBER];
} FSMPageData;
typedef FSMPageData *FSMPage;
FSMLocalMap
对于小表,不需要创建FSM来存储空间信息,使用本地的内存映射信息.
//已尝试或者已在表的末尾之后
#define FSM_LOCAL_NOT_AVAIL 0x00
//可用于尝试
#define FSM_LOCAL_AVAIL 0x01
typedef struct
{
BlockNumber nblocks;//块数
uint8 map[HEAP_FSM_CREATION_THRESHOLD];//数组
} FSMLocalMap;
static FSMLocalMap fsm_local_map =
{
0,
{
FSM_LOCAL_NOT_AVAIL
}
};
#define FSM_LOCAL_MAP_EXISTS (fsm_local_map.nblocks > 0)
通用例程
包括获取左子节点/右子节点/父节点等
//在page中遍历树.Root编号为0
#define leftchild(x) (2 * (x) + 1)
#define rightchild(x) (2 * (x) + 2)
#define parentof(x) (((x) - 1) / 2)
static int
rightneighbor(int x)
{
x++;
if (((x + 1) & x) == 0)//有符号整型,全1为0
x = parentof(x);
return x;
}
static BlockNumber
fsm_logical_to_physical(FSMAddress addr)
{
BlockNumber pages;//块号
int leafno;//页号
int l;//临时变量
leafno = addr.logpageno;
for (l = 0; l < addr.level; l++)
leafno *= SlotsPerFSMPage;
//统计用于定位叶子页面的上层节点数
pages = 0;
for (l = 0; l < FSM_TREE_DEPTH; l++)
{
pages += leafno + 1;
leafno /= SlotsPerFSMPage;
}
pages -= addr.level;
//计数从0开始(减一)
return pages - 1;
}
//addr = fsm_get_location(oldPage, &slot);
static FSMAddress
fsm_get_location(BlockNumber heapblk, uint16 *slot)
{
FSMAddress addr;
addr.level = FSM_BOTTOM_LEVEL;
//#define SlotsPerFSMPage LeafNodesPerPage
//#define LeafNodesPerPage (NodesPerPage - NonLeafNodesPerPage) = 8156 - 4095 = 4061
//#define NodesPerPage (BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - \
offsetof(FSMPageData, fp_nodes)) = 8192 - 32 - 4 = 8156
//#define NonLeafNodesPerPage (BLCKSZ / 2 - 1) = 4095
addr.logpageno = heapblk / SlotsPerFSMPage;
*slot = heapblk % SlotsPerFSMPage;
return addr;
}
二、源码解读
fsm_search函数搜索FSM,找到有足够空闲空间(min_cat)的堆page.
//return fsm_search(rel, search_cat);
static BlockNumber
fsm_search(Relation rel, uint8 min_cat)
{
int restarts = 0;
FSMAddress addr = FSM_ROOT_ADDRESS;
for (;;)
{
//--------- 循环
int slot;
Buffer buf;
uint8 max_avail = 0;
//读取FSM page
buf = fsm_readbuf(rel, addr, false);
//页内搜索
if (BufferIsValid(buf))
{
LockBuffer(buf, BUFFER_LOCK_SHARE);
//搜索可用的slot
slot = fsm_search_avail(buf, min_cat,
(addr.level == FSM_BOTTOM_LEVEL),
false);
if (slot == -1)
//获取最大可用空间
max_avail = fsm_get_max_avail(BufferGetPage(buf));
UnlockReleaseBuffer(buf);
}
else
//buffer无效,则设置为-1
slot = -1;
if (slot != -1)
{
if (addr.level == FSM_BOTTOM_LEVEL)
return fsm_get_heap_blk(addr, slot);
addr = fsm_get_child(addr, slot);
}
else if (addr.level == FSM_ROOT_LEVEL)
{
return InvalidBlockNumber;
}
else
{
uint16 parentslot;
FSMAddress parent;
parent = fsm_get_parent(addr, &parentslot);
fsm_set_and_search(rel, parent, parentslot, max_avail, 0);
if (restarts++ > 10000)
return InvalidBlockNumber;
//从root开始搜索
addr = FSM_ROOT_ADDRESS;
}
}
}
“PostgreSQL中fsm_search函数有什么作用”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!