PostgreSQL Source Code  git master
localbuf.c File Reference
#include "postgres.h"
#include "access/parallel.h"
#include "executor/instrument.h"
#include "pgstat.h"
#include "storage/buf_internals.h"
#include "storage/bufmgr.h"
#include "storage/fd.h"
#include "utils/guc_hooks.h"
#include "utils/memutils.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)
 
static 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)
 
void DropRelationLocalBuffers (RelFileLocator rlocator, ForkNumber forkNum, 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 39 of file localbuf.c.

Function Documentation

◆ AtEOXact_LocalBuffers()

void AtEOXact_LocalBuffers ( bool  isCommit)

Definition at line 819 of file localbuf.c.

820 {
822 }
static void CheckForLocalBufferLeaks(void)
Definition: localbuf.c:786

References CheckForLocalBufferLeaks().

Referenced by AtEOXact_Buffers().

◆ AtProcExit_LocalBuffers()

void AtProcExit_LocalBuffers ( void  )

Definition at line 830 of file localbuf.c.

831 {
832  /*
833  * We shouldn't be holding any remaining pins; if we are, and assertions
834  * aren't enabled, we'll fail later in DropRelationBuffers while trying to
835  * drop the temp rels.
836  */
838 }

References CheckForLocalBufferLeaks().

Referenced by AtProcExit_Buffers().

◆ check_temp_buffers()

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

Definition at line 704 of file localbuf.c.

705 {
706  /*
707  * Once local buffers have been initialized, it's too late to change this.
708  * However, if this is only a test call, allow it.
709  */
710  if (source != PGC_S_TEST && NLocBuffer && NLocBuffer != *newval)
711  {
712  GUC_check_errdetail("temp_buffers cannot be changed after any temporary tables have been accessed in the session.");
713  return false;
714  }
715  return true;
716 }
#define newval
#define GUC_check_errdetail
Definition: guc.h:447
@ PGC_S_TEST
Definition: guc.h:121
int NLocBuffer
Definition: localbuf.c:42
static rewind_source * source
Definition: pg_rewind.c:89

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

◆ CheckForLocalBufferLeaks()

static void CheckForLocalBufferLeaks ( void  )
static

Definition at line 786 of file localbuf.c.

787 {
788 #ifdef USE_ASSERT_CHECKING
789  if (LocalRefCount)
790  {
791  int RefCountErrors = 0;
792  int i;
793 
794  for (i = 0; i < NLocBuffer; i++)
795  {
796  if (LocalRefCount[i] != 0)
797  {
798  Buffer b = -i - 1;
799  char *s;
800 
802  elog(WARNING, "local buffer refcount leak: %s", s);
803  pfree(s);
804 
805  RefCountErrors++;
806  }
807  }
808  Assert(RefCountErrors == 0);
809  }
810 #endif
811 }
int Buffer
Definition: buf.h:23
char * DebugPrintBufferRefcount(Buffer buffer)
Definition: bufmgr.c:3318
#define WARNING
Definition: elog.h:36
#define elog(elevel,...)
Definition: elog.h:224
int b
Definition: isn.c:70
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
int32 * LocalRefCount
Definition: localbuf.c:46
void pfree(void *pointer)
Definition: mcxt.c:1508

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

Referenced by AtEOXact_LocalBuffers(), and AtProcExit_LocalBuffers().

◆ DropRelationAllLocalBuffers()

void DropRelationAllLocalBuffers ( RelFileLocator  rlocator)

Definition at line 537 of file localbuf.c.

538 {
539  int i;
540 
541  for (i = 0; i < NLocBuffer; i++)
542  {
544  LocalBufferLookupEnt *hresult;
545  uint32 buf_state;
546 
547  buf_state = pg_atomic_read_u32(&bufHdr->state);
548 
549  if ((buf_state & BM_TAG_VALID) &&
550  BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator))
551  {
552  if (LocalRefCount[i] != 0)
553  elog(ERROR, "block %u of %s is still referenced (local %u)",
554  bufHdr->tag.blockNum,
556  MyProcNumber,
557  BufTagGetForkNum(&bufHdr->tag)),
558  LocalRefCount[i]);
559  /* Remove entry from hashtable */
560  hresult = (LocalBufferLookupEnt *)
561  hash_search(LocalBufHash, &bufHdr->tag, HASH_REMOVE, NULL);
562  if (!hresult) /* shouldn't happen */
563  elog(ERROR, "local buffer hash table corrupted");
564  /* Mark buffer invalid */
565  ClearBufferTag(&bufHdr->tag);
566  buf_state &= ~BUF_FLAG_MASK;
567  buf_state &= ~BUF_USAGECOUNT_MASK;
568  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
569  }
570  }
571 }
static void pg_atomic_unlocked_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:290
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition: atomics.h:234
#define BM_TAG_VALID
Definition: buf_internals.h:63
#define BUF_USAGECOUNT_MASK
Definition: buf_internals.h:45
static ForkNumber BufTagGetForkNum(const BufferTag *tag)
static BufferDesc * GetLocalBufferDescriptor(uint32 id)
static bool BufTagMatchesRelFileLocator(const BufferTag *tag, const RelFileLocator *rlocator)
#define BUF_FLAG_MASK
Definition: buf_internals.h:48
static void ClearBufferTag(BufferTag *tag)
static RelFileLocator BufTagGetRelFileLocator(const BufferTag *tag)
unsigned int uint32
Definition: c.h:493
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
#define ERROR
Definition: elog.h:39
ProcNumber MyProcNumber
Definition: globals.c:87
@ HASH_REMOVE
Definition: hsearch.h:115
static HTAB * LocalBufHash
Definition: localbuf.c:50
#define relpathbackend(rlocator, backend, forknum)
Definition: relpath.h:85
BufferTag tag
pg_atomic_uint32 state
BlockNumber blockNum
Definition: buf_internals.h:98

References buftag::blockNum, BM_TAG_VALID, BUF_FLAG_MASK, BUF_USAGECOUNT_MASK, BufTagGetForkNum(), BufTagGetRelFileLocator(), BufTagMatchesRelFileLocator(), ClearBufferTag(), elog, ERROR, GetLocalBufferDescriptor(), HASH_REMOVE, hash_search(), i, LocalBufHash, LocalRefCount, MyProcNumber, NLocBuffer, pg_atomic_read_u32(), pg_atomic_unlocked_write_u32(), relpathbackend, BufferDesc::state, and BufferDesc::tag.

Referenced by DropRelationsAllBuffers().

◆ DropRelationLocalBuffers()

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

Definition at line 489 of file localbuf.c.

491 {
492  int i;
493 
494  for (i = 0; i < NLocBuffer; i++)
495  {
497  LocalBufferLookupEnt *hresult;
498  uint32 buf_state;
499 
500  buf_state = pg_atomic_read_u32(&bufHdr->state);
501 
502  if ((buf_state & BM_TAG_VALID) &&
503  BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator) &&
504  BufTagGetForkNum(&bufHdr->tag) == forkNum &&
505  bufHdr->tag.blockNum >= firstDelBlock)
506  {
507  if (LocalRefCount[i] != 0)
508  elog(ERROR, "block %u of %s is still referenced (local %u)",
509  bufHdr->tag.blockNum,
511  MyProcNumber,
512  BufTagGetForkNum(&bufHdr->tag)),
513  LocalRefCount[i]);
514 
515  /* Remove entry from hashtable */
516  hresult = (LocalBufferLookupEnt *)
517  hash_search(LocalBufHash, &bufHdr->tag, HASH_REMOVE, NULL);
518  if (!hresult) /* shouldn't happen */
519  elog(ERROR, "local buffer hash table corrupted");
520  /* Mark buffer invalid */
521  ClearBufferTag(&bufHdr->tag);
522  buf_state &= ~BUF_FLAG_MASK;
523  buf_state &= ~BUF_USAGECOUNT_MASK;
524  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
525  }
526  }
527 }

References buftag::blockNum, BM_TAG_VALID, BUF_FLAG_MASK, BUF_USAGECOUNT_MASK, BufTagGetForkNum(), BufTagGetRelFileLocator(), BufTagMatchesRelFileLocator(), ClearBufferTag(), elog, ERROR, GetLocalBufferDescriptor(), HASH_REMOVE, hash_search(), i, LocalBufHash, LocalRefCount, MyProcNumber, NLocBuffer, pg_atomic_read_u32(), pg_atomic_unlocked_write_u32(), relpathbackend, BufferDesc::state, and BufferDesc::tag.

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 313 of file localbuf.c.

320 {
321  BlockNumber first_block;
322  instr_time io_start;
323 
324  /* Initialize local buffers if first request in this session */
325  if (LocalBufHash == NULL)
327 
328  LimitAdditionalLocalPins(&extend_by);
329 
330  for (uint32 i = 0; i < extend_by; i++)
331  {
332  BufferDesc *buf_hdr;
333  Block buf_block;
334 
335  buffers[i] = GetLocalVictimBuffer();
336  buf_hdr = GetLocalBufferDescriptor(-buffers[i] - 1);
337  buf_block = LocalBufHdrGetBlock(buf_hdr);
338 
339  /* new buffers are zero-filled */
340  MemSet((char *) buf_block, 0, BLCKSZ);
341  }
342 
343  first_block = smgrnblocks(bmr.smgr, fork);
344 
345  if (extend_upto != InvalidBlockNumber)
346  {
347  /*
348  * In contrast to shared relations, nothing could change the relation
349  * size concurrently. Thus we shouldn't end up finding that we don't
350  * need to do anything.
351  */
352  Assert(first_block <= extend_upto);
353 
354  Assert((uint64) first_block + extend_by <= extend_upto);
355  }
356 
357  /* Fail if relation is already at maximum possible length */
358  if ((uint64) first_block + extend_by >= MaxBlockNumber)
359  ereport(ERROR,
360  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
361  errmsg("cannot extend relation %s beyond %u blocks",
362  relpath(bmr.smgr->smgr_rlocator, fork),
363  MaxBlockNumber)));
364 
365  for (uint32 i = 0; i < extend_by; i++)
366  {
367  int victim_buf_id;
368  BufferDesc *victim_buf_hdr;
369  BufferTag tag;
370  LocalBufferLookupEnt *hresult;
371  bool found;
372 
373  victim_buf_id = -buffers[i] - 1;
374  victim_buf_hdr = GetLocalBufferDescriptor(victim_buf_id);
375 
376  /* in case we need to pin an existing buffer below */
378 
379  InitBufferTag(&tag, &bmr.smgr->smgr_rlocator.locator, fork, first_block + i);
380 
381  hresult = (LocalBufferLookupEnt *)
382  hash_search(LocalBufHash, (void *) &tag, HASH_ENTER, &found);
383  if (found)
384  {
385  BufferDesc *existing_hdr;
386  uint32 buf_state;
387 
389 
390  existing_hdr = GetLocalBufferDescriptor(hresult->id);
391  PinLocalBuffer(existing_hdr, false);
392  buffers[i] = BufferDescriptorGetBuffer(existing_hdr);
393 
394  buf_state = pg_atomic_read_u32(&existing_hdr->state);
395  Assert(buf_state & BM_TAG_VALID);
396  Assert(!(buf_state & BM_DIRTY));
397  buf_state &= ~BM_VALID;
398  pg_atomic_unlocked_write_u32(&existing_hdr->state, buf_state);
399  }
400  else
401  {
402  uint32 buf_state = pg_atomic_read_u32(&victim_buf_hdr->state);
403 
404  Assert(!(buf_state & (BM_VALID | BM_TAG_VALID | BM_DIRTY | BM_JUST_DIRTIED)));
405 
406  victim_buf_hdr->tag = tag;
407 
408  buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE;
409 
410  pg_atomic_unlocked_write_u32(&victim_buf_hdr->state, buf_state);
411 
412  hresult->id = victim_buf_id;
413  }
414  }
415 
417 
418  /* actually extend relation */
419  smgrzeroextend(bmr.smgr, fork, first_block, extend_by, false);
420 
422  io_start, extend_by);
423 
424  for (uint32 i = 0; i < extend_by; i++)
425  {
426  Buffer buf = buffers[i];
427  BufferDesc *buf_hdr;
428  uint32 buf_state;
429 
430  buf_hdr = GetLocalBufferDescriptor(-buf - 1);
431 
432  buf_state = pg_atomic_read_u32(&buf_hdr->state);
433  buf_state |= BM_VALID;
434  pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state);
435  }
436 
437  *extended_by = extend_by;
438 
439  pgBufferUsage.local_blks_written += extend_by;
440 
441  return first_block;
442 }
uint32 BlockNumber
Definition: block.h:31
#define InvalidBlockNumber
Definition: block.h:33
#define MaxBlockNumber
Definition: block.h:35
static void InitBufferTag(BufferTag *tag, const RelFileLocator *rlocator, ForkNumber forkNum, BlockNumber blockNum)
#define BM_DIRTY
Definition: buf_internals.h:61
#define BM_JUST_DIRTIED
Definition: buf_internals.h:66
#define BUF_USAGECOUNT_ONE
Definition: buf_internals.h:46
#define BM_VALID
Definition: buf_internals.h:62
static Buffer BufferDescriptorGetBuffer(const BufferDesc *bdesc)
bool track_io_timing
Definition: bufmgr.c:138
void * Block
Definition: bufmgr.h:24
#define MemSet(start, val, len)
Definition: c.h:1007
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ereport(elevel,...)
Definition: elog.h:149
@ HASH_ENTER
Definition: hsearch.h:114
BufferUsage pgBufferUsage
Definition: instrument.c:20
void UnpinLocalBuffer(Buffer buffer)
Definition: localbuf.c:681
#define LocalBufHdrGetBlock(bufHdr)
Definition: localbuf.c:39
static void LimitAdditionalLocalPins(uint32 *additional_pins)
Definition: localbuf.c:291
bool PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount)
Definition: localbuf.c:655
static void InitLocalBuffers(void)
Definition: localbuf.c:580
static Buffer GetLocalVictimBuffer(void)
Definition: localbuf.c:178
static char * buf
Definition: pg_test_fsync.c:73
@ IOOBJECT_TEMP_RELATION
Definition: pgstat.h:281
@ IOCONTEXT_NORMAL
Definition: pgstat.h:290
@ IOOP_EXTEND
Definition: pgstat.h:299
instr_time pgstat_prepare_io_time(bool track_io_guc)
Definition: pgstat_io.c:100
void pgstat_count_io_op_time(IOObject io_object, IOContext io_context, IOOp io_op, instr_time start_time, uint32 cnt)
Definition: pgstat_io.c:122
#define relpath(rlocator, forknum)
Definition: relpath.h:94
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition: resowner.c:442
BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:655
void smgrzeroextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, int nblocks, bool skipFsync)
Definition: smgr.c:560
struct SMgrRelationData * smgr
Definition: bufmgr.h:102
int64 local_blks_written
Definition: instrument.h:33
RelFileLocator locator
RelFileLocatorBackend smgr_rlocator
Definition: smgr.h:37

References Assert(), BM_DIRTY, BM_JUST_DIRTIED, BM_TAG_VALID, BM_VALID, buf, BUF_USAGECOUNT_ONE, BufferDescriptorGetBuffer(), CurrentResourceOwner, ereport, errcode(), errmsg(), ERROR, GetLocalBufferDescriptor(), GetLocalVictimBuffer(), HASH_ENTER, hash_search(), i, LocalBufferLookupEnt::id, InitBufferTag(), InitLocalBuffers(), InvalidBlockNumber, IOCONTEXT_NORMAL, IOOBJECT_TEMP_RELATION, IOOP_EXTEND, LimitAdditionalLocalPins(), BufferUsage::local_blks_written, LocalBufHash, LocalBufHdrGetBlock, RelFileLocatorBackend::locator, MaxBlockNumber, MemSet, pg_atomic_read_u32(), pg_atomic_unlocked_write_u32(), pgBufferUsage, pgstat_count_io_op_time(), pgstat_prepare_io_time(), PinLocalBuffer(), relpath, ResourceOwnerEnlarge(), BufferManagerRelation::smgr, SMgrRelationData::smgr_rlocator, smgrnblocks(), smgrzeroextend(), BufferDesc::state, BufferDesc::tag, track_io_timing, and UnpinLocalBuffer().

Referenced by ExtendBufferedRelCommon().

◆ GetLocalBufferStorage()

static Block GetLocalBufferStorage ( void  )
static

Definition at line 728 of file localbuf.c.

729 {
730  static char *cur_block = NULL;
731  static int next_buf_in_block = 0;
732  static int num_bufs_in_block = 0;
733  static int total_bufs_allocated = 0;
734  static MemoryContext LocalBufferContext = NULL;
735 
736  char *this_buf;
737 
738  Assert(total_bufs_allocated < NLocBuffer);
739 
740  if (next_buf_in_block >= num_bufs_in_block)
741  {
742  /* Need to make a new request to memmgr */
743  int num_bufs;
744 
745  /*
746  * We allocate local buffers in a context of their own, so that the
747  * space eaten for them is easily recognizable in MemoryContextStats
748  * output. Create the context on first use.
749  */
750  if (LocalBufferContext == NULL)
751  LocalBufferContext =
753  "LocalBufferContext",
755 
756  /* Start with a 16-buffer request; subsequent ones double each time */
757  num_bufs = Max(num_bufs_in_block * 2, 16);
758  /* But not more than what we need for all remaining local bufs */
759  num_bufs = Min(num_bufs, NLocBuffer - total_bufs_allocated);
760  /* And don't overflow MaxAllocSize, either */
761  num_bufs = Min(num_bufs, MaxAllocSize / BLCKSZ);
762 
763  /* Buffers should be I/O aligned. */
764  cur_block = (char *)
766  MemoryContextAlloc(LocalBufferContext,
767  num_bufs * BLCKSZ + PG_IO_ALIGN_SIZE));
768  next_buf_in_block = 0;
769  num_bufs_in_block = num_bufs;
770  }
771 
772  /* Allocate next buffer in current memory block */
773  this_buf = cur_block + next_buf_in_block * BLCKSZ;
774  next_buf_in_block++;
775  total_bufs_allocated++;
776 
777  return (Block) this_buf;
778 }
#define Min(x, y)
Definition: c.h:991
#define TYPEALIGN(ALIGNVAL, LEN)
Definition: c.h:791
#define Max(x, y)
Definition: c.h:985
MemoryContext TopMemoryContext
Definition: mcxt.c:137
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1168
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
#define MaxAllocSize
Definition: memutils.h:40
#define PG_IO_ALIGN_SIZE

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert(), Max, MaxAllocSize, MemoryContextAlloc(), Min, NLocBuffer, PG_IO_ALIGN_SIZE, TopMemoryContext, and TYPEALIGN.

Referenced by GetLocalVictimBuffer().

◆ GetLocalVictimBuffer()

static Buffer GetLocalVictimBuffer ( void  )
static

Definition at line 178 of file localbuf.c.

179 {
180  int victim_bufid;
181  int trycounter;
182  uint32 buf_state;
183  BufferDesc *bufHdr;
184 
186 
187  /*
188  * Need to get a new buffer. We use a clock sweep algorithm (essentially
189  * the same as what freelist.c does now...)
190  */
191  trycounter = NLocBuffer;
192  for (;;)
193  {
194  victim_bufid = nextFreeLocalBufId;
195 
197  nextFreeLocalBufId = 0;
198 
199  bufHdr = GetLocalBufferDescriptor(victim_bufid);
200 
201  if (LocalRefCount[victim_bufid] == 0)
202  {
203  buf_state = pg_atomic_read_u32(&bufHdr->state);
204 
205  if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0)
206  {
207  buf_state -= BUF_USAGECOUNT_ONE;
208  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
209  trycounter = NLocBuffer;
210  }
211  else
212  {
213  /* Found a usable buffer */
214  PinLocalBuffer(bufHdr, false);
215  break;
216  }
217  }
218  else if (--trycounter == 0)
219  ereport(ERROR,
220  (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
221  errmsg("no empty local buffer available")));
222  }
223 
224  /*
225  * lazy memory allocation: allocate space on first use of a buffer.
226  */
227  if (LocalBufHdrGetBlock(bufHdr) == NULL)
228  {
229  /* Set pointer for use by BufferGetBlock() macro */
231  }
232 
233  /*
234  * this buffer is not referenced but it might still be dirty. if that's
235  * the case, write it out before reusing it!
236  */
237  if (buf_state & BM_DIRTY)
238  {
239  instr_time io_start;
240  SMgrRelation oreln;
241  Page localpage = (char *) LocalBufHdrGetBlock(bufHdr);
242 
243  /* Find smgr relation for buffer */
244  oreln = smgropen(BufTagGetRelFileLocator(&bufHdr->tag), MyProcNumber);
245 
246  PageSetChecksumInplace(localpage, bufHdr->tag.blockNum);
247 
249 
250  /* And write... */
251  smgrwrite(oreln,
252  BufTagGetForkNum(&bufHdr->tag),
253  bufHdr->tag.blockNum,
254  localpage,
255  false);
256 
257  /* Temporary table I/O does not use Buffer Access Strategies */
259  IOOP_WRITE, io_start, 1);
260 
261  /* Mark not-dirty now in case we error out below */
262  buf_state &= ~BM_DIRTY;
263  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
264 
266  }
267 
268  /*
269  * Remove the victim buffer from the hashtable and mark as invalid.
270  */
271  if (buf_state & BM_TAG_VALID)
272  {
273  LocalBufferLookupEnt *hresult;
274 
275  hresult = (LocalBufferLookupEnt *)
276  hash_search(LocalBufHash, &bufHdr->tag, HASH_REMOVE, NULL);
277  if (!hresult) /* shouldn't happen */
278  elog(ERROR, "local buffer hash table corrupted");
279  /* mark buffer invalid just in case hash insert fails */
280  ClearBufferTag(&bufHdr->tag);
281  buf_state &= ~(BUF_FLAG_MASK | BUF_USAGECOUNT_MASK);
282  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
284  }
285 
286  return BufferDescriptorGetBuffer(bufHdr);
287 }
#define BUF_STATE_GET_USAGECOUNT(state)
Definition: buf_internals.h:52
void PageSetChecksumInplace(Page page, BlockNumber blkno)
Definition: bufpage.c:1542
Pointer Page
Definition: bufpage.h:78
static Block GetLocalBufferStorage(void)
Definition: localbuf.c:728
static int nextFreeLocalBufId
Definition: localbuf.c:48
@ IOOP_EVICT
Definition: pgstat.h:298
@ IOOP_WRITE
Definition: pgstat.h:304
void pgstat_count_io_op(IOObject io_object, IOContext io_context, IOOp io_op)
Definition: pgstat_io.c:77
SMgrRelation smgropen(RelFileLocator rlocator, ProcNumber backend)
Definition: smgr.c:198
static void smgrwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, const void *buffer, bool skipFsync)
Definition: smgr.h:121

References buftag::blockNum, BM_DIRTY, BM_TAG_VALID, BUF_FLAG_MASK, BUF_STATE_GET_USAGECOUNT, BUF_USAGECOUNT_MASK, BUF_USAGECOUNT_ONE, BufferDescriptorGetBuffer(), BufTagGetForkNum(), BufTagGetRelFileLocator(), ClearBufferTag(), CurrentResourceOwner, elog, ereport, errcode(), errmsg(), ERROR, GetLocalBufferDescriptor(), GetLocalBufferStorage(), HASH_REMOVE, hash_search(), IOCONTEXT_NORMAL, IOOBJECT_TEMP_RELATION, IOOP_EVICT, IOOP_WRITE, BufferUsage::local_blks_written, LocalBufHash, LocalBufHdrGetBlock, LocalRefCount, MyProcNumber, nextFreeLocalBufId, NLocBuffer, PageSetChecksumInplace(), pg_atomic_read_u32(), pg_atomic_unlocked_write_u32(), pgBufferUsage, pgstat_count_io_op(), pgstat_count_io_op_time(), pgstat_prepare_io_time(), PinLocalBuffer(), ResourceOwnerEnlarge(), smgropen(), smgrwrite(), BufferDesc::state, BufferDesc::tag, and track_io_timing.

Referenced by ExtendBufferedRelLocal(), and LocalBufferAlloc().

◆ InitLocalBuffers()

static void InitLocalBuffers ( void  )
static

Definition at line 580 of file localbuf.c.

581 {
582  int nbufs = num_temp_buffers;
583  HASHCTL info;
584  int i;
585 
586  /*
587  * Parallel workers can't access data in temporary tables, because they
588  * have no visibility into the local buffers of their leader. This is a
589  * convenient, low-cost place to provide a backstop check for that. Note
590  * that we don't wish to prevent a parallel worker from accessing catalog
591  * metadata about a temp table, so checks at higher levels would be
592  * inappropriate.
593  */
594  if (IsParallelWorker())
595  ereport(ERROR,
596  (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
597  errmsg("cannot access temporary tables during a parallel operation")));
598 
599  /* Allocate and zero buffer headers and auxiliary arrays */
600  LocalBufferDescriptors = (BufferDesc *) calloc(nbufs, sizeof(BufferDesc));
601  LocalBufferBlockPointers = (Block *) calloc(nbufs, sizeof(Block));
602  LocalRefCount = (int32 *) calloc(nbufs, sizeof(int32));
604  ereport(FATAL,
605  (errcode(ERRCODE_OUT_OF_MEMORY),
606  errmsg("out of memory")));
607 
608  nextFreeLocalBufId = 0;
609 
610  /* initialize fields that need to start off nonzero */
611  for (i = 0; i < nbufs; i++)
612  {
614 
615  /*
616  * negative to indicate local buffer. This is tricky: shared buffers
617  * start with 0. We have to start with -2. (Note that the routine
618  * BufferDescriptorGetBuffer adds 1 to buf_id so our first buffer id
619  * is -1.)
620  */
621  buf->buf_id = -i - 2;
622 
623  /*
624  * Intentionally do not initialize the buffer's atomic variable
625  * (besides zeroing the underlying memory above). That way we get
626  * errors on platforms without atomics, if somebody (re-)introduces
627  * atomic operations for local buffers.
628  */
629  }
630 
631  /* Create the lookup hash table */
632  info.keysize = sizeof(BufferTag);
633  info.entrysize = sizeof(LocalBufferLookupEnt);
634 
635  LocalBufHash = hash_create("Local Buffer Lookup Table",
636  nbufs,
637  &info,
639 
640  if (!LocalBufHash)
641  elog(ERROR, "could not initialize local buffer hash table");
642 
643  /* Initialization done, mark buffers allocated */
644  NLocBuffer = nbufs;
645 }
struct buftag BufferTag
signed int int32
Definition: c.h:481
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#define FATAL
Definition: elog.h:41
int num_temp_buffers
Definition: guc_tables.c:536
#define calloc(a, b)
Definition: header.h:55
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
#define IsParallelWorker()
Definition: parallel.h:60
Block * LocalBufferBlockPointers
Definition: localbuf.c:45
BufferDesc * LocalBufferDescriptors
Definition: localbuf.c:44
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76

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

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

◆ LimitAdditionalLocalPins()

static void LimitAdditionalLocalPins ( uint32 additional_pins)
static

Definition at line 291 of file localbuf.c.

292 {
293  uint32 max_pins;
294 
295  if (*additional_pins <= 1)
296  return;
297 
298  /*
299  * In contrast to LimitAdditionalPins() other backends don't play a role
300  * here. We can allow up to NLocBuffer pins in total.
301  */
302  max_pins = (NLocBuffer - NLocalPinnedBuffers);
303 
304  if (*additional_pins >= max_pins)
305  *additional_pins = max_pins;
306 }
static int NLocalPinnedBuffers
Definition: localbuf.c:53

References NLocalPinnedBuffers, and NLocBuffer.

Referenced by ExtendBufferedRelLocal().

◆ LocalBufferAlloc()

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

Definition at line 117 of file localbuf.c.

119 {
120  BufferTag newTag; /* identity of requested block */
121  LocalBufferLookupEnt *hresult;
122  BufferDesc *bufHdr;
123  Buffer victim_buffer;
124  int bufid;
125  bool found;
126 
127  InitBufferTag(&newTag, &smgr->smgr_rlocator.locator, forkNum, blockNum);
128 
129  /* Initialize local buffers if first request in this session */
130  if (LocalBufHash == NULL)
132 
134 
135  /* See if the desired buffer already exists */
136  hresult = (LocalBufferLookupEnt *)
137  hash_search(LocalBufHash, &newTag, HASH_FIND, NULL);
138 
139  if (hresult)
140  {
141  bufid = hresult->id;
142  bufHdr = GetLocalBufferDescriptor(bufid);
143  Assert(BufferTagsEqual(&bufHdr->tag, &newTag));
144 
145  *foundPtr = PinLocalBuffer(bufHdr, true);
146  }
147  else
148  {
149  uint32 buf_state;
150 
151  victim_buffer = GetLocalVictimBuffer();
152  bufid = -victim_buffer - 1;
153  bufHdr = GetLocalBufferDescriptor(bufid);
154 
155  hresult = (LocalBufferLookupEnt *)
156  hash_search(LocalBufHash, &newTag, HASH_ENTER, &found);
157  if (found) /* shouldn't happen */
158  elog(ERROR, "local buffer hash table corrupted");
159  hresult->id = bufid;
160 
161  /*
162  * it's all ours now.
163  */
164  bufHdr->tag = newTag;
165 
166  buf_state = pg_atomic_read_u32(&bufHdr->state);
167  buf_state &= ~(BUF_FLAG_MASK | BUF_USAGECOUNT_MASK);
168  buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE;
169  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
170 
171  *foundPtr = false;
172  }
173 
174  return bufHdr;
175 }
static bool BufferTagsEqual(const BufferTag *tag1, const BufferTag *tag2)
@ HASH_FIND
Definition: hsearch.h:113

References Assert(), BM_TAG_VALID, BUF_FLAG_MASK, BUF_USAGECOUNT_MASK, BUF_USAGECOUNT_ONE, BufferTagsEqual(), CurrentResourceOwner, elog, ERROR, GetLocalBufferDescriptor(), GetLocalVictimBuffer(), HASH_ENTER, HASH_FIND, hash_search(), LocalBufferLookupEnt::id, InitBufferTag(), InitLocalBuffers(), LocalBufHash, RelFileLocatorBackend::locator, pg_atomic_read_u32(), pg_atomic_unlocked_write_u32(), PinLocalBuffer(), ResourceOwnerEnlarge(), SMgrRelationData::smgr_rlocator, BufferDesc::state, and BufferDesc::tag.

Referenced by ReadBuffer_common().

◆ MarkLocalBufferDirty()

void MarkLocalBufferDirty ( Buffer  buffer)

Definition at line 449 of file localbuf.c.

450 {
451  int bufid;
452  BufferDesc *bufHdr;
453  uint32 buf_state;
454 
455  Assert(BufferIsLocal(buffer));
456 
457 #ifdef LBDEBUG
458  fprintf(stderr, "LB DIRTY %d\n", buffer);
459 #endif
460 
461  bufid = -buffer - 1;
462 
463  Assert(LocalRefCount[bufid] > 0);
464 
465  bufHdr = GetLocalBufferDescriptor(bufid);
466 
467  buf_state = pg_atomic_read_u32(&bufHdr->state);
468 
469  if (!(buf_state & BM_DIRTY))
471 
472  buf_state |= BM_DIRTY;
473 
474  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
475 }
#define BufferIsLocal(buffer)
Definition: buf.h:37
#define fprintf
Definition: port.h:242
int64 local_blks_dirtied
Definition: instrument.h:32

References Assert(), BM_DIRTY, BufferIsLocal, fprintf, GetLocalBufferDescriptor(), BufferUsage::local_blks_dirtied, LocalRefCount, pg_atomic_read_u32(), pg_atomic_unlocked_write_u32(), pgBufferUsage, and BufferDesc::state.

Referenced by MarkBufferDirty(), and MarkBufferDirtyHint().

◆ PinLocalBuffer()

bool PinLocalBuffer ( BufferDesc buf_hdr,
bool  adjust_usagecount 
)

Definition at line 655 of file localbuf.c.

656 {
657  uint32 buf_state;
658  Buffer buffer = BufferDescriptorGetBuffer(buf_hdr);
659  int bufid = -buffer - 1;
660 
661  buf_state = pg_atomic_read_u32(&buf_hdr->state);
662 
663  if (LocalRefCount[bufid] == 0)
664  {
666  if (adjust_usagecount &&
668  {
669  buf_state += BUF_USAGECOUNT_ONE;
670  pg_atomic_unlocked_write_u32(&buf_hdr->state, buf_state);
671  }
672  }
673  LocalRefCount[bufid]++;
675  BufferDescriptorGetBuffer(buf_hdr));
676 
677  return buf_state & BM_VALID;
678 }
#define BM_MAX_USAGE_COUNT
Definition: buf_internals.h:78
void ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)

References BM_MAX_USAGE_COUNT, BM_VALID, BUF_STATE_GET_USAGECOUNT, BUF_USAGECOUNT_ONE, BufferDescriptorGetBuffer(), CurrentResourceOwner, LocalRefCount, NLocalPinnedBuffers, pg_atomic_read_u32(), pg_atomic_unlocked_write_u32(), ResourceOwnerRememberBuffer(), and BufferDesc::state.

Referenced by ExtendBufferedRelLocal(), GetLocalVictimBuffer(), LocalBufferAlloc(), and ReadRecentBuffer().

◆ PrefetchLocalBuffer()

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

Definition at line 69 of file localbuf.c.

71 {
72  PrefetchBufferResult result = {InvalidBuffer, false};
73  BufferTag newTag; /* identity of requested block */
74  LocalBufferLookupEnt *hresult;
75 
76  InitBufferTag(&newTag, &smgr->smgr_rlocator.locator, forkNum, blockNum);
77 
78  /* Initialize local buffers if first request in this session */
79  if (LocalBufHash == NULL)
81 
82  /* See if the desired buffer already exists */
83  hresult = (LocalBufferLookupEnt *)
84  hash_search(LocalBufHash, &newTag, HASH_FIND, NULL);
85 
86  if (hresult)
87  {
88  /* Yes, so nothing to do */
89  result.recent_buffer = -hresult->id - 1;
90  }
91  else
92  {
93 #ifdef USE_PREFETCH
94  /* Not in buffers, so initiate prefetch */
95  if ((io_direct_flags & IO_DIRECT_DATA) == 0 &&
96  smgrprefetch(smgr, forkNum, blockNum, 1))
97  {
98  result.initiated_io = true;
99  }
100 #endif /* USE_PREFETCH */
101  }
102 
103  return result;
104 }
#define InvalidBuffer
Definition: buf.h:25
int io_direct_flags
Definition: fd.c:168
#define IO_DIRECT_DATA
Definition: fd.h:54
bool smgrprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, int nblocks)
Definition: smgr.c:585
Buffer recent_buffer
Definition: bufmgr.h:59

References HASH_FIND, hash_search(), LocalBufferLookupEnt::id, InitBufferTag(), PrefetchBufferResult::initiated_io, InitLocalBuffers(), InvalidBuffer, IO_DIRECT_DATA, io_direct_flags, LocalBufHash, RelFileLocatorBackend::locator, PrefetchBufferResult::recent_buffer, SMgrRelationData::smgr_rlocator, and smgrprefetch().

Referenced by PrefetchBuffer().

◆ UnpinLocalBuffer()

void UnpinLocalBuffer ( Buffer  buffer)

Definition at line 681 of file localbuf.c.

682 {
683  UnpinLocalBufferNoOwner(buffer);
685 }
void UnpinLocalBufferNoOwner(Buffer buffer)
Definition: localbuf.c:688
void ResourceOwnerForgetBuffer(ResourceOwner owner, Buffer buffer)

References CurrentResourceOwner, ResourceOwnerForgetBuffer(), and UnpinLocalBufferNoOwner().

Referenced by ExtendBufferedRelLocal(), ReleaseAndReadBuffer(), and ReleaseBuffer().

◆ UnpinLocalBufferNoOwner()

void UnpinLocalBufferNoOwner ( Buffer  buffer)

Definition at line 688 of file localbuf.c.

689 {
690  int buffid = -buffer - 1;
691 
692  Assert(BufferIsLocal(buffer));
693  Assert(LocalRefCount[buffid] > 0);
695 
696  if (--LocalRefCount[buffid] == 0)
698 }

References Assert(), BufferIsLocal, LocalRefCount, and NLocalPinnedBuffers.

Referenced by ResOwnerReleaseBufferPin(), and UnpinLocalBuffer().

Variable Documentation

◆ LocalBufferBlockPointers

Block* LocalBufferBlockPointers = NULL

Definition at line 45 of file localbuf.c.

Referenced by BufferGetBlock(), and InitLocalBuffers().

◆ LocalBufferDescriptors

BufferDesc* LocalBufferDescriptors = NULL

Definition at line 44 of file localbuf.c.

Referenced by GetLocalBufferDescriptor(), and InitLocalBuffers().

◆ LocalBufHash

◆ LocalRefCount

◆ nextFreeLocalBufId

int nextFreeLocalBufId = 0
static

Definition at line 48 of file localbuf.c.

Referenced by GetLocalVictimBuffer(), and InitLocalBuffers().

◆ NLocalPinnedBuffers

int NLocalPinnedBuffers = 0
static

Definition at line 53 of file localbuf.c.

Referenced by LimitAdditionalLocalPins(), PinLocalBuffer(), and UnpinLocalBufferNoOwner().

◆ NLocBuffer