• 【 OpenGauss源码学习 —— 列存储(CStoreAllocator 类)】


    声明:本文的部分内容参考了他人的文章。在编写过程中,我们尊重他人的知识产权和学术成果,力求遵循合理使用原则,并在适用的情况下注明引用来源。
    本文主要参考了 OpenGauss1.1.0 的开源代码和《OpenGauss数据库源码解析》一书以及OpenGauss社区学习文档和一些参考资料

    CStoreAllocator 类

      CStoreAllocator 类列式存储引擎中担任关键角色,负责管理列存储表的空间分配和释放。它通过提供静态方法获取列存储文件列存储单元的空间,以及执行空间锁定释放操作,有效地支持列存储表扩展管理。此外,该类还涉及CUIDColumn UID)的管理,包括获取下一个 CUID重新检查最大 CUID 等操作,为列存储引擎提供了对列的唯一标识和顺序管理的支持。通过这些功能,CStoreAllocator 实现了在列存储引擎中的高效空间管理,为列存储表的数据组织和访问提供了基础支持。
      以下是该类的主要功能:

    1. 空间分配和释放: 提供了静态方法来获取列存储的文件空间列存储单元CU的空间。这包括对文件空间的扩展对空闲空间管理器(Free Space Manager,FSM)的查询
    • AcquireFileSpace列存储文件获取空间
    • AcquireSpace列存储单元获取空间
    • TryAcquireSpaceFromFSM尝试从自由空间管理器获取空间。
    1. 空间锁定和释放提供了静态方法来在执行空间分配前后对表进行锁定和解锁
    • LockRelForAcquireSpace执行空间分配前锁定表
    • ReleaseRelForAcquireSpace执行空间分配后解锁表
    1. 其他空间管理操作提供了其他一些与空间管理相关的操作,如无效列空间缓存构建列空间缓存等。
    • InvalidColSpaceCache使列空间缓存无效
    • BuildColSpaceCacheForRel为表构建列空间缓存
    1. CUIDColumn UID管理提供了获取下一个CUID重新检查最大 CUID 等方法。
    • GetNextCUID获取下一个 CUID
    • recheck_max_cuid重新检查最大 CUID

      CStoreAllocator 类源码如下所示:(路径:src/gausskernel/storage/cstore/cstore_allocspace.cpp

    class CStoreAllocator : public BaseObject {
    
    private:
        CStoreAllocator();
        virtual ~CStoreAllocator();
    
    public:
        // 初始化列空间缓存
        static void InitColSpaceCache(void);
    
        // 重置列空间缓存
        static void ResetColSpaceCache(void);
    
        // 获取下一个 CUID
        static uint32 GetNextCUID(Relation rel);
    
        // 在获取空间之前需要锁定关系
        static void LockRelForAcquireSpace(Relation rel);
    
        // 释放获取空间前的关系锁
        static void ReleaseRelForAcquireSpace(Relation rel);
    
        // 获取文件空间
        static uint32 AcquireFileSpace(const CFileNode& cnode, uint64 extend_offset, uint64 cu_offset, uint32 cu_size);
    
        // 获取 CU 的空间
        static uint64 AcquireSpace(const CFileNode& cnode, Size size, int align_size);
    
        // 从自由空间中尝试获取 CU 的空间
        static uint64 TryAcquireSpaceFromFSM(CStoreFreeSpace* fsm, Size size, int align_size);
    
        // 使列空间缓存无效
        static void InvalidColSpaceCache(const CFileNode& cnode);
    
        // 为关系构建列空间缓存
        static void BuildColSpaceCacheForRel(const CFileNode* cnodes, int nColumn, uint64* offsets, uint32 maxCUID);
    
        // 为关系构建列空间缓存
        static void BuildColSpaceCacheForRel(
            _in_ Relation heapRel, _in_ AttrNumber* attrIds, _in_ int attrNum, _in_ List* btreeIndex = NIL);
    
        // 检查列空间缓存是否存在
        static bool ColSpaceCacheExist(const CFileNode* cnodes, int nColumn);
    
        // 获取扩展偏移量
        static uint64 GetExtendOffset(uint64 max_offset);
    
        // 计算扩展大小
        static uint32 CalcExtendSize(uint64 cu_offset, uint32 cu_size, uint64 extend_offset);
    
        // 重新检查最大 CUID
        static uint32 recheck_max_cuid(Relation m_rel, uint32 max_cuid, int index_num, Relation* m_idxRelation);
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

      我们可能不会对每个成员函数都进行分析,感兴趣的读者可以自行阅读源码。

    CStoreAllocator::InitColSpaceCache 函数

      CStoreAllocator::InitColSpaceCache 函数用于初始化列式存储引擎中的列空间缓存,即用于管理列存储文件空间信息的哈希表。在初始化之前,它首先检查是否已经存在列空间缓存,如果不存在,则创建一个新的哈希表哈希表的键是 CStoreColumnFileTag 结构,用于唯一标识列存储文件的标签,而哈希表的值是 CStoreColFileDesc 结构,用于存储列存储文件的描述信息。初始化完成后,该哈希表将用于存储和检索列存储文件的空间信息。函数源码如下所示:(路径:src/gausskernel/storage/cstore/cstore_allocspace.cpp

    void CStoreAllocator::InitColSpaceCache(void)
    {
    	// 初始化哈希表控制结构
        HASHCTL ctl;
    
        // 检查是否已经存在列空间缓存
        if (CStoreColspaceCache == NULL) {
            errno_t rc = memset_s(&ctl, sizeof(ctl), 0, sizeof(ctl));
            securec_check(rc, "", "");
            
            // 设置哈希表键的大小为 CStoreColumnFileTag 结构的大小
            ctl.keysize = sizeof(CStoreColumnFileTag);
            // 设置哈希表项的大小为 CStoreColFileDesc 结构的大小
            ctl.entrysize = sizeof(CStoreColFileDesc);
            // 设置哈希函数为 tag_hash
            ctl.hash = tag_hash;
    
            // 创建并初始化列空间缓存的哈希表
            CStoreColspaceCache =
                HeapMemInitHash("CStore Column Space Cache", 40960, 81920, &ctl, HASH_ELEM | HASH_FUNCTION);
    
            // 检查哈希表是否成功创建
            if (CStoreColspaceCache == NULL)
                ereport(PANIC, (errmsg("could not initialize CStore Column space desc hash table")));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    CStoreAllocator::ResetColSpaceCache 函数

      CStoreAllocator::ResetColSpaceCache 函数的作用是重置列存储中用于管理列空间的缓存哈希表。在列存储中,每个列都有对应的空间描述信息,用于记录该列的文件偏移等信息。重置过程中,会清空哈希表中的所有数据,通常在一些需要重新加载列信息的场景下调用,确保列信息的准确性。函数源码如下所示:(路径:src/gausskernel/storage/cstore/cstore_allocspace.cpp

    void CStoreAllocator::ResetColSpaceCache(void)
    {
        // 如果列空间缓存已经初始化
        if (CStoreColspaceCache != NULL) {
            // 重置列空间缓存哈希表
            HeapMemResetHash(CStoreColspaceCache, "CStore Column Space Cache");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    CStoreAllocator::GetNextCUID 函数

      CStoreAllocator::GetNextCUID 函数的作用是获取下一个可用的CUID(Column ID),用于标识列存储中的新的列单元Column Unit。在获取过程中,会检查 CUID 是否已用尽,如果已用尽则抛出错误。同时,如果 CUID 接近耗尽阈值,会发出警告。最后,增加最大 CUID为下一个列单元做准备。函数源码如下所示:(路径:src/gausskernel/storage/cstore/cstore_allocspace.cpp

    uint32 CStoreAllocator::GetNextCUID(Relation rel)
    {
        // 标识是否在哈希表中找到对应项
        bool found = false;
        // 用于存储哈希表中的项
        CStoreColFileDesc* entry = NULL;
        // 用于存储获取到的CUID
        uint32 cuid = InValidCUID;
        // 构建标识列文件的哈希表键
        CStoreColumnFileTag tag(rel->rd_node, VirtualSpaceCacheColID, MAIN_FORKNUM);
    
        // 获取列空间哈希表的锁,以进行写操作
        (void)LWLockAcquire(CStoreColspaceCacheLock, LW_EXCLUSIVE);
        // 在列空间哈希表中查找对应的项
        entry = (CStoreColFileDesc*)hash_search(CStoreColspaceCache, (void*)&tag, HASH_FIND, &found);
        // 断言确保找到对应项
        Assert(found);
        // 获取到当前的最大CUID
        cuid = entry->maxCuid;
        // 如果CUID已用尽,则抛出错误
        if (cuid == MaxCUID)
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
                     errmsg("No CUID is left for new CU in relation \"%u\". Please execute the VACUUM FULL before doing "
                            "anything else",
                            rel->rd_id)));
        // 如果CUID接近耗尽阈值,则发出警告
        if (cuid > CUIDWarningThreshold && cuid < MaxCUID)
            ereport(WARNING, (errmsg("CUID is almost used up in relation \"%u\"", rel->rd_id)));
        // 增加最大CUID,为下一个CU做准备
        entry->maxCuid++;
        // 释放列空间哈希表的锁
        LWLockRelease(CStoreColspaceCacheLock);
        // 返回获取到的CUID
        return cuid;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    CStoreAllocator::AcquireSpace 函数

      CStoreAllocator::AcquireSpace 函数的作用是为列文件分配空间,其中包括在列空间哈希表中查找对应的列文件描述项,并根据对齐要求文件扩展大小等信息计算出列文件中新的偏移量。在更新最大偏移量之前,通过 CStoreAllocator::AcquireFileSpace 函数完成对列文件的扩展。函数源码如下所示:(路径:src/gausskernel/storage/cstore/cstore_allocspace.cpp

    uint64 CStoreAllocator::AcquireSpace(const CFileNode& cnode, Size size, int align_size)
    {
        // 断言:对齐大小必须大于0
        Assert(align_size > 0);
        // 用于标识是否在哈希表中找到对应项
        bool found = false;
        // 用于存储找到的列文件描述项
        CStoreColFileDesc* entry = NULL;
        // 初始偏移量为无效值
        uint64 offset = InvalidCStoreOffset;
        // 用于存储文件扩展大小
        uint32 extend_size = 0;
    
        // 获取列空间哈希表的独占锁
        LWLockAcquire(CStoreColspaceCacheLock, LW_EXCLUSIVE);
        // 在列空间哈希表中查找与给定CFileNode相对应的项
        entry = (CStoreColFileDesc*)hash_search(CStoreColspaceCache, (const void*)&cnode, HASH_FIND, &found);
        // 断言:必须找到对应项
        Assert(found);
        // 如果找到对应项
        if (found) {
            // 将偏移量设置为找到的最大偏移量
            offset = entry->maxOffset;
            // 在升级时,最后一个列单元需要添加填充,因此cu_point必须向后对齐
            int remainder = offset % align_size;
            // 如果remainder不为0,表示需要进行对齐操作
            if (remainder != 0) {
                // 发出警告消息
                ereport(WARNING, (errmsg("AcquireSpace: find un align size(%lu)", offset)));
                // 进行对齐操作
                offset = offset + align_size - remainder;
                // 更新最大偏移量
                entry->maxOffset = offset;
            }
    
            // 必须在更新之前完成快速扩展,因为我们不能留下空洞
            extend_size = CStoreAllocator::AcquireFileSpace(cnode, entry->extendOffset, entry->maxOffset, size);
    
            // 更新最大偏移量和扩展偏移量
            entry->maxOffset += size;
            entry->extendOffset += extend_size;
        }
        // 释放列空间哈希表的独占锁
        LWLockRelease(CStoreColspaceCacheLock);
        // 返回偏移量
        return offset;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    CStoreAllocator::AcquireFileSpace 函数

      CStoreAllocator::AcquireFileSpace 该函数的作用是为列文件分配文件空间,其中包括对列文件进行扩展操作。在快速分配策略下,通过 CUStorage 对象的 FastExtendFile 函数实现快速扩展;在非快速分配策略下,通过分配缓冲区、填充 0,并通过 CUStorage 对象的 SaveCU 函数保存列单元。最后,释放 CUStorage 对象返回扩展大小

    :其中 CUStorage 相关内容可以阅读【 OpenGauss源码学习 —— 列存储(CUStorage)】一文

      CStoreAllocator::AcquireFileSpace 函数源码如下所示:(路径:src/gausskernel/storage/cstore/cstore_allocspace.cpp

    /*
     * @Description: 分配文件大小
     * @Param[IN] extend_offset: 扩展偏移量
     * @Param[IN] size: 列单元大小
     * @See also:
     */
    uint32 CStoreAllocator::AcquireFileSpace(const CFileNode& cnode, uint64 extend_offset, uint64 cu_offset, uint32 cu_size)
    {
        // 用于存储扩展大小
        uint32 extend_size = 0;
        // 创建CUStorage对象,用于对列文件进行操作
        CUStorage* cuStorage = New(CurrentMemoryContext) CUStorage(cnode);
    
        // 在ADIO模式下运行
        ADIO_RUN()
        {
            // 如果启用了快速分配策略
            if (u_sess->attr.attr_sql.enable_fast_allocate) {
                // 计算扩展大小
                extend_size = CStoreAllocator::CalcExtendSize(cu_offset, (uint32)cu_size, extend_offset);
                // 如果扩展大小不为0,则使用快速扩展文件
                if (extend_size != 0) {
                    cuStorage->FastExtendFile(extend_offset, extend_size, true);
                }
                // 使用快速扩展文件
                cuStorage->FastExtendFile(cu_offset, cu_size, false);
            } else {
                // 分配缓冲区,填充0,然后保存CU
                char* buffer = (char*)adio_align_alloc(cu_size);
                errno_t rc = memset_s(buffer, cu_size, 0, cu_size);
                securec_check(rc, "\0", "\0");
                cuStorage->SaveCU(buffer, cu_offset, cu_size, true);
                adio_align_free(buffer);
                extend_size = cu_size;
            }
        }
        // 在非ADIO模式下运行
        ADIO_ELSE()
        {
            // 分配缓冲区,填充0,然后保存CU
            char* buffer = (char*)palloc0(cu_size);
            cuStorage->SaveCU(buffer, cu_offset, cu_size, false, true);
            pfree(buffer);
            buffer = NULL;
            extend_size = cu_size;
        }
        // 结束ADIO模式
    
        // 释放CUStorage对象
        DELETE_EX(cuStorage);
    
        // 返回扩展大小
        return extend_size;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    CStoreAllocator::TryAcquireSpaceFromFSM 函数

      该函数的作用是从给定的空闲空间管理器Free Space Manager,FSM)中尝试获取指定大小的空间,并确保满足对齐要求。函数通过弹出最大大小的空闲空间描述项计算偏移量,并在升级时进行对齐操作。如果成功获取空间,则更新描述项的起始偏移量和大小,并将其重新推入空闲空间管理器。最终返回成功获取的偏移量。函数源码如下所示:(路径:src/gausskernel/storage/cstore/cstore_allocspace.cpp

    uint64 CStoreAllocator::TryAcquireSpaceFromFSM(CStoreFreeSpace* fsm, Size size, int align_size)
    {
        // 存储空闲空间的描述项
        CStoreFreeSpaceDesc desc;
        // 初始偏移量为无效值
        uint64 offset = InvalidCStoreOffset;
    
        // 断言:空闲空间管理器不能为空
        Assert(fsm != NULL);
        // 断言:对齐大小必须大于0
        Assert(align_size > 0);
        // 如果空闲空间管理器没有足够的空间
        if (!fsm->HasEnoughSpace(size + align_size))
            return offset;
    
        // 从空闲空间管理器中弹出最大大小的描述项
        fsm->PopDescWithMaxSize(desc);
        // 将偏移量设置为描述项的起始偏移量
        offset = desc.beginOffset;
    
        // 在升级时,最后一个列单元需要添加填充,因此cu_point必须向后对齐
        int remainder = offset % align_size;
        // 如果remainder不为0,表示需要进行对齐操作
        if (remainder != 0) {
            // 发出警告消息
            ereport(WARNING, (errmsg("TryAcquireSpaceFromFSM: find un align size(%lu)", offset)));
            // 进行对齐操作
            offset = offset + align_size - remainder;
            // 更新描述项的起始偏移量和大小
            desc.beginOffset = offset;
            desc.size -= remainder;
        }
    
        // 更新描述项的起始偏移量和大小
        desc.beginOffset += size;
        desc.size -= size;
        // 如果描述项的大小仍然大于0,将其重新推入空闲空间管理器
        if (desc.size > 0)
            fsm->Push(desc);
        // 返回偏移量
        return offset;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

      其中,CStoreAllocator::TryAcquireSpaceFromFSM 函数由 CUStorage::AllocSpace 函数调用,因为在【 OpenGauss源码学习 —— 列存储(CUStorage)】一文中没有对 CUStorage::AllocSpace 函数进行介绍,这里顺带简述一下。

    CUStorage::AllocSpace 函数

      CUStorage::AllocSpace 函数根据存储策略选择不同的分配方式,其中包括使用自由空间管理器Free Space Manager)或者使用追加模式。函数尝试从自由空间管理器中获取指定大小的空间,如果获取失败则使用追加模式从 CStore 分配器中获取。最终返回成功获取的偏移量,并根据分配模式标记是否为追加模式。函数源码如下所示:(路径:src/gausskernel/storage/cstore/custorage.cpp

    uint64 CUStorage::AllocSpace(_in_ int size)
    {
        // 初始偏移量为无效值
        uint64 offset = InvalidCStoreOffset;
        // 对齐大小,默认为2字节对齐
        int align_size = is_2byte_align ? ALIGNOF_TIMESERIES_CUSIZE : ALIGNOF_CUSIZE;
    
        // 根据策略选择不同的分配方式
        switch (m_strategy) {
            // 使用自由空间管理器(Free Space Manager)
            case USING_FREE_SPACE:
                // 尝试从自由空间管理器中获取指定大小的空间
                offset = CStoreAllocator::TryAcquireSpaceFromFSM(m_freespace, size, align_size);
                // 如果成功获取到空间
                if (offset != InvalidCStoreOffset) {
                    // 标记为非追加模式
                    append_only = false;
                    break;
                }
                // 如果没有合适的空闲空间,使用追加模式
            /* if no free space fits, use the APPEND_ONLY way */
            case APPEND_ONLY:
                // 从CStore分配器中获取指定大小的空间
                offset = CStoreAllocator::AcquireSpace(m_cnode, size, align_size);
                // 标记为追加模式
                append_only = true;
                break;
            // 默认情况下,断言失败
            default:
                Assert(false);
                break;
        }
    
        // 返回最终的偏移量
        return offset;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    CStoreAllocator::InvalidColSpaceCache 函数

      CStoreAllocator::InvalidColSpaceCache 函数用于使指定文件节点的列存空间缓存项失效,首先获取列存空间缓存锁,然后在列存空间缓存中查找并移除指定文件节点的缓存项,最后释放列存空间缓存锁。其中,CStoreAllocator::InvalidColSpaceCache 函数分别由:CStore::InvalidRelSpaceCacheCStore::UnlinkColDataFileCStore::TruncateStorageInSameXact 函数调用。其中 CStore 的介绍可以浏览【 OpenGauss源码学习 —— 列存储(CStore)】系列相关文章。
      CStoreAllocator::InvalidColSpaceCache 函数源码如下所示:(路径:src/gausskernel/storage/cstore/custorage.cpp

    void CStoreAllocator::InvalidColSpaceCache(const CFileNode& cnode)
    {
        // 获取列存空间缓存锁
        LWLockAcquire(CStoreColspaceCacheLock, LW_EXCLUSIVE);
        
        // 在列存空间缓存中查找并移除指定文件节点的缓存项
        hash_search(CStoreColspaceCache, (void*)&cnode, HASH_REMOVE, NULL);
        
        // 释放列存空间缓存锁
        LWLockRelease(CStoreColspaceCacheLock);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    CStoreAllocator::BuildColSpaceCacheForRel 函数

      CStoreAllocator::BuildColSpaceCacheForRel 函数用于构建关联关系的列存空间缓存,首先创建虚拟文件节点标签表示全局列存空间缓存,然后获取列存空间缓存锁。接着,检查关联关系的所有缓存项是否有效,如果无效则进行更新遍历所有列,将它们的信息插入到列存空间缓存中,最后释放列存空间缓存锁。函数源码如下所示:(路径:src/gausskernel/storage/cstore/custorage.cpp

    void CStoreAllocator::BuildColSpaceCacheForRel(const CFileNode* cnodes, int nColumn, uint64* offsets, uint32 maxCUID)
    {
        // 创建虚拟文件节点标签,表示全局列存空间缓存
        CFileNode tag(cnodes[0].m_rnode, VirtualSpaceCacheColID, MAIN_FORKNUM);
        // 标记是否在列存空间缓存中找到相关项
        bool found = false;
        // 列存文件描述项指针
        CStoreColFileDesc* entry = NULL;
    
        // 获取列存空间缓存锁
        LWLockAcquire(CStoreColspaceCacheLock, LW_EXCLUSIVE);
    
        // 检查关联关系的所有缓存项是否有效
        // 如果无效,进行更新;如果有效,跳过
        entry = (CStoreColFileDesc*)hash_search(CStoreColspaceCache, (void*)&tag, HASH_ENTER, &found);
        if (entry == NULL)
            ereport(PANIC, (errmsg("build global column space cache hash table failed")));
    
        // 其他会话已经插入了关联关系的一些列或所有列到哈希表中
        // !!!注意我们重用了变量 'found'
        if (found) {
            for (int i = 0; i < nColumn; i++) {
                hash_search(CStoreColspaceCache, (void*)&cnodes[i], HASH_FIND, &found);
    
                // 其他会话已经插入了一些列
                // 这是不完整的
                if (!found)
                    break;
            }
        }
    
        if (!found) {
            entry->maxCuid = maxCUID;
            entry->maxOffset = InvalidCStoreOffset;
    
            // 遍历所有列,将它们的信息插入到列存空间缓存中
            for (int i = 0; i < nColumn; i++) {
                entry = (CStoreColFileDesc*)hash_search(CStoreColspaceCache, (void*)&cnodes[i], HASH_ENTER, NULL);
                if (entry == NULL)
                    ereport(PANIC, (errmsg("build global column space cache hash table failed")));
                entry->maxOffset = offsets[i];
                entry->maxCuid = InValidCUID;
                entry->extendOffset = CStoreAllocator::GetExtendOffset(entry->maxOffset);
            }
        }
    
        // 释放列存空间缓存锁
        LWLockRelease(CStoreColspaceCacheLock);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    CStoreAllocator::ColSpaceCacheExist 函数

      CStoreAllocator::ColSpaceCacheExist 函数用于检查关联关系的列是否存在于列存空间缓存中,首先获取列存空间缓存锁,然后遍历所有列检查它们是否在列存空间缓存中,最后释放列存空间缓存锁。函数源码如下所示:(路径:src/gausskernel/storage/cstore/custorage.cpp

    bool CStoreAllocator::ColSpaceCacheExist(const CFileNode* cnodes, int nColumn)
    {
        // 标记是否在列存空间缓存中找到相关项
        bool found = false;
    
        // 获取列存空间缓存锁
        LWLockAcquire(CStoreColspaceCacheLock, LW_SHARED);
    
        // 遍历所有列,检查它们是否在列存空间缓存中
        for (int i = 0; i < nColumn; i++) {
            hash_search(CStoreColspaceCache, (void*)&cnodes[i], HASH_FIND, &found);
            if (!found)
                break;
        }
    
        // 释放列存空间缓存锁
        LWLockRelease(CStoreColspaceCacheLock);
        return found;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    CStoreAllocator::GetExtendOffset 函数

      CStoreAllocator::GetExtendOffset 函数用于计算快速扩展的偏移量,首先获取快速扩展文件大小的段大小,然后计算当前最大偏移量对应的文件偏移量,并计算偏移量对段大小的余数。如果余数不为0,则将最大偏移量调整到下一个段的起始位置,最后返回调整后的最大偏移量作为扩展偏移量。函数源码如下所示:(路径:src/gausskernel/storage/cstore/custorage.cpp

    /*
     * @Description: 计算快速扩展偏移量
     * @Param[IN] max_offset: 文件的最大CU指针
     * @Return: 扩展偏移量
     * @See also:
     */
    uint64 CStoreAllocator::GetExtendOffset(uint64 max_offset)
    {
        // 获取快速扩展文件大小的段大小
        int extend_segment = (int)(u_sess->attr.attr_storage.fast_extend_file_size * 1024LL);
    
        // 计算当前最大偏移量对应的文件偏移量
        uint64 offset = CU_FILE_OFFSET(max_offset);
    
        // 计算偏移量对段大小的余数
        uint64 remainder = offset % extend_segment;
    
        // 如果余数不为0,则将最大偏移量调整到下一个段的起始位置
        if (remainder != 0) {
            max_offset = max_offset + extend_segment - remainder;
        }
    
        // 返回调整后的最大偏移量作为扩展偏移量
        return max_offset;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    CStoreAllocator::CalcExtendSize 函数

      CStoreAllocator::CalcExtendSize 函数用于在分配空间时计算快速扩展的大小。首先获取快速扩展文件大小的段大小,然后计算剩余的扩展大小。如果 CU 大小小于等于剩余的扩展大小,则不需要进行快速扩展,返回 0。接着计算需要的文件大小,如果需要的文件大小小于等于段大小,则扩展大小设为段大小。最后,计算需要的文件大小对段大小的余数,计算扩展大小,使其为段大小的倍数,并返回扩展大小。函数源码如下所示:(路径:src/gausskernel/storage/cstore/custorage.cpp

    /*
     * @Description: 计算分配空间时的扩展大小
     * @Param[IN] cu_offset: 最大CU偏移量
     * @Param[IN] cu_size: 写入CU的大小
     * @Param[IN] extend_offset: 记录的扩展偏移量
     * @Return: 0 -- 不需要扩展,其他值为扩展大小
     * @See also:
     */
    uint32 CStoreAllocator::CalcExtendSize(uint64 cu_offset, uint32 cu_size, uint64 extend_offset)
    {
        // 获取快速扩展文件大小的段大小
        uint32 extend_segment = (uint32)(u_sess->attr.attr_storage.fast_extend_file_size * 1024LL);
    
        // 计算剩余的扩展大小
        uint32 left_extend_size = extend_offset - cu_offset;
    
        // 如果CU大小小于等于剩余的扩展大小,不需要进行快速扩展
        if (cu_size <= left_extend_size) {
            return 0;
        }
    
        // 计算需要的文件大小
        uint32 need_file_size = cu_size - left_extend_size;
    
        // 如果需要的文件大小小于等于段大小,扩展大小设为段大小
        if (need_file_size <= extend_segment) {
            return extend_segment;
        }
    
        // 计算需要的文件大小对段大小的余数
        uint32 remainder = need_file_size % extend_segment;
    
        // 计算扩展大小,使其为段大小的倍数
        return need_file_size + extend_segment - remainder;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    CStoreAllocator::recheck_max_cuid 函数

      CStoreAllocator::recheck_max_cuid 函数用于在获取最大 CUID重新检查最大 CUID。首先,遍历所有索引,找到支持 CBTREE 和 CGIN 的索引。然后,如果没有支持 CBTREE 和 CGIN 的索引,直接返回原始的最大 CUID。接着,获取支持 CBTREE 和 CGIN 的索引中的最大 CUID,并释放索引列表。如果索引中的最大 CUID等于 MaxCUID报错。最后,如果索引中的最大 CUID 大于原始最大 CUID更新缓存中的最大 CUID,并返回索引中的最大 CUID;如果索引中的最大 CUID 不大于原始最大CUID,则返回原始最大 CUID。函数源码如下所示:(路径:src/gausskernel/storage/cstore/custorage.cpp

    /**
     * 由于在获取最大CUID后我们释放了锁,我们会怀疑系统的最大CUID,因此在此重新检查位于索引中的最大CUID。
     * 我们希望确保索引中没有更大的CUID。
     */
    uint32 CStoreAllocator::recheck_max_cuid(Relation m_rel, uint32 max_cuid, int index_num, Relation* m_idxRelation)
    {
        bool find = false;
        List* index_rel_list = NIL;
    
        // 遍历所有索引,找到支持CBTREE和CGIN的索引
        for (int i = 0; i < index_num; ++i) {
            Oid am_oid = m_idxRelation[i]->rd_rel->relam;
            if (am_oid == CBTREE_AM_OID || am_oid == CGIN_AM_OID) {
                index_rel_list = lappend(index_rel_list, m_idxRelation[i]);
            }
        }
    
        // 如果没有支持CBTREE和CGIN的索引,则返回原始的最大CUID
        if (list_length(index_rel_list) == 0) {
            return max_cuid;
        }
    
        // 获取索引中的最大CUID,并释放索引列表
        uint32 max_idx_cuid = CStore::GetMaxIndexCUID(m_rel, index_rel_list) + 1;
        list_free_ext(index_rel_list);
    
        // 如果索引中的最大CUID等于MaxCUID,报错
        if (max_idx_cuid == MaxCUID) {
            ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
                            errmsg("No CUID is left for new CU in relation \"%u\".", m_rel->rd_id)));
        }
    
        // 如果索引中的最大CUID大于原始最大CUID,更新缓存中的最大CUID,并返回索引中的最大CUID
        if (max_idx_cuid > max_cuid) {
            CStoreColFileDesc* entry = NULL;
            CStoreColumnFileTag tag(m_rel->rd_node, VirtualSpaceCacheColID, MAIN_FORKNUM);
            (void)LWLockAcquire(CStoreColspaceCacheLock, LW_EXCLUSIVE);
            entry = (CStoreColFileDesc*)hash_search(CStoreColspaceCache, (void*)&tag, HASH_FIND, &find);
            Assert(find);
            entry->maxCuid = max_idx_cuid + 1;
            LWLockRelease(CStoreColspaceCacheLock);
            return max_idx_cuid;
        }
    
        // 如果索引中的最大CUID不大于原始最大CUID,则返回原始最大CUID
        return max_cuid;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
  • 相关阅读:
    内外通、效益增 | 数商云•瓴犀产品3.0开启全方位精准精细化协同模式
    c++&qt day4
    机器学习——代价敏感错误率与代价曲线
    高压放大器的输入和输出阻抗为啥是50欧的
    数据结构:二叉搜索树
    pandas数据分析 - 分组聚合、分组转换、分组筛选
    Gmail 将停止支持基本 HTML 视图
    推荐模型复现(一):熟悉Torch-RecHub框架与使用
    善用开发工具
    【C++】-- 继承
  • 原文地址:https://blog.csdn.net/qq_43899283/article/details/134448446