分析PostgreSQL SetupLockInTable方法中与OOM相关的代码
发表于:2025-11-07 作者:千家信息网编辑
千家信息网最后更新 2025年11月07日,这篇文章主要介绍"分析PostgreSQL SetupLockInTable方法中与OOM相关的代码",在日常操作中,相信很多人在分析PostgreSQL SetupLockInTable方法中与OO
千家信息网最后更新 2025年11月07日分析PostgreSQL SetupLockInTable方法中与OOM相关的代码
这篇文章主要介绍"分析PostgreSQL SetupLockInTable方法中与OOM相关的代码",在日常操作中,相信很多人在分析PostgreSQL SetupLockInTable方法中与OOM相关的代码问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"分析PostgreSQL SetupLockInTable方法中与OOM相关的代码"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
有时候我们可能会在PG的日志发现如下信息:
2020-01-09 16:29:19.062 CST,"pg12","testdb",6193,"[local]",5e16dccd.1831,1,"CREATE TABLE",2020-01-09 15:57:01 CST,2/34,1512004206,ERROR,53200,"out of shared memory",,"You might need to increase max_locks_per_transaction.",,,,"CREATE TABLE a13030 (id int);",,,"psql"2020-01-09 16:29:19.379 CST,"pg12","testdb",6193,"[local]",5e16dccd.1831,2,"CREATE TABLE",2020-01-09 15:57:01 CST,2/0,1512004206,ERROR,25P02,"current transaction is aborted, commands ignored until end of transaction block",,,,,,"CREATE TABLE a13031 (id int);",,,"psql"
直观上来看,OOM似乎与max_locks_per_transaction扯不上什么关系,为什么PG会提示增加max_locks_per_transaction的值呢?
一、源码解读
测试脚本
\pset footer off\pset tuples_only\o /tmp/drop.sqlSELECT 'drop table if exists tbl' || id || ' ;' as "--" FROM generate_series(1, 20000) AS id;\i /tmp/drop.sql\pset footer off\pset tuples_only\o /tmp/create.sqlSELECT 'CREATE TABLE tbl' || id || ' (id int);' as "--" FROM generate_series(1, 20000) AS id;\o /tmp/ret.txtbegin;\i /tmp/create.sql
数据结构
HTAB
/* * Top control structure for a hashtable --- in a shared table, each backend * has its own copy (OK since no fields change at runtime) * 哈希表的顶层控制结构. * 在这个共享哈希表中,每一个后台进程都有自己的拷贝 * (之所以没有问题是因为fork出来后,在运行期没有字段会变化) */struct HTAB{ //指向共享的控制信息 HASHHDR *hctl; /* => shared control information */ //段开始目录 HASHSEGMENT *dir; /* directory of segment starts */ //哈希函数 HashValueFunc hash; /* hash function */ //哈希键比较函数 HashCompareFunc match; /* key comparison function */ //哈希键拷贝函数 HashCopyFunc keycopy; /* key copying function */ //内存分配器 HashAllocFunc alloc; /* memory allocator */ //内存上下文 MemoryContext hcxt; /* memory context if default allocator used */ //表名(用于错误信息) char *tabname; /* table name (for error messages) */ //如在共享内存中,则为T bool isshared; /* true if table is in shared memory */ //如为T,则固定大小不能扩展 bool isfixed; /* if true, don't enlarge */ /* freezing a shared table isn't allowed, so we can keep state here */ //不允许冻结共享表,因此这里会保存相关状态 bool frozen; /* true = no more inserts allowed */ /* We keep local copies of these fixed values to reduce contention */ //保存这些固定值的本地拷贝,以减少冲突 //哈希键长度(以字节为单位) Size keysize; /* hash key length in bytes */ //段大小,必须为2的幂 long ssize; /* segment size --- must be power of 2 */ //段偏移,ssize的对数 int sshift; /* segment shift = log2(ssize) */};/* * Header structure for a hash table --- contains all changeable info * 哈希表的头部结构 -- 存储所有可变信息 * * In a shared-memory hash table, the HASHHDR is in shared memory, while * each backend has a local HTAB struct. For a non-shared table, there isn't * any functional difference between HASHHDR and HTAB, but we separate them * anyway to share code between shared and non-shared tables. * 在共享内存哈希表中,HASHHDR位于共享内存中,每一个后台进程都有一个本地HTAB结构. * 对于非共享哈希表,HASHHDR和HTAB没有任何功能性的不同, * 但无论如何,我们还是把它们区分为共享和非共享表. */struct HASHHDR{ /* * The freelist can become a point of contention in high-concurrency hash * tables, so we use an array of freelists, each with its own mutex and * nentries count, instead of just a single one. Although the freelists * normally operate independently, we will scavenge entries from freelists * other than a hashcode's default freelist when necessary. * 在高并发的哈希表中,空闲链表会成为竞争热点,因此我们使用空闲链表数组, * 数组中的每一个元素都有自己的mutex和条目统计,而不是使用一个. * * If the hash table is not partitioned, only freeList[0] is used and its * spinlock is not used at all; callers' locking is assumed sufficient. * 如果哈希表没有分区,那么只有freelist[0]元素是有用的,自旋锁没有任何用处; * 调用者锁定被认为已足够OK. */ /* Number of freelists to be used for a partitioned hash table. */ //#define NUM_FREELISTS 32 FreeListData freeList[NUM_FREELISTS]; /* These fields can change, but not in a partitioned table */ //这些域字段可以改变,但不适用于分区表 /* Also, dsize can't change in a shared table, even if unpartitioned */ //同时,就算是非分区表,共享表的dsize也不能改变 //目录大小 long dsize; /* directory size */ //已分配的段大小(<= dbsize) long nsegs; /* number of allocated segments (<= dsize) */ //正在使用的最大桶ID uint32 max_bucket; /* ID of maximum bucket in use */ //进入整个哈希表的模掩码 uint32 high_mask; /* mask to modulo into entire table */ //进入低于半个哈希表的模掩码 uint32 low_mask; /* mask to modulo into lower half of table */ /* These fields are fixed at hashtable creation */ //下面这些字段在哈希表创建时已固定 //哈希键大小(以字节为单位) Size keysize; /* hash key length in bytes */ //所有用户元素大小(以字节为单位) Size entrysize; /* total user element size in bytes */ //分区个数(2的幂),或者为0 long num_partitions; /* # partitions (must be power of 2), or 0 */ //目标的填充因子 long ffactor; /* target fill factor */ //如目录是固定大小,则该值为dsize的上限值 long max_dsize; /* 'dsize' limit if directory is fixed size */ //段大小,必须是2的幂 long ssize; /* segment size --- must be power of 2 */ //端偏移,ssize的对数 int sshift; /* segment shift = log2(ssize) */ //一次性分配的条目个数 int nelem_alloc; /* number of entries to allocate at once */#ifdef HASH_STATISTICS /* * Count statistics here. NB: stats code doesn't bother with mutex, so * counts could be corrupted a bit in a partitioned table. * 统计信息. * 注意:统计相关的代码不会影响mutex,因此对于分区表,统计可能有一点点问题 */ long accesses; long collisions;#endif};/* * Per-freelist data. * 空闲链表数据. * * In a partitioned hash table, each freelist is associated with a specific * set of hashcodes, as determined by the FREELIST_IDX() macro below. * nentries tracks the number of live hashtable entries having those hashcodes * (NOT the number of entries in the freelist, as you might expect). * 在一个分区哈希表中,每一个空闲链表与特定的hashcodes集合相关,通过下面的FREELIST_IDX()宏进行定义. * nentries跟踪有这些hashcodes的仍存活的hashtable条目个数. * (注意不要搞错,不是空闲的条目个数) * * The coverage of a freelist might be more or less than one partition, so it * needs its own lock rather than relying on caller locking. Relying on that * wouldn't work even if the coverage was the same, because of the occasional * need to "borrow" entries from another freelist; see get_hash_entry(). * 空闲链表的覆盖范围可能比一个分区多或少,因此需要自己的锁而不能仅仅依赖调用者的锁. * 依赖调用者锁在覆盖面一样的情况下也不会起效,因为偶尔需要从另一个自由列表"借用"条目,详细参见get_hash_entry() * * Using an array of FreeListData instead of separate arrays of mutexes, * nentries and freeLists helps to reduce sharing of cache lines between * different mutexes. * 使用FreeListData数组而不是一个独立的mutexes,nentries和freelists数组有助于减少不同mutexes之间的缓存线共享. */typedef struct{ //该空闲链表的自旋锁 slock_t mutex; /* spinlock for this freelist */ //相关桶中的条目个数 long nentries; /* number of entries in associated buckets */ //空闲元素链 HASHELEMENT *freeList; /* chain of free elements */} FreeListData;/* * HASHELEMENT is the private part of a hashtable entry. The caller's data * follows the HASHELEMENT structure (on a MAXALIGN'd boundary). The hash key * is expected to be at the start of the caller's hash entry data structure. * HASHELEMENT是哈希表条目的私有部分. * 调用者的数据按照HASHELEMENT结构组织(位于MAXALIGN的边界). * 哈希键应位于调用者hash条目数据结构的开始位置. */typedef struct HASHELEMENT{ //链接到相同桶中的下一个条目 struct HASHELEMENT *link; /* link to next entry in same bucket */ //该条目的哈希函数结果 uint32 hashvalue; /* hash function result for this entry */} HASHELEMENT;/* Hash table header struct is an opaque type known only within dynahash.c *///哈希表头部结构,非透明类型,用于dynahash.ctypedef struct HASHHDR HASHHDR;/* Hash table control struct is an opaque type known only within dynahash.c *///哈希表控制结构,非透明类型,用于dynahash.ctypedef struct HTAB HTAB;/* Parameter data structure for hash_create *///hash_create使用的参数数据结构/* Only those fields indicated by hash_flags need be set *///根据hash_flags标记设置相应的字段typedef struct HASHCTL{ //分区个数(必须是2的幂) long num_partitions; /* # partitions (must be power of 2) */ //段大小 long ssize; /* segment size */ //初始化目录大小 long dsize; /* (initial) directory size */ //dsize上限 long max_dsize; /* limit to dsize if dir size is limited */ //填充因子 long ffactor; /* fill factor */ //哈希键大小(字节为单位) Size keysize; /* hash key length in bytes */ //参见上述数据结构注释 Size entrysize; /* total user element size in bytes */ // HashValueFunc hash; /* hash function */ HashCompareFunc match; /* key comparison function */ HashCopyFunc keycopy; /* key copying function */ HashAllocFunc alloc; /* memory allocator */ MemoryContext hcxt; /* memory context to use for allocations */ //共享内存中的哈希头部结构地址 HASHHDR *hctl; /* location of header in shared mem */} HASHCTL;/* A hash bucket is a linked list of HASHELEMENTs *///哈希桶是HASHELEMENTs链表typedef HASHELEMENT *HASHBUCKET;/* A hash segment is an array of bucket headers *///hash segment是桶数组typedef HASHBUCKET *HASHSEGMENT;/* * Hash functions must have this signature. * Hash函数必须有它自己的标识 */typedef uint32 (*HashValueFunc) (const void *key, Size keysize); /* * Key comparison functions must have this signature. Comparison functions * return zero for match, nonzero for no match. (The comparison function * definition is designed to allow memcmp() and strncmp() to be used directly * as key comparison functions.) * 哈希键对比函数必须有自己的标识. * 如匹配则对比函数返回0,不匹配返回非0. * (对比函数定义被设计为允许在对比键值时可直接使用memcmp()和strncmp()) */typedef int (*HashCompareFunc) (const void *key1, const void *key2, Size keysize); /* * Key copying functions must have this signature. The return value is not * used. (The definition is set up to allow memcpy() and strlcpy() to be * used directly.) * 键拷贝函数必须有自己的标识. * 返回值无用. */typedef void *(*HashCopyFunc) (void *dest, const void *src, Size keysize);/* * Space allocation function for a hashtable --- designed to match malloc(). * Note: there is no free function API; can't destroy a hashtable unless you * use the default allocator. * 哈希表的恐惧分配函数 -- 被设计为与malloc()函数匹配. * 注意:这里没有释放函数API;不能销毁哈希表,除非使用默认的分配器. */typedef void *(*HashAllocFunc) (Size request);get_hash_entry
分配一个新的哈希表条目.如内存溢出则返回NULL.
/* * Allocate a new hashtable entry if possible; return NULL if out of memory. * (Or, if the underlying space allocator throws error for out-of-memory, * we won't return at all.) * 如可能,分配一个新的哈希表条目.如内存溢出则返回NULL. * (或者,如果依赖的空间分配器因为内存溢出抛出错误,则不会返回任何信息) */static HASHBUCKETget_hash_entry(HTAB *hashp, int freelist_idx){ HASHHDR *hctl = hashp->hctl; HASHBUCKET newElement; for (;;) { //循环 /* if partitioned, must lock to touch nentries and freeList */ //如为分区哈希表,在访问条目和空闲链表时,必须锁定 if (IS_PARTITIONED(hctl)) SpinLockAcquire(&hctl->freeList[freelist_idx].mutex); /* try to get an entry from the freelist */ //从空闲链表中尝试获取一个条目 newElement = hctl->freeList[freelist_idx].freeList; if (newElement != NULL) break; if (IS_PARTITIONED(hctl)) SpinLockRelease(&hctl->freeList[freelist_idx].mutex); /* * No free elements in this freelist. In a partitioned table, there * might be entries in other freelists, but to reduce contention we * prefer to first try to get another chunk of buckets from the main * shmem allocator. If that fails, though, we *MUST* root through all * the other freelists before giving up. There are multiple callers * that assume that they can allocate every element in the initially * requested table size, or that deleting an element guarantees they * can insert a new element, even if shared memory is entirely full. * Failing because the needed element is in a different freelist is * not acceptable. * 在空闲链表中没有空闲条目.在分区哈希表中,在其他空闲链表中可能存在条目, * 但为了减少争用,我们期望首先尝试从主shmem分配器中获取桶中的其他chunk. * 如果失败,我们必须在放弃之前从根节点开始遍历所有其他空闲链表. * 存在多个调用者假定它们可以在初始的请求哈希表大小内分配每一个元素, * 或者甚至在共享内存全满的情况下删除元素可以保证它们可以插入一个新元素. * 之所以失败是因为所需要的元素在不同的空闲链表中是不可接受的. */ if (!element_alloc(hashp, hctl->nelem_alloc, freelist_idx)) { //本空闲链表不能分配内存 int borrow_from_idx; if (!IS_PARTITIONED(hctl)) //非分区哈希表,返回NULL,意味着内存溢出了. return NULL; /* out of memory */ /* try to borrow element from another freelist */ //尝试从其他空闲链表浏览元素 borrow_from_idx = freelist_idx; for (;;) { //------- 开始遍历其他空闲链表 borrow_from_idx = (borrow_from_idx + 1) % NUM_FREELISTS; if (borrow_from_idx == freelist_idx) //已经完成整个空闲链表的遍历,退出 break; /* examined all freelists, fail */ //获取自旋锁 SpinLockAcquire(&(hctl->freeList[borrow_from_idx].mutex)); newElement = hctl->freeList[borrow_from_idx].freeList; if (newElement != NULL) { hctl->freeList[borrow_from_idx].freeList = newElement->link; SpinLockRelease(&(hctl->freeList[borrow_from_idx].mutex)); /* careful: count the new element in its proper freelist */ //小心:在合适的空闲链表上统计新的元素 SpinLockAcquire(&hctl->freeList[freelist_idx].mutex); hctl->freeList[freelist_idx].nentries++; SpinLockRelease(&hctl->freeList[freelist_idx].mutex); return newElement; } SpinLockRelease(&(hctl->freeList[borrow_from_idx].mutex)); } /* no elements available to borrow either, so out of memory */ //已无可用空间,内存溢出 return NULL; } } /* remove entry from freelist, bump nentries */ //从空闲链表中移除条目,nentries+1 hctl->freeList[freelist_idx].freeList = newElement->link; hctl->freeList[freelist_idx].nentries++; if (IS_PARTITIONED(hctl)) SpinLockRelease(&hctl->freeList[freelist_idx].mutex); return newElement;}二、跟踪分析
跟踪SetupLockInTable,进入hash_search_with_hash_value
(gdb) b SetupLockInTable if lockmode == 8Breakpoint 2 at 0x8ccf4e: file lock.c, line 1131.(gdb) cContinuing.Breakpoint 2, SetupLockInTable (lockMethodTable=0xc8dba0, proc=0x7f293e800b70, locktag=0x7fff167a9250, hashcode=1823181291, lockmode=8) at lock.c:11311131 lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,(gdb) stephash_search_with_hash_value (hashp=0x1210160, keyPtr=0x7fff167a9250, hashvalue=1823181291, action=HASH_ENTER_NULL, foundPtr=0x7fff167a90bf) at dynahash.c:925925 HASHHDR *hctl = hashp->hctl;
查看HTAB(hashp)和HASHHDR(hctl)
(gdb) n926 int freelist_idx = FREELIST_IDX(hctl, hashvalue);(gdb) p *hashp$8 = {hctl = 0x7f293e443980, dir = 0x7f293e443cd8, hash = 0xa79ac6 , match = 0x47cb70 , keycopy = 0x47d0a0 , alloc = 0x8c3419 , hcxt = 0x0, tabname = 0x12101c0 "LOCK hash", isshared = true, isfixed = false, frozen = false, keysize = 16, ssize = 256, sshift = 8}(gdb) p *hctl$9 = {freeList = {{mutex = 0 '\000', nentries = 389, freeList = 0x0}, {mutex = 0 '\000', nentries = 392, freeList = 0x0}, {mutex = 0 '\000', nentries = 400, freeList = 0x0}, {mutex = 0 '\000', nentries = 382, freeList = 0x7f293ebd1b00}, {mutex = 0 '\000', nentries = 439, freeList = 0x7f293ebc89a0}, { mutex = 0 '\000', nentries = 391, freeList = 0x7f293ebc1b20}, {mutex = 0 '\000', nentries = 411, freeList = 0x7f293eb91680}, {mutex = 0 '\000', nentries = 395, freeList = 0x0}, {mutex = 0 '\000', nentries = 402, freeList = 0x0}, {mutex = 0 '\000', nentries = 416, freeList = 0x7f293ebcb338}, { mutex = 0 '\000', nentries = 431, freeList = 0x7f293ebc3170}, {mutex = 0 '\000', nentries = 421, freeList = 0x0}, {mutex = 0 '\000', nentries = 406, freeList = 0x7f293eb995a8}, {mutex = 0 '\000', nentries = 409, freeList = 0x7f293ebd2238}, {mutex = 0 '\000', nentries = 411, freeList = 0x7f293ebd1f98}, {mutex = 0 '\000', nentries = 386, freeList = 0x0}, {mutex = 0 '\000', nentries = 412, freeList = 0x0}, { mutex = 0 '\000', nentries = 424, freeList = 0x0}, {mutex = 0 '\000', nentries = 394, freeList = 0x7f293ebd1da0}, {mutex = 0 '\000', nentries = 401, freeList = 0x0}, {mutex = 0 '\000', nentries = 408, freeList = 0x7f293eb99500}, {mutex = 0 '\000', nentries = 437, freeList = 0x0}, { mutex = 0 '\000', nentries = 429, freeList = 0x7f293ebd2778}, {mutex = 0 '\000', nentries = 386, freeList = 0x0}, {mutex = 0 '\000', nentries = 410, freeList = 0x7f293ebd2d60}, {mutex = 0 '\000', nentries = 416, freeList = 0x0}, {mutex = 0 '\000', nentries = 412, freeList = 0x7f293ebd1c50}, { mutex = 0 '\000', nentries = 436, freeList = 0x7f293ebd1ba8}, {mutex = 0 '\000', nentries = 380, freeList = 0x7f293ebd1cf8}, {mutex = 0 '\000', nentries = 428, freeList = 0x0}, {mutex = 0 '\000', nentries = 405, freeList = 0x0}, {mutex = 0 '\000', nentries = 372, freeList = 0x0}}, dsize = 256, nsegs = 16, max_bucket = 4095, high_mask = 8191, low_mask = 4095, keysize = 16, entrysize = 152, num_partitions = 16, ffactor = 1, max_dsize = 256, ssize = 256, sshift = 8, nelem_alloc = 48} 可以看到,hctl中的freelist数组,数组中每个元素的freeList,如不为0x0(NULL),则说明还有空闲空间,否则说明已无空间.
(gdb) n949 if (action == HASH_ENTER || action == HASH_ENTER_NULL)(gdb) p freelist_idx$10 = 11(gdb) p hctl->freeList[11]$11 = {mutex = 0 '\000', nentries = 421, freeList = 0x0}(gdb) n956 if (!IS_PARTITIONED(hctl) && !hashp->frozen &&(gdb) 965 bucket = calc_bucket(hctl, hashvalue); --> hash桶(gdb) 967 segment_num = bucket >> hashp->sshift; --> 根据hash桶获取段(gdb) 968 segment_ndx = MOD(bucket, hashp->ssize);--> 根据hash桶获取段内偏移(gdb) 970 segp = hashp->dir[segment_num];--> 获取hash段指针(gdb) 972 if (segp == NULL)(gdb) p bucket$12 = 2539(gdb) p segment_num$13 = 9(gdb) p segment_ndx$14 = 235(gdb) p *segp$15 = (HASHBUCKET) 0x7f293e44de98(gdb) p **segp$16 = {link = 0x0, hashvalue = 3817199872}(gdb) n975 prevBucketPtr = &segp[segment_ndx]; --> HASHBUCKET指针的指针(gdb) 976 currBucket = *prevBucketPtr; --> HASHBUCKET指针(gdb) 981 match = hashp->match; /* save one fetch in inner loop */(gdb) 982 keysize = hashp->keysize; /* ditto */(gdb) p match$17 = (HashCompareFunc) 0x47cb70 --> hash函数(gdb) n984 while (currBucket != NULL) --> 沿着碰撞链循环获取hash桶(gdb) 986 if (currBucket->hashvalue == hashvalue && --> 退出条件:找到匹配的元素(gdb) 989 prevBucketPtr = &(currBucket->link);(gdb) 990 currBucket = *prevBucketPtr;(gdb) 984 while (currBucket != NULL) --> 退出条件:hash桶指针为NULL,没有找到元素(gdb) 997 if (foundPtr)(gdb) p foundPtr$18 = (_Bool *) 0x7fff167a90bf(gdb) n998 *foundPtr = (bool) (currBucket != NULL);(gdb) 1003 switch (action)(gdb) 1042 Assert(hashp->alloc != DynaHashAlloc);(gdb) 1047 if (currBucket != NULL)(gdb) 1051 if (hashp->frozen)(gdb) 1055 currBucket = get_hash_entry(hashp, freelist_idx);(gdb) stepget_hash_entry (hashp=0x1210160, freelist_idx=11) at dynahash.c:12521252 HASHHDR *hctl = hashp->hctl;(gdb) n注 : #define IS_PARTITIONED(hctl) ((hctl)->num_partitions != 0)1258 if (IS_PARTITIONED(hctl))(gdb) p *hctl$19 = {freeList = {{mutex = 0 '\000', nentries = 389, freeList = 0x0}, {mutex = 0 '\000', nentries = 392, freeList = 0x0}, {mutex = 0 '\000', nentries = 400, freeList = 0x0}, {mutex = 0 '\000', nentries = 382, freeList = 0x7f293ebd1b00}, {mutex = 0 '\000', nentries = 439, freeList = 0x7f293ebc89a0}, { mutex = 0 '\000', nentries = 391, freeList = 0x7f293ebc1b20}, {mutex = 0 '\000', nentries = 411, freeList = 0x7f293eb91680}, {mutex = 0 '\000', nentries = 395, freeList = 0x0}, {mutex = 0 '\000', nentries = 402, freeList = 0x0}, {mutex = 0 '\000', nentries = 416, freeList = 0x7f293ebcb338}, { mutex = 0 '\000', nentries = 431, freeList = 0x7f293ebc3170}, {mutex = 0 '\000', nentries = 421, freeList = 0x0}, {mutex = 0 '\000', nentries = 406, freeList = 0x7f293eb995a8}, {mutex = 0 '\000', nentries = 409, freeList = 0x7f293ebd2238}, {mutex = 0 '\000', nentries = 411, freeList = 0x7f293ebd1f98}, {mutex = 0 '\000', nentries = 386, freeList = 0x0}, {mutex = 0 '\000', nentries = 412, freeList = 0x0}, { mutex = 0 '\000', nentries = 424, freeList = 0x0}, {mutex = 0 '\000', nentries = 394, freeList = 0x7f293ebd1da0}, {mutex = 0 '\000', nentries = 401, freeList = 0x0}, {mutex = 0 '\000', nentries = 408, freeList = 0x7f293eb99500}, {mutex = 0 '\000', nentries = 437, freeList = 0x0}, { mutex = 0 '\000', nentries = 429, freeList = 0x7f293ebd2778}, {mutex = 0 '\000', nentries = 386, freeList = 0x0}, {mutex = 0 '\000', nentries = 410, freeList = 0x7f293ebd2d60}, {mutex = 0 '\000', nentries = 416, freeList = 0x0}, {mutex = 0 '\000', nentries = 412, freeList = 0x7f293ebd1c50}, { mutex = 0 '\000', nentries = 436, freeList = 0x7f293ebd1ba8}, {mutex = 0 '\000', nentries = 380, freeList = 0x7f293ebd1cf8}, {mutex = 0 '\000', nentries = 428, freeList = 0x0}, {mutex = 0 '\000', nentries = 405, freeList = 0x0}, {mutex = 0 '\000', nentries = 372, freeList = 0x0}}, dsize = 256, nsegs = 16, max_bucket = 4095, high_mask = 8191, low_mask = 4095, keysize = 16, entrysize = 152, num_partitions = 16, ffactor = 1, max_dsize = 256, ssize = 256, sshift = 8, nelem_alloc = 48}(gdb) n1259 SpinLockAcquire(&hctl->freeList[freelist_idx].mutex);(gdb) 1262 newElement = hctl->freeList[freelist_idx].freeList; --> 尝试从空闲链表中获取新元素(gdb) 1264 if (newElement != NULL) --> 不为NULL,则返回,否则,尝试扩展(gdb) p newElement$20 = (HASHBUCKET) 0x0(gdb) n1267 if (IS_PARTITIONED(hctl))(gdb) 1268 SpinLockRelease(&hctl->freeList[freelist_idx].mutex);(gdb) 1282 if (!element_alloc(hashp, hctl->nelem_alloc, freelist_idx)) --> 扩展(gdb) stepelement_alloc (hashp=0x1210160, nelem=48, freelist_idx=11) at dynahash.c:1659 --> 进入element_alloc1659 HASHHDR *hctl = hashp->hctl;(gdb) n1666 if (hashp->isfixed)(gdb) 1670 elementSize = MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(hctl->entrysize); --> 确保地址对齐(gdb) 1672 CurrentDynaHashCxt = hashp->hcxt;(gdb) p elementSize$21 = 168(gdb) n1673 firstElement = (HASHELEMENT *) hashp->alloc(nelem * elementSize); --> 分配空间(gdb) 1675 if (!firstElement)(gdb) p firstElement$22 = (HASHELEMENT *) 0x0(gdb) p nelem * elementSize$23 = 8064(gdb) n1676 return false;--> 扩展失败,返回false(gdb) 1700 }(gdb) get_hash_entry (hashp=0x1210160, freelist_idx=11) at dynahash.c:12861286 if (!IS_PARTITIONED(hctl))(gdb) 1290 borrow_from_idx = freelist_idx; --> 该空闲链表无法扩展,寻找下一个空闲链表(gdb) 1293 borrow_from_idx = (borrow_from_idx + 1) % NUM_FREELISTS; --> 简单的+1后取模(gdb) p freelist_idx$24 = 11(gdb) n1294 if (borrow_from_idx == freelist_idx) --> 找了一圈,回到原点,内存不足,这时候会报错(gdb) p NUM_FREELISTS$25 = 32(gdb) p borrow_from_idx$26 = 12(gdb) n1297 SpinLockAcquire(&(hctl->freeList[borrow_from_idx].mutex));(gdb) 1298 newElement = hctl->freeList[borrow_from_idx].freeList;(gdb) 1300 if (newElement != NULL)(gdb) 1302 hctl->freeList[borrow_from_idx].freeList = newElement->link;(gdb) 1303 SpinLockRelease(&(hctl->freeList[borrow_from_idx].mutex));(gdb) 1306 SpinLockAcquire(&hctl->freeList[freelist_idx].mutex);(gdb) 1307 hctl->freeList[freelist_idx].nentries++;(gdb) 1308 SpinLockRelease(&hctl->freeList[freelist_idx].mutex);(gdb) p newElement$27 = (HASHBUCKET) 0x7f293eb995a8(gdb) n1310 return newElement; --> 找到了空闲元素,返回(gdb) 1329 }(gdb) hash_search_with_hash_value (hashp=0x1210160, keyPtr=0x7fff167a9250, hashvalue=1823181291, action=HASH_ENTER_NULL, foundPtr=0x7fff167a90bf) at dynahash.c:10561056 if (currBucket == NULL)(gdb) 1073 *prevBucketPtr = currBucket;(gdb) 1074 currBucket->link = NULL;(gdb) 1077 currBucket->hashvalue = hashvalue;(gdb) 1078 hashp->keycopy(ELEMENTKEY(currBucket), keyPtr, keysize);(gdb) 1087 return (void *) ELEMENTKEY(currBucket);(gdb) 1093 }(gdb) SetupLockInTable (lockMethodTable=0xc8dba0 , proc=0x7f293e800b70, locktag=0x7fff167a9250, hashcode=1823181291, lockmode=8) at lock.c:11361136 if (!lock)(gdb) 1142 if (!found)(gdb) 1144 lock->grantMask = 0;(gdb) 1145 lock->waitMask = 0;(gdb) 1146 SHMQueueInit(&(lock->procLocks));(gdb) 1147 ProcQueueInit(&(lock->waitProcs));(gdb) 1148 lock->nRequested = 0;(gdb) 1149 lock->nGranted = 0;(gdb) 1150 MemSet(lock->requested, 0, sizeof(int) * MAX_LOCKMODES);(gdb) 1151 MemSet(lock->granted, 0, sizeof(int) * MAX_LOCKMODES);(gdb) 1165 proclocktag.myLock = lock;(gdb) 1166 proclocktag.myProc = proc;(gdb) 1168 proclock_hashcode = ProcLockHashCode(&proclocktag, hashcode);(gdb) 1173 proclock = (PROCLOCK *) hash_search_with_hash_value(LockMethodProcLockHash,(gdb) 1178 if (!proclock)(gdb) p proclock$28 = (PROCLOCK *) 0x7f293ebc6ec0(gdb) n1203 if (!found)(gdb) 1205 uint32 partition = LockHashPartition(hashcode);(gdb) 1217 proclock->groupLeader = proc->lockGroupLeader != NULL ?(gdb) 1218 proc->lockGroupLeader : proc;(gdb) 1217 proclock->groupLeader = proc->lockGroupLeader != NULL ?(gdb) 1219 proclock->holdMask = 0;(gdb) 1220 proclock->releaseMask = 0;(gdb) 1222 SHMQueueInsertBefore(&lock->procLocks, &proclock->lockLink);(gdb) 1223 SHMQueueInsertBefore(&(proc->myProcLocks[partition]),(gdb) 1275 lock->nRequested++;(gdb) 1276 lock->requested[lockmode]++;(gdb) 1277 Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0));(gdb) 1283 if (proclock->holdMask & LOCKBIT_ON(lockmode))(gdb) 1289 return proclock;(gdb) 1290 }(gdb) LockAcquireExtended (locktag=0x7fff167a9250, lockmode=8, sessionLock=false, dontWait=false, reportMemoryError=true, locallockp=0x7fff167a9248) at lock.c:956956 if (!proclock)(gdb) cContinuing. 到此,关于"分析PostgreSQL SetupLockInTable方法中与OOM相关的代码"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!
哈希
空闲
条目
元素
内存
函数
大小
分配
结构
数组
个数
信息
数据
用者
代码
方法
分析
指针
空间
尝试
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
产品数据库软件
金山区制造软件开发项目信息
100万用户网络安全审查
读秀学术资源数据库
湖北省网络安全协会
网络安全攻防演
诛仙手游新服务器
hp服务器配置管理账号密码
el和数据库同步
网络安全技术试题第三套
苹果手机为什么要连接服务器
主要包括网络安全继电保护等专业
福州新华互联网科技在哪里
南宁警察学院网络安全
杭州软件开发工程师招聘
苹果6允许微信使用数据库
太仓电子网络技术哪个好
服务器路由配置
邵阳游戏软件开发价格
成立软件开发公司
河北钦动网络技术有限公司
太湖家园网 网络安全
临安游戏软件开发
数据库 如何表示月日年
面向对象数据库技术是什么
网络安全8开手抄报简单又漂亮
北京软件开发 外包公司
数据库实例恢复的起点和终点
湖南潮流软件开发参考价格
电子政务的软件开发要求