PostgreSQL Source Code git master
Loading...
Searching...
No Matches
localbuf.c File Reference
#include "postgres.h"
#include "access/parallel.h"
#include "executor/instrument.h"
#include "pgstat.h"
#include "storage/aio.h"
#include "storage/buf_internals.h"
#include "storage/bufmgr.h"
#include "storage/fd.h"
#include "utils/guc_hooks.h"
#include "utils/memdebug.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/resowner.h"
Include dependency graph for localbuf.c:

Go to the source code of this file.

Data Structures

struct  LocalBufferLookupEnt
 

Macros

#define LocalBufHdrGetBlock(bufHdr)    LocalBufferBlockPointers[-((bufHdr)->buf_id + 2)]
 

Functions

static void InitLocalBuffers (void)
 
static Block GetLocalBufferStorage (void)
 
static Buffer GetLocalVictimBuffer (void)
 
PrefetchBufferResult PrefetchLocalBuffer (SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum)
 
BufferDescLocalBufferAlloc (SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, bool *foundPtr)
 
void FlushLocalBuffer (BufferDesc *bufHdr, SMgrRelation reln)
 
uint32 GetLocalPinLimit (void)
 
uint32 GetAdditionalLocalPinLimit (void)
 
void LimitAdditionalLocalPins (uint32 *additional_pins)
 
BlockNumber ExtendBufferedRelLocal (BufferManagerRelation bmr, ForkNumber fork, uint32 flags, uint32 extend_by, BlockNumber extend_upto, Buffer *buffers, uint32 *extended_by)
 
void MarkLocalBufferDirty (Buffer buffer)
 
StartBufferIOResult StartLocalBufferIO (BufferDesc *bufHdr, bool forInput, bool wait, PgAioWaitRef *io_wref)
 
void TerminateLocalBufferIO (BufferDesc *bufHdr, bool clear_dirty, uint64 set_flag_bits, bool release_aio)
 
void InvalidateLocalBuffer (BufferDesc *bufHdr, bool check_unreferenced)
 
void DropRelationLocalBuffers (RelFileLocator rlocator, ForkNumber *forkNum, int nforks, BlockNumber *firstDelBlock)
 
void DropRelationAllLocalBuffers (RelFileLocator rlocator)
 
bool PinLocalBuffer (BufferDesc *buf_hdr, bool adjust_usagecount)
 
void UnpinLocalBuffer (Buffer buffer)
 
void UnpinLocalBufferNoOwner (Buffer buffer)
 
bool check_temp_buffers (int *newval, void **extra, GucSource source)
 
static void CheckForLocalBufferLeaks (void)
 
void AtEOXact_LocalBuffers (bool isCommit)
 
void AtProcExit_LocalBuffers (void)
 

Variables

int NLocBuffer = 0
 
BufferDescLocalBufferDescriptors = NULL
 
BlockLocalBufferBlockPointers = NULL
 
int32LocalRefCount = NULL
 
static int nextFreeLocalBufId = 0
 
static HTABLocalBufHash = NULL
 
static int NLocalPinnedBuffers = 0
 

Macro Definition Documentation

◆ LocalBufHdrGetBlock

#define LocalBufHdrGetBlock (   bufHdr)     LocalBufferBlockPointers[-((bufHdr)->buf_id + 2)]

Definition at line 42 of file localbuf.c.

73{
75 BufferTag newTag; /* identity of requested block */
77
78 InitBufferTag(&newTag, &smgr->smgr_rlocator.locator, forkNum, blockNum);
79
80 /* Initialize local buffers if first request in this session */
81 if (LocalBufHash == NULL)
83
84 /* See if the desired buffer already exists */
87
88 if (hresult)
89 {
90 /* Yes, so nothing to do */
91 result.recent_buffer = -hresult->id - 1;
92 }
93 else
94 {
95#ifdef USE_PREFETCH
96 /* Not in buffers, so initiate prefetch */
97 if ((io_direct_flags & IO_DIRECT_DATA) == 0 &&
98 smgrprefetch(smgr, forkNum, blockNum, 1))
99 {
100 result.initiated_io = true;
101 }
102#endif /* USE_PREFETCH */
103 }
104
105 return result;
106}
107
108
109/*
110 * LocalBufferAlloc -
111 * Find or create a local buffer for the given page of the given relation.
112 *
113 * API is similar to bufmgr.c's BufferAlloc, except that we do not need to do
114 * any locking since this is all local. We support only default access
115 * strategy (hence, usage_count is always advanced).
116 */
119 bool *foundPtr)
120{
121 BufferTag newTag; /* identity of requested block */
125 int bufid;
126 bool found;
127
128 InitBufferTag(&newTag, &smgr->smgr_rlocator.locator, forkNum, blockNum);
129
130 /* Initialize local buffers if first request in this session */
131 if (LocalBufHash == NULL)
133
135
136 /* See if the desired buffer already exists */
139
140 if (hresult)
141 {
142 bufid = hresult->id;
145
147 }
148 else
149 {
151
153 bufid = -victim_buffer - 1;
155
158 if (found) /* shouldn't happen */
159 elog(ERROR, "local buffer hash table corrupted");
160 hresult->id = bufid;
161
162 /*
163 * it's all ours now.
164 */
165 bufHdr->tag = newTag;
166
171
172 *foundPtr = false;
173 }
174
175 return bufHdr;
176}
177
178/*
179 * Like FlushBuffer(), just for local buffers.
180 */
181void
183{
186
188
189 /*
190 * Try to start an I/O operation. There currently are no reasons for
191 * StartLocalBufferIO to return anything other than
192 * BUFFER_IO_READY_FOR_IO, so we raise an error in that case.
193 */
195 elog(ERROR, "failed to start write IO on local buffer");
196
197 /* Find smgr relation for buffer */
198 if (reln == NULL)
201
202 PageSetChecksum(localpage, bufHdr->tag.blockNum);
203
205
206 /* And write... */
209 bufHdr->tag.blockNum,
210 localpage,
211 false);
212
213 /* Temporary table I/O does not use Buffer Access Strategies */
216
217 /* Mark not-dirty */
218 TerminateLocalBufferIO(bufHdr, true, 0, false);
219
221}
222
223static Buffer
225{
226 int victim_bufid;
227 int trycounter;
229
231
232 /*
233 * Need to get a new buffer. We use a clock-sweep algorithm (essentially
234 * the same as what freelist.c does now...)
235 */
237 for (;;)
238 {
240
243
245
246 if (LocalRefCount[victim_bufid] == 0)
247 {
249
251 {
255 }
256 else if (BUF_STATE_GET_REFCOUNT(buf_state) > 0)
257 {
258 /*
259 * This can be reached if the backend initiated AIO for this
260 * buffer and then errored out.
261 */
262 }
263 else
264 {
265 /* Found a usable buffer */
266 PinLocalBuffer(bufHdr, false);
267 break;
268 }
269 }
270 else if (--trycounter == 0)
273 errmsg("no empty local buffer available")));
274 }
275
276 /*
277 * lazy memory allocation: allocate space on first use of a buffer.
278 */
280 {
281 /* Set pointer for use by BufferGetBlock() macro */
283 }
284
285 /*
286 * this buffer is not referenced but it might still be dirty. if that's
287 * the case, write it out before reusing it!
288 */
289 if (pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY)
291
292 /*
293 * Remove the victim buffer from the hashtable and mark as invalid.
294 */
296 {
298
300 }
301
303}
304
305/* see GetPinLimit() */
306uint32
308{
309 /*
310 * Every backend has its own temporary buffers, but we leave headroom for
311 * concurrent pin-holders -- like multiple scans in the same query.
312 */
313 return num_temp_buffers / 4;
314}
315
316/* see GetAdditionalPinLimit() */
317uint32
319{
320 uint32 total = GetLocalPinLimit();
321
323
324 if (NLocalPinnedBuffers >= total)
325 return 0;
326 return total - NLocalPinnedBuffers;
327}
328
329/* see LimitAdditionalPins() */
330void
332{
334
335 if (*additional_pins <= 1)
336 return;
337
338 /*
339 * In contrast to LimitAdditionalPins() other backends don't play a role
340 * here. We can allow up to NLocBuffer pins in total, but it might not be
341 * initialized yet so read num_temp_buffers.
342 */
344
347}
348
349/*
350 * Implementation of ExtendBufferedRelBy() and ExtendBufferedRelTo() for
351 * temporary buffers.
352 */
356 uint32 flags,
359 Buffer *buffers,
361{
364
365 /* Initialize local buffers if first request in this session */
366 if (LocalBufHash == NULL)
368
370
371 for (uint32 i = 0; i < extend_by; i++)
372 {
375
376 buffers[i] = GetLocalVictimBuffer();
377 buf_hdr = GetLocalBufferDescriptor(-buffers[i] - 1);
379
380 /* new buffers are zero-filled */
382 }
383
385
387 {
388 /*
389 * In contrast to shared relations, nothing could change the relation
390 * size concurrently. Thus we shouldn't end up finding that we don't
391 * need to do anything.
392 */
394
396 }
397
398 /* Fail if relation is already at maximum possible length */
402 errmsg("cannot extend relation %s beyond %u blocks",
403 relpath(BMR_GET_SMGR(bmr)->smgr_rlocator, fork).str,
405
406 for (uint32 i = 0; i < extend_by; i++)
407 {
408 int victim_buf_id;
410 BufferTag tag;
412 bool found;
413
414 victim_buf_id = -buffers[i] - 1;
416
417 /* in case we need to pin an existing buffer below */
419
420 InitBufferTag(&tag, &BMR_GET_SMGR(bmr)->smgr_rlocator.locator, fork,
421 first_block + i);
422
424 hash_search(LocalBufHash, &tag, HASH_ENTER, &found);
425 if (found)
426 {
429
431
435
436 /*
437 * Clear the BM_VALID bit, do StartLocalBufferIO() and proceed.
438 */
444
445 /* no need to loop for local buffers */
447 }
448 else
449 {
451
453
454 victim_buf_hdr->tag = tag;
455
457
459
461
463 }
464 }
465
467
468 /* actually extend relation */
470
473
474 for (uint32 i = 0; i < extend_by; i++)
475 {
476 Buffer buf = buffers[i];
479
481
485 }
486
488
490
491 return first_block;
492}
493
494/*
495 * MarkLocalBufferDirty -
496 * mark a local buffer dirty
497 */
498void
500{
501 int bufid;
504
505 Assert(BufferIsLocal(buffer));
506
507#ifdef LBDEBUG
508 fprintf(stderr, "LB DIRTY %d\n", buffer);
509#endif
510
511 bufid = -buffer - 1;
512
514
516
518
519 if (!(buf_state & BM_DIRTY))
521
523
525}
526
527/*
528 * Like StartSharedBufferIO, but for local buffers
529 */
531StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool wait, PgAioWaitRef *io_wref)
532{
534
535 /*
536 * With AIO the buffer could have IO in progress, e.g. when there are two
537 * scans of the same relation. Either wait for the other IO (if wait =
538 * true and io_wref == NULL) or return BUFFER_IO_IN_PROGRESS;
539 */
540 if (pgaio_wref_valid(&bufHdr->io_wref))
541 {
542 PgAioWaitRef buf_wref = bufHdr->io_wref;
543
544 if (io_wref != NULL)
545 {
546 /* We've already asynchronously started this IO, so join it */
547 *io_wref = buf_wref;
549 }
550
551 /*
552 * For temp buffers we should never need to wait in
553 * StartLocalBufferIO() when called with io_wref == NULL while there
554 * are staged IOs, as it's not allowed to call code that is not aware
555 * of AIO while in batch mode.
556 */
558
559 if (!wait)
561
563 }
564
565 /* Once we get here, there is definitely no I/O active on this buffer */
566
567 /* Check if someone else already did the I/O */
570 {
572 }
573
574 /* BM_IO_IN_PROGRESS isn't currently used for local buffers */
575
576 /* local buffers don't track IO using resowners */
577
579}
580
581/*
582 * Like TerminateBufferIO, but for local buffers
583 */
584void
586 bool release_aio)
587{
588 /* Only need to adjust flags */
590
591 /* BM_IO_IN_PROGRESS isn't currently used for local buffers */
592
593 /* Clear earlier errors, if this IO failed, it'll be marked again */
595
596 if (clear_dirty)
598
599 if (release_aio)
600 {
601 /* release pin held by IO subsystem, see also buffer_stage_common() */
604 pgaio_wref_clear(&bufHdr->io_wref);
605 }
606
609
610 /* local buffers don't track IO using resowners */
611
612 /* local buffers don't use the IO CV, as no other process can see buffer */
613
614 /* local buffers don't use BM_PIN_COUNT_WAITER, so no need to wake */
615}
616
617/*
618 * InvalidateLocalBuffer -- mark a local buffer invalid.
619 *
620 * If check_unreferenced is true, error out if the buffer is still
621 * pinned. Passing false is appropriate when calling InvalidateLocalBuffer()
622 * as part of changing the identity of a buffer, instead of just dropping the
623 * buffer.
624 *
625 * See also InvalidateBuffer().
626 */
627void
629{
631 int bufid = -buffer - 1;
634
635 /*
636 * It's possible that we started IO on this buffer before e.g. aborting
637 * the transaction that created a table. We need to wait for that IO to
638 * complete before removing / reusing the buffer.
639 */
640 if (pgaio_wref_valid(&bufHdr->io_wref))
641 {
642 PgAioWaitRef iow = bufHdr->io_wref;
643
645 Assert(!pgaio_wref_valid(&bufHdr->io_wref));
646 }
647
649
650 /*
651 * We need to test not just LocalRefCount[bufid] but also the BufferDesc
652 * itself, as the latter is used to represent a pin by the AIO subsystem.
653 * This can happen if AIO is initiated and then the query errors out.
654 */
655 if (check_unreferenced &&
657 elog(ERROR, "block %u of %s is still referenced (local %d)",
658 bufHdr->tag.blockNum,
661 BufTagGetForkNum(&bufHdr->tag)).str,
663
664 /* Remove entry from hashtable */
667 if (!hresult) /* shouldn't happen */
668 elog(ERROR, "local buffer hash table corrupted");
669 /* Mark buffer invalid */
670 ClearBufferTag(&bufHdr->tag);
674}
675
676/*
677 * DropRelationLocalBuffers
678 * This function removes from the buffer pool all the pages of the
679 * specified relation that have block numbers >= firstDelBlock.
680 * (In particular, with firstDelBlock = 0, all pages are removed.)
681 * Dirty pages are simply dropped, without bothering to write them
682 * out first. Therefore, this is NOT rollback-able, and so should be
683 * used only with extreme caution!
684 *
685 * See DropRelationBuffers in bufmgr.c for more notes.
686 */
687void
690{
691 int i;
692 int j;
693
694 for (i = 0; i < NLocBuffer; i++)
695 {
698
700
701 if (!(buf_state & BM_TAG_VALID) ||
702 !BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator))
703 continue;
704
705 for (j = 0; j < nforks; j++)
706 {
707 if (BufTagGetForkNum(&bufHdr->tag) == forkNum[j] &&
708 bufHdr->tag.blockNum >= firstDelBlock[j])
709 {
711 break;
712 }
713 }
714 }
715}
716
717/*
718 * DropRelationAllLocalBuffers
719 * This function removes from the buffer pool all pages of all forks
720 * of the specified relation.
721 *
722 * See DropRelationsAllBuffers in bufmgr.c for more notes.
723 */
724void
726{
727 int i;
728
729 for (i = 0; i < NLocBuffer; i++)
730 {
733
735
736 if ((buf_state & BM_TAG_VALID) &&
737 BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator))
738 {
740 }
741 }
742}
743
744/*
745 * InitLocalBuffers -
746 * init the local buffer cache. Since most queries (esp. multi-user ones)
747 * don't involve local buffers, we delay allocating actual memory for the
748 * buffers until we need them; just make the buffer headers here.
749 */
750static void
752{
754 HASHCTL info;
755 int i;
756
757 /*
758 * Parallel workers can't access data in temporary tables, because they
759 * have no visibility into the local buffers of their leader. This is a
760 * convenient, low-cost place to provide a backstop check for that. Note
761 * that we don't wish to prevent a parallel worker from accessing catalog
762 * metadata about a temp table, so checks at higher levels would be
763 * inappropriate.
764 */
765 if (IsParallelWorker())
768 errmsg("cannot access temporary tables during a parallel operation")));
769
770 /* Allocate and zero buffer headers and auxiliary arrays */
773 LocalRefCount = (int32 *) calloc(nbufs, sizeof(int32));
777 errmsg("out of memory")));
778
780
781 /* initialize fields that need to start off nonzero */
782 for (i = 0; i < nbufs; i++)
783 {
785
786 /*
787 * negative to indicate local buffer. This is tricky: shared buffers
788 * start with 0. We have to start with -2. (Note that the routine
789 * BufferDescriptorGetBuffer adds 1 to buf_id so our first buffer id
790 * is -1.)
791 */
792 buf->buf_id = -i - 2;
793
794 pgaio_wref_clear(&buf->io_wref);
795
796 /*
797 * Intentionally do not initialize the buffer's atomic variable
798 * (besides zeroing the underlying memory above). That way we get
799 * errors on platforms without atomics, if somebody (re-)introduces
800 * atomic operations for local buffers.
801 */
802 }
803
804 /* Create the lookup hash table */
805 info.keysize = sizeof(BufferTag);
806 info.entrysize = sizeof(LocalBufferLookupEnt);
807
808 LocalBufHash = hash_create("Local Buffer Lookup Table",
809 nbufs,
810 &info,
812
813 if (!LocalBufHash)
814 elog(ERROR, "could not initialize local buffer hash table");
815
816 /* Initialization done, mark buffers allocated */
818}
819
820/*
821 * XXX: We could have a slightly more efficient version of PinLocalBuffer()
822 * that does not support adjusting the usagecount - but so far it does not
823 * seem worth the trouble.
824 *
825 * Note that ResourceOwnerEnlarge() must have been done already.
826 */
827bool
829{
832 int bufid = -buffer - 1;
833
835
836 if (LocalRefCount[bufid] == 0)
837 {
840 if (adjust_usagecount &&
842 {
844 }
846
847 /*
848 * See comment in PinBuffer().
849 *
850 * If the buffer isn't allocated yet, it'll be marked as defined in
851 * GetLocalBufferStorage().
852 */
855 }
859
860 return buf_state & BM_VALID;
861}
862
863void
865{
868}
869
870void
872{
873 int buffid = -buffer - 1;
874
875 Assert(BufferIsLocal(buffer));
878
879 if (--LocalRefCount[buffid] == 0)
880 {
883
885
890
891 /* see comment in UnpinBufferNoOwner */
893 }
894}
895
896/*
897 * GUC check_hook for temp_buffers
898 */
899bool
900check_temp_buffers(int *newval, void **extra, GucSource source)
901{
902 /*
903 * Once local buffers have been initialized, it's too late to change this.
904 * However, if this is only a test call, allow it.
905 */
907 {
908 GUC_check_errdetail("\"temp_buffers\" cannot be changed after any temporary tables have been accessed in the session.");
909 return false;
910 }
911 return true;
912}
913
914/*
915 * GetLocalBufferStorage - allocate memory for a local buffer
916 *
917 * The idea of this function is to aggregate our requests for storage
918 * so that the memory manager doesn't see a whole lot of relatively small
919 * requests. Since we'll never give back a local buffer once it's created
920 * within a particular process, no point in burdening memmgr with separately
921 * managed chunks.
922 */
923static Block
925{
926 static char *cur_block = NULL;
927 static int next_buf_in_block = 0;
928 static int num_bufs_in_block = 0;
929 static int total_bufs_allocated = 0;
931
932 char *this_buf;
933
935
937 {
938 /* Need to make a new request to memmgr */
939 int num_bufs;
940
941 /*
942 * We allocate local buffers in a context of their own, so that the
943 * space eaten for them is easily recognizable in MemoryContextStats
944 * output. Create the context on first use.
945 */
949 "LocalBufferContext",
951
952 /* Start with a 16-buffer request; subsequent ones double each time */
953 num_bufs = Max(num_bufs_in_block * 2, 16);
954 /* But not more than what we need for all remaining local bufs */
956 /* And don't overflow MaxAllocSize, either */
958
959 /* Buffers should be I/O aligned. */
963 0);
964
967 }
968
969 /* Allocate next buffer in current memory block */
973
974 /*
975 * Caller's PinLocalBuffer() was too early for Valgrind updates, so do it
976 * here. The block is actually undefined, but we want consistency with
977 * the regular case of not needing to allocate memory. This is
978 * specifically needed when method_io_uring.c fills the block, because
979 * Valgrind doesn't recognize io_uring reads causing undefined memory to
980 * become defined.
981 */
983
984 return (Block) this_buf;
985}
986
987/*
988 * CheckForLocalBufferLeaks - ensure this backend holds no local buffer pins
989 *
990 * This is just like CheckForBufferLeaks(), but for local buffers.
991 */
992static void
994{
995#ifdef USE_ASSERT_CHECKING
996 if (LocalRefCount)
997 {
998 int RefCountErrors = 0;
999 int i;
1000
1001 for (i = 0; i < NLocBuffer; i++)
1002 {
1003 if (LocalRefCount[i] != 0)
1004 {
1005 Buffer b = -i - 1;
1006 char *s;
1007
1009 elog(WARNING, "local buffer refcount leak: %s", s);
1010 pfree(s);
1011
1013 }
1014 }
1015 Assert(RefCountErrors == 0);
1016 }
1017#endif
1018}
1019
1020/*
1021 * AtEOXact_LocalBuffers - clean up at end of transaction.
1022 *
1023 * This is just like AtEOXact_Buffers, but for local buffers.
1024 */
1025void
1027{
1029}
1030
1031/*
1032 * AtProcExit_LocalBuffers - ensure we have dropped pins during backend exit.
1033 *
1034 * This is just like AtProcExit_Buffers, but for local buffers.
1035 */
1036void
1038{
1039 /*
1040 * We shouldn't be holding any remaining pins; if we are, and assertions
1041 * aren't enabled, we'll fail later in DropRelationBuffers while trying to
1042 * drop the temp rels.
1043 */
1045}
bool pgaio_wref_valid(PgAioWaitRef *iow)
Definition aio.c:971
void pgaio_wref_clear(PgAioWaitRef *iow)
Definition aio.c:964
bool pgaio_have_staged(void)
Definition aio.c:1117
void pgaio_wref_wait(PgAioWaitRef *iow)
Definition aio.c:991
static void pg_atomic_unlocked_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition atomics.h:494
static uint64 pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
Definition atomics.h:467
uint32 BlockNumber
Definition block.h:31
#define InvalidBlockNumber
Definition block.h:33
#define MaxBlockNumber
Definition block.h:35
int Buffer
Definition buf.h:23
#define InvalidBuffer
Definition buf.h:25
#define BufferIsLocal(buffer)
Definition buf.h:37
#define BM_MAX_USAGE_COUNT
static void InitBufferTag(BufferTag *tag, const RelFileLocator *rlocator, ForkNumber forkNum, BlockNumber blockNum)
#define BM_TAG_VALID
#define BUF_USAGECOUNT_MASK
static ForkNumber BufTagGetForkNum(const BufferTag *tag)
#define BUF_REFCOUNT_ONE
static bool BufferTagsEqual(const BufferTag *tag1, const BufferTag *tag2)
static bool BufTagMatchesRelFileLocator(const BufferTag *tag, const RelFileLocator *rlocator)
#define BUF_FLAG_MASK
#define BM_DIRTY
#define BUF_STATE_GET_USAGECOUNT(state)
StartBufferIOResult
@ BUFFER_IO_IN_PROGRESS
@ BUFFER_IO_ALREADY_DONE
@ BUFFER_IO_READY_FOR_IO
static void ClearBufferTag(BufferTag *tag)
static void ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
struct buftag BufferTag
static void ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)
#define BUF_USAGECOUNT_ONE
#define BUF_STATE_GET_REFCOUNT(state)
static RelFileLocator BufTagGetRelFileLocator(const BufferTag *tag)
#define BM_VALID
static BufferDesc * GetLocalBufferDescriptor(uint32 id)
static Buffer BufferDescriptorGetBuffer(const BufferDesc *bdesc)
bool track_io_timing
Definition bufmgr.c:192
char * DebugPrintBufferRefcount(Buffer buffer)
Definition bufmgr.c:4389
void * Block
Definition bufmgr.h:26
#define BMR_GET_SMGR(bmr)
Definition bufmgr.h:118
void PageSetChecksum(Page page, BlockNumber blkno)
Definition bufpage.c:1518
PageData * Page
Definition bufpage.h:81
#define Min(x, y)
Definition c.h:1091
#define Max(x, y)
Definition c.h:1085
#define Assert(condition)
Definition c.h:943
int32_t int32
Definition c.h:620
uint64_t uint64
Definition c.h:625
uint32_t uint32
Definition c.h:624
#define MemSet(start, val, len)
Definition c.h:1107
uint32 result
#define fprintf(file, fmt, msg)
Definition cubescan.l:21
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:889
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:360
int errcode(int sqlerrcode)
Definition elog.c:875
#define FATAL
Definition elog.h:42
#define WARNING
Definition elog.h:37
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
int io_direct_flags
Definition fd.c:172
#define IO_DIRECT_DATA
Definition fd.h:54
#define MaxAllocSize
Definition fe_memutils.h:22
ProcNumber MyProcNumber
Definition globals.c:92
#define newval
#define GUC_check_errdetail
Definition guc.h:507
GucSource
Definition guc.h:112
@ PGC_S_TEST
Definition guc.h:125
int num_temp_buffers
Definition guc_tables.c:580
const char * str
@ HASH_FIND
Definition hsearch.h:108
@ HASH_REMOVE
Definition hsearch.h:110
@ HASH_ENTER
Definition hsearch.h:109
#define HASH_ELEM
Definition hsearch.h:90
#define HASH_BLOBS
Definition hsearch.h:92
#define IsParallelWorker()
Definition parallel.h:62
BufferUsage pgBufferUsage
Definition instrument.c:25
int b
Definition isn.c:74
int j
Definition isn.c:78
int i
Definition isn.c:77
int32 * LocalRefCount
Definition localbuf.c:49
void FlushLocalBuffer(BufferDesc *bufHdr, SMgrRelation reln)
Definition localbuf.c:183
void UnpinLocalBuffer(Buffer buffer)
Definition localbuf.c:865
static HTAB * LocalBufHash
Definition localbuf.c:53
static int NLocalPinnedBuffers
Definition localbuf.c:56
void AtEOXact_LocalBuffers(bool isCommit)
Definition localbuf.c:1027
#define LocalBufHdrGetBlock(bufHdr)
Definition localbuf.c:42
static void CheckForLocalBufferLeaks(void)
Definition localbuf.c:994
uint32 GetAdditionalLocalPinLimit(void)
Definition localbuf.c:319
StartBufferIOResult StartLocalBufferIO(BufferDesc *bufHdr, bool forInput, bool wait, PgAioWaitRef *io_wref)
Definition localbuf.c:532
static Block GetLocalBufferStorage(void)
Definition localbuf.c:925
static int nextFreeLocalBufId
Definition localbuf.c:51
bool check_temp_buffers(int *newval, void **extra, GucSource source)
Definition localbuf.c:901
void AtProcExit_LocalBuffers(void)
Definition localbuf.c:1038
bool PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount)
Definition localbuf.c:829
static void InitLocalBuffers(void)
Definition localbuf.c:752
void LimitAdditionalLocalPins(uint32 *additional_pins)
Definition localbuf.c:332
uint32 GetLocalPinLimit(void)
Definition localbuf.c:308
static Buffer GetLocalVictimBuffer(void)
Definition localbuf.c:225
void MarkLocalBufferDirty(Buffer buffer)
Definition localbuf.c:500
void DropRelationAllLocalBuffers(RelFileLocator rlocator)
Definition localbuf.c:726
void InvalidateLocalBuffer(BufferDesc *bufHdr, bool check_unreferenced)
Definition localbuf.c:629
void TerminateLocalBufferIO(BufferDesc *bufHdr, bool clear_dirty, uint64 set_flag_bits, bool release_aio)
Definition localbuf.c:586
int NLocBuffer
Definition localbuf.c:45
BlockNumber ExtendBufferedRelLocal(BufferManagerRelation bmr, ForkNumber fork, uint32 flags, uint32 extend_by, BlockNumber extend_upto, Buffer *buffers, uint32 *extended_by)
Definition localbuf.c:355
Block * LocalBufferBlockPointers
Definition localbuf.c:48
void UnpinLocalBufferNoOwner(Buffer buffer)
Definition localbuf.c:872
void DropRelationLocalBuffers(RelFileLocator rlocator, ForkNumber *forkNum, int nforks, BlockNumber *firstDelBlock)
Definition localbuf.c:689
BufferDesc * LocalBufferDescriptors
Definition localbuf.c:47
BufferDesc * LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, bool *foundPtr)
Definition localbuf.c:119
void pfree(void *pointer)
Definition mcxt.c:1616
void * MemoryContextAllocAligned(MemoryContext context, Size size, Size alignto, int flags)
Definition mcxt.c:1482
MemoryContext TopMemoryContext
Definition mcxt.c:166
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition memdebug.h:26
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
Definition memdebug.h:27
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
static char * errmsg
#define PG_IO_ALIGN_SIZE
static rewind_source * source
Definition pg_rewind.c:89
static char buf[DEFAULT_XLOG_SEG_SIZE]
@ IOOBJECT_TEMP_RELATION
Definition pgstat.h:282
@ IOCONTEXT_NORMAL
Definition pgstat.h:293
@ IOOP_EXTEND
Definition pgstat.h:318
@ IOOP_EVICT
Definition pgstat.h:311
@ IOOP_WRITE
Definition pgstat.h:320
instr_time pgstat_prepare_io_time(bool track_io_guc)
Definition pgstat_io.c:91
void pgstat_count_io_op(IOObject io_object, IOContext io_context, IOOp io_op, uint32 cnt, uint64 bytes)
Definition pgstat_io.c:68
void pgstat_count_io_op_time(IOObject io_object, IOContext io_context, IOOp io_op, instr_time start_time, uint32 cnt, uint64 bytes)
Definition pgstat_io.c:122
static int fb(int x)
ForkNumber
Definition relpath.h:56
#define relpath(rlocator, forknum)
Definition relpath.h:150
#define relpathbackend(rlocator, backend, forknum)
Definition relpath.h:141
ResourceOwner CurrentResourceOwner
Definition resowner.c:173
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition resowner.c:449
BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum)
Definition smgr.c:819
SMgrRelation smgropen(RelFileLocator rlocator, ProcNumber backend)
Definition smgr.c:240
void smgrzeroextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, int nblocks, bool skipFsync)
Definition smgr.c:649
bool smgrprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, int nblocks)
Definition smgr.c:678
static void smgrwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, const void *buffer, bool skipFsync)
Definition smgr.h:131
#define calloc(a, b)
int64 local_blks_written
Definition instrument.h:33
int64 local_blks_dirtied
Definition instrument.h:32
Size keysize
Definition hsearch.h:69
Size entrysize
Definition hsearch.h:70
RelFileLocator locator
RelFileLocatorBackend smgr_rlocator
Definition smgr.h:38

Function Documentation

◆ AtEOXact_LocalBuffers()

void AtEOXact_LocalBuffers ( bool  isCommit)

Definition at line 1027 of file localbuf.c.

1028{
1030}

References CheckForLocalBufferLeaks().

Referenced by AtEOXact_Buffers().

◆ AtProcExit_LocalBuffers()

void AtProcExit_LocalBuffers ( void  )

Definition at line 1038 of file localbuf.c.

1039{
1040 /*
1041 * We shouldn't be holding any remaining pins; if we are, and assertions
1042 * aren't enabled, we'll fail later in DropRelationBuffers while trying to
1043 * drop the temp rels.
1044 */
1046}

References CheckForLocalBufferLeaks().

Referenced by AtProcExit_Buffers().

◆ check_temp_buffers()

bool check_temp_buffers ( int newval,
void **  extra,
GucSource  source 
)

Definition at line 901 of file localbuf.c.

902{
903 /*
904 * Once local buffers have been initialized, it's too late to change this.
905 * However, if this is only a test call, allow it.
906 */
908 {
909 GUC_check_errdetail("\"temp_buffers\" cannot be changed after any temporary tables have been accessed in the session.");
910 return false;
911 }
912 return true;
913}

References GUC_check_errdetail, newval, NLocBuffer, PGC_S_TEST, and source.

◆ CheckForLocalBufferLeaks()

static void CheckForLocalBufferLeaks ( void  )
static

Definition at line 994 of file localbuf.c.

995{
996#ifdef USE_ASSERT_CHECKING
997 if (LocalRefCount)
998 {
999 int RefCountErrors = 0;
1000 int i;
1001
1002 for (i = 0; i < NLocBuffer; i++)
1003 {
1004 if (LocalRefCount[i] != 0)
1005 {
1006 Buffer b = -i - 1;
1007 char *s;
1008
1010 elog(WARNING, "local buffer refcount leak: %s", s);
1011 pfree(s);
1012
1014 }
1015 }
1016 Assert(RefCountErrors == 0);
1017 }
1018#endif
1019}

References Assert, b, DebugPrintBufferRefcount(), elog, fb(), i, LocalRefCount, NLocBuffer, pfree(), and WARNING.

Referenced by AtEOXact_LocalBuffers(), and AtProcExit_LocalBuffers().

◆ DropRelationAllLocalBuffers()

void DropRelationAllLocalBuffers ( RelFileLocator  rlocator)

Definition at line 726 of file localbuf.c.

727{
728 int i;
729
730 for (i = 0; i < NLocBuffer; i++)
731 {
734
736
737 if ((buf_state & BM_TAG_VALID) &&
738 BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator))
739 {
741 }
742 }
743}

References BM_TAG_VALID, BufTagMatchesRelFileLocator(), fb(), GetLocalBufferDescriptor(), i, InvalidateLocalBuffer(), NLocBuffer, and pg_atomic_read_u64().

Referenced by DropRelationsAllBuffers().

◆ DropRelationLocalBuffers()

void DropRelationLocalBuffers ( RelFileLocator  rlocator,
ForkNumber forkNum,
int  nforks,
BlockNumber firstDelBlock 
)

Definition at line 689 of file localbuf.c.

691{
692 int i;
693 int j;
694
695 for (i = 0; i < NLocBuffer; i++)
696 {
699
701
702 if (!(buf_state & BM_TAG_VALID) ||
703 !BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator))
704 continue;
705
706 for (j = 0; j < nforks; j++)
707 {
708 if (BufTagGetForkNum(&bufHdr->tag) == forkNum[j] &&
709 bufHdr->tag.blockNum >= firstDelBlock[j])
710 {
712 break;
713 }
714 }
715 }
716}

References BM_TAG_VALID, BufTagGetForkNum(), BufTagMatchesRelFileLocator(), fb(), GetLocalBufferDescriptor(), i, InvalidateLocalBuffer(), j, NLocBuffer, and pg_atomic_read_u64().

Referenced by DropRelationBuffers().

◆ ExtendBufferedRelLocal()

BlockNumber ExtendBufferedRelLocal ( BufferManagerRelation  bmr,
ForkNumber  fork,
uint32  flags,
uint32  extend_by,
BlockNumber  extend_upto,
Buffer buffers,
uint32 extended_by 
)

Definition at line 355 of file localbuf.c.

362{
365
366 /* Initialize local buffers if first request in this session */
367 if (LocalBufHash == NULL)
369
371
372 for (uint32 i = 0; i < extend_by; i++)
373 {
376
377 buffers[i] = GetLocalVictimBuffer();
378 buf_hdr = GetLocalBufferDescriptor(-buffers[i] - 1);
380
381 /* new buffers are zero-filled */
383 }
384
386
388 {
389 /*
390 * In contrast to shared relations, nothing could change the relation
391 * size concurrently. Thus we shouldn't end up finding that we don't
392 * need to do anything.
393 */
395
397 }
398
399 /* Fail if relation is already at maximum possible length */
403 errmsg("cannot extend relation %s beyond %u blocks",
404 relpath(BMR_GET_SMGR(bmr)->smgr_rlocator, fork).str,
406
407 for (uint32 i = 0; i < extend_by; i++)
408 {
409 int victim_buf_id;
411 BufferTag tag;
413 bool found;
414
415 victim_buf_id = -buffers[i] - 1;
417
418 /* in case we need to pin an existing buffer below */
420
421 InitBufferTag(&tag, &BMR_GET_SMGR(bmr)->smgr_rlocator.locator, fork,
422 first_block + i);
423
425 hash_search(LocalBufHash, &tag, HASH_ENTER, &found);
426 if (found)
427 {
430
432
436
437 /*
438 * Clear the BM_VALID bit, do StartLocalBufferIO() and proceed.
439 */
445
446 /* no need to loop for local buffers */
448 }
449 else
450 {
452
454
455 victim_buf_hdr->tag = tag;
456
458
460
462
464 }
465 }
466
468
469 /* actually extend relation */
471
474
475 for (uint32 i = 0; i < extend_by; i++)
476 {
477 Buffer buf = buffers[i];
480
482
486 }
487
489
491
492 return first_block;
493}

References Assert, BM_DIRTY, BM_TAG_VALID, BM_VALID, BMR_GET_SMGR, buf, BUF_USAGECOUNT_ONE, BufferDescriptorGetBuffer(), CurrentResourceOwner, ereport, errcode(), errmsg, ERROR, fb(), GetLocalBufferDescriptor(), GetLocalVictimBuffer(), HASH_ENTER, hash_search(), i, InitBufferTag(), InitLocalBuffers(), InvalidBlockNumber, IOCONTEXT_NORMAL, IOOBJECT_TEMP_RELATION, IOOP_EXTEND, LimitAdditionalLocalPins(), BufferUsage::local_blks_written, LocalBufHash, LocalBufHdrGetBlock, MaxBlockNumber, MemSet, pg_atomic_read_u64(), pg_atomic_unlocked_write_u64(), pgBufferUsage, pgstat_count_io_op_time(), pgstat_prepare_io_time(), PinLocalBuffer(), relpath, ResourceOwnerEnlarge(), smgrnblocks(), smgrzeroextend(), StartLocalBufferIO(), str, track_io_timing, and UnpinLocalBuffer().

Referenced by ExtendBufferedRelCommon().

◆ FlushLocalBuffer()

void FlushLocalBuffer ( BufferDesc bufHdr,
SMgrRelation  reln 
)

Definition at line 183 of file localbuf.c.

184{
187
189
190 /*
191 * Try to start an I/O operation. There currently are no reasons for
192 * StartLocalBufferIO to return anything other than
193 * BUFFER_IO_READY_FOR_IO, so we raise an error in that case.
194 */
196 elog(ERROR, "failed to start write IO on local buffer");
197
198 /* Find smgr relation for buffer */
199 if (reln == NULL)
202
203 PageSetChecksum(localpage, bufHdr->tag.blockNum);
204
206
207 /* And write... */
210 bufHdr->tag.blockNum,
211 localpage,
212 false);
213
214 /* Temporary table I/O does not use Buffer Access Strategies */
217
218 /* Mark not-dirty */
219 TerminateLocalBufferIO(bufHdr, true, 0, false);
220
222}

References Assert, BUFFER_IO_READY_FOR_IO, BufferDescriptorGetBuffer(), BufTagGetForkNum(), BufTagGetRelFileLocator(), elog, ERROR, fb(), IOCONTEXT_NORMAL, IOOBJECT_TEMP_RELATION, IOOP_WRITE, BufferUsage::local_blks_written, LocalBufHdrGetBlock, LocalRefCount, MyProcNumber, PageSetChecksum(), pgBufferUsage, pgstat_count_io_op_time(), pgstat_prepare_io_time(), smgropen(), smgrwrite(), StartLocalBufferIO(), TerminateLocalBufferIO(), and track_io_timing.

Referenced by FlushRelationBuffers(), GetLocalVictimBuffer(), and invalidate_one_block().

◆ GetAdditionalLocalPinLimit()

uint32 GetAdditionalLocalPinLimit ( void  )

Definition at line 319 of file localbuf.c.

320{
321 uint32 total = GetLocalPinLimit();
322
324
325 if (NLocalPinnedBuffers >= total)
326 return 0;
327 return total - NLocalPinnedBuffers;
328}

References Assert, GetLocalPinLimit(), NLocalPinnedBuffers, and num_temp_buffers.

Referenced by read_stream_start_pending_read().

◆ GetLocalBufferStorage()

static Block GetLocalBufferStorage ( void  )
static

Definition at line 925 of file localbuf.c.

926{
927 static char *cur_block = NULL;
928 static int next_buf_in_block = 0;
929 static int num_bufs_in_block = 0;
930 static int total_bufs_allocated = 0;
932
933 char *this_buf;
934
936
938 {
939 /* Need to make a new request to memmgr */
940 int num_bufs;
941
942 /*
943 * We allocate local buffers in a context of their own, so that the
944 * space eaten for them is easily recognizable in MemoryContextStats
945 * output. Create the context on first use.
946 */
950 "LocalBufferContext",
952
953 /* Start with a 16-buffer request; subsequent ones double each time */
954 num_bufs = Max(num_bufs_in_block * 2, 16);
955 /* But not more than what we need for all remaining local bufs */
957 /* And don't overflow MaxAllocSize, either */
959
960 /* Buffers should be I/O aligned. */
964 0);
965
968 }
969
970 /* Allocate next buffer in current memory block */
974
975 /*
976 * Caller's PinLocalBuffer() was too early for Valgrind updates, so do it
977 * here. The block is actually undefined, but we want consistency with
978 * the regular case of not needing to allocate memory. This is
979 * specifically needed when method_io_uring.c fills the block, because
980 * Valgrind doesn't recognize io_uring reads causing undefined memory to
981 * become defined.
982 */
984
985 return (Block) this_buf;
986}

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, fb(), Max, MaxAllocSize, MemoryContextAllocAligned(), Min, NLocBuffer, PG_IO_ALIGN_SIZE, TopMemoryContext, and VALGRIND_MAKE_MEM_DEFINED.

Referenced by GetLocalVictimBuffer().

◆ GetLocalPinLimit()

uint32 GetLocalPinLimit ( void  )

Definition at line 308 of file localbuf.c.

309{
310 /*
311 * Every backend has its own temporary buffers, but we leave headroom for
312 * concurrent pin-holders -- like multiple scans in the same query.
313 */
314 return num_temp_buffers / 4;
315}

References num_temp_buffers.

Referenced by GetAdditionalLocalPinLimit(), and read_stream_begin_impl().

◆ GetLocalVictimBuffer()

static Buffer GetLocalVictimBuffer ( void  )
static

Definition at line 225 of file localbuf.c.

226{
227 int victim_bufid;
228 int trycounter;
230
232
233 /*
234 * Need to get a new buffer. We use a clock-sweep algorithm (essentially
235 * the same as what freelist.c does now...)
236 */
238 for (;;)
239 {
241
244
246
247 if (LocalRefCount[victim_bufid] == 0)
248 {
250
252 {
256 }
257 else if (BUF_STATE_GET_REFCOUNT(buf_state) > 0)
258 {
259 /*
260 * This can be reached if the backend initiated AIO for this
261 * buffer and then errored out.
262 */
263 }
264 else
265 {
266 /* Found a usable buffer */
267 PinLocalBuffer(bufHdr, false);
268 break;
269 }
270 }
271 else if (--trycounter == 0)
274 errmsg("no empty local buffer available")));
275 }
276
277 /*
278 * lazy memory allocation: allocate space on first use of a buffer.
279 */
281 {
282 /* Set pointer for use by BufferGetBlock() macro */
284 }
285
286 /*
287 * this buffer is not referenced but it might still be dirty. if that's
288 * the case, write it out before reusing it!
289 */
290 if (pg_atomic_read_u64(&bufHdr->state) & BM_DIRTY)
292
293 /*
294 * Remove the victim buffer from the hashtable and mark as invalid.
295 */
297 {
299
301 }
302
304}

References BM_DIRTY, BM_TAG_VALID, BUF_STATE_GET_REFCOUNT, BUF_STATE_GET_USAGECOUNT, BUF_USAGECOUNT_ONE, BufferDescriptorGetBuffer(), CurrentResourceOwner, ereport, errcode(), errmsg, ERROR, fb(), FlushLocalBuffer(), GetLocalBufferDescriptor(), GetLocalBufferStorage(), InvalidateLocalBuffer(), IOCONTEXT_NORMAL, IOOBJECT_TEMP_RELATION, IOOP_EVICT, LocalBufHdrGetBlock, LocalRefCount, nextFreeLocalBufId, NLocBuffer, pg_atomic_read_u64(), pg_atomic_unlocked_write_u64(), pgstat_count_io_op(), PinLocalBuffer(), and ResourceOwnerEnlarge().

Referenced by ExtendBufferedRelLocal(), and LocalBufferAlloc().

◆ InitLocalBuffers()

static void InitLocalBuffers ( void  )
static

Definition at line 752 of file localbuf.c.

753{
755 HASHCTL info;
756 int i;
757
758 /*
759 * Parallel workers can't access data in temporary tables, because they
760 * have no visibility into the local buffers of their leader. This is a
761 * convenient, low-cost place to provide a backstop check for that. Note
762 * that we don't wish to prevent a parallel worker from accessing catalog
763 * metadata about a temp table, so checks at higher levels would be
764 * inappropriate.
765 */
766 if (IsParallelWorker())
769 errmsg("cannot access temporary tables during a parallel operation")));
770
771 /* Allocate and zero buffer headers and auxiliary arrays */
774 LocalRefCount = (int32 *) calloc(nbufs, sizeof(int32));
778 errmsg("out of memory")));
779
781
782 /* initialize fields that need to start off nonzero */
783 for (i = 0; i < nbufs; i++)
784 {
786
787 /*
788 * negative to indicate local buffer. This is tricky: shared buffers
789 * start with 0. We have to start with -2. (Note that the routine
790 * BufferDescriptorGetBuffer adds 1 to buf_id so our first buffer id
791 * is -1.)
792 */
793 buf->buf_id = -i - 2;
794
795 pgaio_wref_clear(&buf->io_wref);
796
797 /*
798 * Intentionally do not initialize the buffer's atomic variable
799 * (besides zeroing the underlying memory above). That way we get
800 * errors on platforms without atomics, if somebody (re-)introduces
801 * atomic operations for local buffers.
802 */
803 }
804
805 /* Create the lookup hash table */
806 info.keysize = sizeof(BufferTag);
807 info.entrysize = sizeof(LocalBufferLookupEnt);
808
809 LocalBufHash = hash_create("Local Buffer Lookup Table",
810 nbufs,
811 &info,
813
814 if (!LocalBufHash)
815 elog(ERROR, "could not initialize local buffer hash table");
816
817 /* Initialization done, mark buffers allocated */
819}

References buf, calloc, elog, HASHCTL::entrysize, ereport, errcode(), errmsg, ERROR, FATAL, fb(), GetLocalBufferDescriptor(), HASH_BLOBS, hash_create(), HASH_ELEM, i, IsParallelWorker, HASHCTL::keysize, LocalBufferBlockPointers, LocalBufferDescriptors, LocalBufHash, LocalRefCount, nextFreeLocalBufId, NLocBuffer, num_temp_buffers, and pgaio_wref_clear().

Referenced by ExtendBufferedRelLocal(), LocalBufferAlloc(), and PrefetchLocalBuffer().

◆ InvalidateLocalBuffer()

void InvalidateLocalBuffer ( BufferDesc bufHdr,
bool  check_unreferenced 
)

Definition at line 629 of file localbuf.c.

630{
632 int bufid = -buffer - 1;
635
636 /*
637 * It's possible that we started IO on this buffer before e.g. aborting
638 * the transaction that created a table. We need to wait for that IO to
639 * complete before removing / reusing the buffer.
640 */
641 if (pgaio_wref_valid(&bufHdr->io_wref))
642 {
643 PgAioWaitRef iow = bufHdr->io_wref;
644
646 Assert(!pgaio_wref_valid(&bufHdr->io_wref));
647 }
648
650
651 /*
652 * We need to test not just LocalRefCount[bufid] but also the BufferDesc
653 * itself, as the latter is used to represent a pin by the AIO subsystem.
654 * This can happen if AIO is initiated and then the query errors out.
655 */
656 if (check_unreferenced &&
658 elog(ERROR, "block %u of %s is still referenced (local %d)",
659 bufHdr->tag.blockNum,
662 BufTagGetForkNum(&bufHdr->tag)).str,
664
665 /* Remove entry from hashtable */
668 if (!hresult) /* shouldn't happen */
669 elog(ERROR, "local buffer hash table corrupted");
670 /* Mark buffer invalid */
671 ClearBufferTag(&bufHdr->tag);
675}

References Assert, BUF_STATE_GET_REFCOUNT, BufferDescriptorGetBuffer(), BufTagGetForkNum(), BufTagGetRelFileLocator(), ClearBufferTag(), elog, ERROR, fb(), HASH_REMOVE, hash_search(), LocalBufHash, LocalRefCount, MyProcNumber, pg_atomic_read_u64(), pg_atomic_unlocked_write_u64(), pgaio_wref_valid(), pgaio_wref_wait(), and relpathbackend.

Referenced by DropRelationAllLocalBuffers(), DropRelationLocalBuffers(), GetLocalVictimBuffer(), invalidate_one_block(), and modify_rel_block().

◆ LimitAdditionalLocalPins()

void LimitAdditionalLocalPins ( uint32 additional_pins)

Definition at line 332 of file localbuf.c.

333{
335
336 if (*additional_pins <= 1)
337 return;
338
339 /*
340 * In contrast to LimitAdditionalPins() other backends don't play a role
341 * here. We can allow up to NLocBuffer pins in total, but it might not be
342 * initialized yet so read num_temp_buffers.
343 */
345
348}

References fb(), NLocalPinnedBuffers, and num_temp_buffers.

Referenced by ExtendBufferedRelLocal().

◆ LocalBufferAlloc()

BufferDesc * LocalBufferAlloc ( SMgrRelation  smgr,
ForkNumber  forkNum,
BlockNumber  blockNum,
bool foundPtr 
)

Definition at line 119 of file localbuf.c.

121{
122 BufferTag newTag; /* identity of requested block */
126 int bufid;
127 bool found;
128
129 InitBufferTag(&newTag, &smgr->smgr_rlocator.locator, forkNum, blockNum);
130
131 /* Initialize local buffers if first request in this session */
132 if (LocalBufHash == NULL)
134
136
137 /* See if the desired buffer already exists */
140
141 if (hresult)
142 {
143 bufid = hresult->id;
146
148 }
149 else
150 {
152
154 bufid = -victim_buffer - 1;
156
159 if (found) /* shouldn't happen */
160 elog(ERROR, "local buffer hash table corrupted");
161 hresult->id = bufid;
162
163 /*
164 * it's all ours now.
165 */
166 bufHdr->tag = newTag;
167
172
173 *foundPtr = false;
174 }
175
176 return bufHdr;
177}

References Assert, BM_TAG_VALID, BUF_FLAG_MASK, BUF_USAGECOUNT_MASK, BUF_USAGECOUNT_ONE, BufferTagsEqual(), CurrentResourceOwner, elog, ERROR, fb(), GetLocalBufferDescriptor(), GetLocalVictimBuffer(), HASH_ENTER, HASH_FIND, hash_search(), InitBufferTag(), InitLocalBuffers(), LocalBufHash, RelFileLocatorBackend::locator, pg_atomic_read_u64(), pg_atomic_unlocked_write_u64(), PinLocalBuffer(), ResourceOwnerEnlarge(), and SMgrRelationData::smgr_rlocator.

Referenced by PinBufferForBlock().

◆ MarkLocalBufferDirty()

void MarkLocalBufferDirty ( Buffer  buffer)

Definition at line 500 of file localbuf.c.

501{
502 int bufid;
505
506 Assert(BufferIsLocal(buffer));
507
508#ifdef LBDEBUG
509 fprintf(stderr, "LB DIRTY %d\n", buffer);
510#endif
511
512 bufid = -buffer - 1;
513
515
517
519
520 if (!(buf_state & BM_DIRTY))
522
524
526}

References Assert, BM_DIRTY, BufferIsLocal, fb(), fprintf, GetLocalBufferDescriptor(), BufferUsage::local_blks_dirtied, LocalRefCount, pg_atomic_read_u64(), pg_atomic_unlocked_write_u64(), and pgBufferUsage.

Referenced by BufferSetHintBits16(), MarkBufferDirty(), and MarkBufferDirtyHint().

◆ PinLocalBuffer()

bool PinLocalBuffer ( BufferDesc buf_hdr,
bool  adjust_usagecount 
)

◆ PrefetchLocalBuffer()

PrefetchBufferResult PrefetchLocalBuffer ( SMgrRelation  smgr,
ForkNumber  forkNum,
BlockNumber  blockNum 
)

Definition at line 72 of file localbuf.c.

74{
76 BufferTag newTag; /* identity of requested block */
78
79 InitBufferTag(&newTag, &smgr->smgr_rlocator.locator, forkNum, blockNum);
80
81 /* Initialize local buffers if first request in this session */
82 if (LocalBufHash == NULL)
84
85 /* See if the desired buffer already exists */
88
89 if (hresult)
90 {
91 /* Yes, so nothing to do */
92 result.recent_buffer = -hresult->id - 1;
93 }
94 else
95 {
96#ifdef USE_PREFETCH
97 /* Not in buffers, so initiate prefetch */
98 if ((io_direct_flags & IO_DIRECT_DATA) == 0 &&
99 smgrprefetch(smgr, forkNum, blockNum, 1))
100 {
101 result.initiated_io = true;
102 }
103#endif /* USE_PREFETCH */
104 }
105
106 return result;
107}

References fb(), HASH_FIND, hash_search(), InitBufferTag(), InitLocalBuffers(), InvalidBuffer, IO_DIRECT_DATA, io_direct_flags, LocalBufHash, RelFileLocatorBackend::locator, result, SMgrRelationData::smgr_rlocator, and smgrprefetch().

Referenced by PrefetchBuffer().

◆ StartLocalBufferIO()

StartBufferIOResult StartLocalBufferIO ( BufferDesc bufHdr,
bool  forInput,
bool  wait,
PgAioWaitRef io_wref 
)

Definition at line 532 of file localbuf.c.

533{
535
536 /*
537 * With AIO the buffer could have IO in progress, e.g. when there are two
538 * scans of the same relation. Either wait for the other IO (if wait =
539 * true and io_wref == NULL) or return BUFFER_IO_IN_PROGRESS;
540 */
541 if (pgaio_wref_valid(&bufHdr->io_wref))
542 {
543 PgAioWaitRef buf_wref = bufHdr->io_wref;
544
545 if (io_wref != NULL)
546 {
547 /* We've already asynchronously started this IO, so join it */
548 *io_wref = buf_wref;
550 }
551
552 /*
553 * For temp buffers we should never need to wait in
554 * StartLocalBufferIO() when called with io_wref == NULL while there
555 * are staged IOs, as it's not allowed to call code that is not aware
556 * of AIO while in batch mode.
557 */
559
560 if (!wait)
562
564 }
565
566 /* Once we get here, there is definitely no I/O active on this buffer */
567
568 /* Check if someone else already did the I/O */
571 {
573 }
574
575 /* BM_IO_IN_PROGRESS isn't currently used for local buffers */
576
577 /* local buffers don't track IO using resowners */
578
580}

References Assert, BM_DIRTY, BM_VALID, BUFFER_IO_ALREADY_DONE, BUFFER_IO_IN_PROGRESS, BUFFER_IO_READY_FOR_IO, fb(), pg_atomic_read_u64(), pgaio_have_staged(), pgaio_wref_valid(), and pgaio_wref_wait().

Referenced by buffer_call_start_io(), ExtendBufferedRelLocal(), FlushLocalBuffer(), read_rel_block_ll(), StartBufferIO(), and ZeroAndLockBuffer().

◆ TerminateLocalBufferIO()

void TerminateLocalBufferIO ( BufferDesc bufHdr,
bool  clear_dirty,
uint64  set_flag_bits,
bool  release_aio 
)

Definition at line 586 of file localbuf.c.

588{
589 /* Only need to adjust flags */
591
592 /* BM_IO_IN_PROGRESS isn't currently used for local buffers */
593
594 /* Clear earlier errors, if this IO failed, it'll be marked again */
596
597 if (clear_dirty)
599
600 if (release_aio)
601 {
602 /* release pin held by IO subsystem, see also buffer_stage_common() */
605 pgaio_wref_clear(&bufHdr->io_wref);
606 }
607
610
611 /* local buffers don't track IO using resowners */
612
613 /* local buffers don't use the IO CV, as no other process can see buffer */
614
615 /* local buffers don't use BM_PIN_COUNT_WAITER, so no need to wake */
616}

References Assert, BUF_REFCOUNT_ONE, BUF_STATE_GET_REFCOUNT, fb(), pg_atomic_read_u64(), pg_atomic_unlocked_write_u64(), and pgaio_wref_clear().

Referenced by buffer_call_terminate_io(), buffer_readv_complete_one(), FlushLocalBuffer(), and ZeroAndLockBuffer().

◆ UnpinLocalBuffer()

◆ UnpinLocalBufferNoOwner()

Variable Documentation

◆ LocalBufferBlockPointers

Block* LocalBufferBlockPointers = NULL

Definition at line 48 of file localbuf.c.

Referenced by BufferGetBlock(), and InitLocalBuffers().

◆ LocalBufferDescriptors

BufferDesc* LocalBufferDescriptors = NULL

Definition at line 47 of file localbuf.c.

Referenced by GetLocalBufferDescriptor(), and InitLocalBuffers().

◆ LocalBufHash

HTAB* LocalBufHash = NULL
static

◆ LocalRefCount

◆ nextFreeLocalBufId

int nextFreeLocalBufId = 0
static

Definition at line 51 of file localbuf.c.

Referenced by GetLocalVictimBuffer(), and InitLocalBuffers().

◆ NLocalPinnedBuffers

int NLocalPinnedBuffers = 0
static

◆ NLocBuffer