Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the function of StrategyGetBuffer function in PostgreSQL

2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

Shulou(Shulou.com)05/31 Report--

This article introduces the relevant knowledge of "what is the role of StrategyGetBuffer function in PostgreSQL". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

I. data structure

BufferDesc

Shared descriptor (status) data for shared buffer

/ * * Flags for buffer descriptors * buffer descriptor tag * * Note: TAG_VALID essentially means that there is a buffer hashtable * entry associated with the buffer's tag. * Note: TAG_VALID essentially means that there is a buffer hash table entry associated with the token of the buffer. * / buffer header locks # define BM_LOCKED (1U bgwprocno =-1; / * * Not acquiring ProcArrayLock here which is slightly icky. It's * actually fine because procLatch isn't ever freed, so we just can * potentially set the wrong process' (or no process') latch. * there is no need to request an "annoying" ProcArrayLock here. * because procLatch has never been released, there is actually no problem, * so we may set the wrong process (or no process) latch. * / SetLatch (& ProcGlobal- > allProcs [bgwprocno] .procLatch);} / * * We count buffer allocation requests so that the bgwriter can estimate * the rate of buffer consumption. Note that buffers recycled by a * strategy object are intentionally not counted here. * calculate buffer allocation requests so that bgwriter can estimate the proportion of buffer consumption. * Note that buffer recycling through policy objects is not calculated here. * / pg_atomic_fetch_add_u32 (& StrategyControl- > numBufferAllocs, 1); / * First check, without acquiring the lock, whether there's buffers in the * freelist. Since we otherwise don't require the spinlock in every * StrategyGetBuffer () invocation, it'd be sad to acquire it here-* uselessly in most cases. That obviously leaves a race where a buffer is * put on the freelist but we don't see the store yet-but that's pretty * harmless, it'll just get used during the next buffer acquisition. * No request lock is required. Check for the existence of buffer in freelist for the first time. * because we don't need to use a spin lock every time we call StrategyGetBuffer (), * it's a bit frustrating to request a spin lock here-- because it's useless in most cases. * there is obviously a competition in which the buffer is placed in the free list, but the process does not see the storage *-but this is harmless and used during the next buffer application. * If there's buffers on the freelist, acquire the spinlock to pop one * buffer of the freelist. Then check whether that buffer is usable and * repeat if not. * if a buffer exists in the free list, request a spin lock and pop up an available buffer from the free list. * then check if the buffer is available, and if not, continue processing. * * Note that the freeNext fields are considered to be protected by the * buffer_strategy_lock not the individual buffer spinlocks, so it's OK to * manipulate them without holding the spinlock. * Note that freeNext fields are protected by buffer_strategy_lock locks instead of independent buffer spin locks, * so you don't need to hold spin locks to maintain these fields. * / if (StrategyControl- > firstFreeBuffer > = 0) {while (true) {/ * Acquire the spinlock to remove element from the freelist * / / request spin lock, delete the element SpinLockAcquire (& StrategyControl- > buffer_strategy_lock) in the free list; if (StrategyControl- > firstFreeBuffer)

< 0) { //如无空闲空间,则马上跳出循环 SpinLockRelease(&StrategyControl->

Buffer_strategy_lock); break;} / / get buffer descriptor buf = GetBufferDescriptor (StrategyControl- > firstFreeBuffer); Assert (buf- > freeNext! = FREENEXT_NOT_IN_LIST); / * Unconditionally remove buffer from freelist * / / unconditionally clear buffer StrategyControl- > firstFreeBuffer = buf- > freeNext in the free list Buf- > freeNext = FREENEXT_NOT_IN_LIST; / * * Release the lock so someone else can access the freelist while * we check out this buffer. * release the lock so that other processes can access the free linked list * / SpinLockRelease (& StrategyControl- > buffer_strategy_lock) when we check the buffer; / * If the buffer is pinned or has a nonzero usage_count, we cannot * use it; discard it and retry. (This can only happen if VACUUM * put a valid buffer in the freelist and then someone else used * it before we got to it. It's probably impossible altogether as * of 8.3, but we'd better check anyway.) * if the buffer pinned or usage_count is not 0, the buffer cannot be used, discard and try again. This happens when VACUUM puts a valid buffer in the free linked list, and other processes get the buffer in advance. * it is completely impossible in 8.3, but it is best to perform this check) * / / Lock the buffer header local_buf_state = LockBufHdr (buf) If (BUF_STATE_GET_REFCOUNT (local_buf_state) = = 0 & & BUF_STATE_GET_USAGECOUNT (local_buf_state) = = 0) {/ / refcount = = 0 & & usagecount = = 0 if (strategy! = NULL) / / is not the default policy, then AddBufferToRing (strategy) is added to the ring buffer Buf) / / set the output parameter * buf_state = local_buf_state; / / return buf return buf;} / / does not meet the condition, unlock buffer header UnlockBufHdr (buf, local_buf_state) }} / * Nothing on the freelist, so run the "clock sweep" algorithm * / / if the condition is not found or cannot be satisfied in the free linked list, execute the "clock sweep" algorithm / / int NBuffers = 1000; trycounter = number of NBuffers;// attempts for (;;) {/ /-Loop / / get the buffer descriptor buf = GetBufferDescriptor (ClockSweepTick ()) / * If the buffer is pinned or has a nonzero usage_count, we cannot use * it; decrement the usage_count (unless pinned) and keep scanning. * if the buffer is already pinned, or if you have a non-zero value usage_count, you cannot use this buffer. * reduce usage_count (unless already pinned) and continue scanning. * / local_buf_state = LockBufHdr (buf) If (BUF_STATE_GET_REFCOUNT (local_buf_state) = = 0) {/ /-refcount = = 0 if (BUF_STATE_GET_USAGECOUNT (local_buf_state)! = 0) {/ / usage_count 0 / / usage_count-1 local_buf_state-= BUF_USAGECOUNT_ONE / / reset attempts trycounter = NBuffers } else {/ / usage_count = 0 / * Found a usable buffer * / / found an available buffer if (strategy! = NULL) / / added to the ring buffer of the policy AddBufferToRing (strategy, buf) / / output parameter assignment * buf_state = local_buf_state; / / returns buf return buf }} else if (--trycounter = = 0) {/ /-refcount 0 & &-- trycounter = = 0 / * * We've scanned all the buffers without making any state changes, * so all the buffers are pinned (or were when we looked at them). * We could hope that someone will free one eventually, but it's * probably better to fail than to risk getting stuck in an * infinite loop. * We have finished traversing all buffers without changing any state, * so all buffers have been pinned (or pinned during search). * We hope that some processes will release buffer periodically, but if they don't get it, it's better to report a mistake than a silly endless cycle. * / UnlockBufHdr (buf, local_buf_state); elog (ERROR, "no unpinned buffers available");} / unlock buffer header UnlockBufHdr (buf, local_buf_state);}} III. Tracking analysis

Test script, query data table:

10:01:54 (xdb@ [local]: 5432) testdb=# select * from T1 limit 10

Start gdb and set breakpoint

(gdb) Continuing.Breakpoint 1, StrategyGetBuffer (strategy=0x0, buf_state=0x7ffcc97fb4ec) at freelist.c:212212 if (strategy! = NULL) (gdb)

Input parameters

Strategy=NULL, policy object, use default policy

(gdb) p * buf_state$1 = 0

1. Initialize related variables

two。 If the policy object is not empty, get buffer from the ring buffer, and return buf if successful

3. If necessary, wake up the background process bgwriter, read it from shared memory once, and then set latch according to this value

(gdb) n231 bgwprocno = INT_ACCESS_ONCE (StrategyControl- > bgwprocno); (gdb) 232 if (bgwprocno! =-1) (gdb) 235 StrategyControl- > bgwprocno =-1 (gdb) p bgwprocno$2 = 112 (gdb) p StrategyControl$3 = (BufferStrategyControl *) 0x7f8607b21700 (gdb) p * StrategyControl$4 = {buffer_strategy_lock = 0'\ 000mm, nextVictimBuffer = {value = 0}, firstFreeBuffer = 134, lastFreeBuffer = 65535, completePasses = 0, numBufferAllocs = {value = 0}, bgwprocno = 112} (gdb) n242 SetLatch (& ProcGlobal- > allProcs [bgwprocno] .proclatch); (gdb)

4. Calculate buffer allocation requests so that bgwriter can estimate the percentage of buffer consumption.

(gdb) 250pg_atomic_fetch_add_u32 (& StrategyControl- > numBufferAllocs, 1)

5. Check to see if buffer exists in freelist

(gdb) 268 if (StrategyControl- > firstFreeBuffer > = 0)

5.1 execute the relevant judgment logic if it exists, and return buf if successful

(gdb) n273 SpinLockAcquire (& StrategyControl- > buffer_strategy_lock); (gdb) 275 if (StrategyControl- > firstFreeBuffer)

< 0)(gdb) 281 buf = GetBufferDescriptor(StrategyControl->

FirstFreeBuffer); (gdb) 282 Assert (buf- > freeNext! = FREENEXT_NOT_IN_LIST) (gdb) p * buf$5 = {tag = {rnode = {spcNode = 0, dbNode = 0, relNode = 0}, forkNum = InvalidForkNumber, blockNum = 4294967295}, buf_id = 134, state = {value = 0}, wait_backend_pid = 0, freeNext = 135, content_lock = {tranche = 54, state = {value = 536870912}, waiters = {head = 2147483647, tail = 2147483647} (gdb) n285 StrategyControl- > firstFreeBuffer = buf- > freeNext (gdb) 286 buf- > freeNext = FREENEXT_NOT_IN_LIST; (gdb) 292 SpinLockRelease (& StrategyControl- > buffer_strategy_lock); (gdb) 301 local_buf_state = LockBufHdr (buf) (gdb) 302 if (BUF_STATE_GET_REFCOUNT (local_buf_state) = = 0 (gdb) 303 & & BUF_STATE_GET_USAGECOUNT (local_buf_state) = = 0) (gdb) 305 if (strategy! = NULL) (gdb) 307 * buf_state = local_buf_state; (gdb) 308 return buf (gdb) p * buf_state$6 = 4194304 (gdb) p * buf$7 = {tag = {rnode = {spcNode = 0, dbNode = 0, relNode = 0}, forkNum = InvalidForkNumber, blockNum = 4294967295}, buf_id = 134,134, state = {value = 4194304}, wait_backend_pid = 0, freeNext =-2, content_lock = {tranche = 54, state = {value = 536870912}, waiters = {head = 2147483647, tail = 2147483647}} (gdb)

Return the result, go back to BufferAlloc

(gdb) n358} (gdb) BufferAlloc (smgr=0x22a38a0, relpersistence=112 'paired, forkNum=MAIN_FORKNUM, blockNum=0, strategy=0x0, foundPtr=0x7ffcc97fb5c3) at bufmgr.c:10731073 Assert (BUF_STATE_GET_REFCOUNT (buf_state) = = 0); (gdb) "what is the function of StrategyGetBuffer function in PostgreSQL" is introduced here, thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Database

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report