PostgreSQL Source Code  git master
localbuf.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * localbuf.c
4  * local buffer manager. Fast buffer manager for temporary tables,
5  * which never need to be WAL-logged or checkpointed, etc.
6  *
7  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994-5, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  * src/backend/storage/buffer/localbuf.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17 
18 #include "access/parallel.h"
19 #include "catalog/catalog.h"
20 #include "executor/instrument.h"
21 #include "pgstat.h"
22 #include "storage/buf_internals.h"
23 #include "storage/bufmgr.h"
24 #include "utils/guc_hooks.h"
25 #include "utils/memutils.h"
26 #include "utils/resowner_private.h"
27 
28 
29 /*#define LBDEBUG*/
30 
31 /* entry for buffer lookup hashtable */
32 typedef struct
33 {
34  BufferTag key; /* Tag of a disk page */
35  int id; /* Associated local buffer's index */
37 
38 /* Note: this macro only works on local buffers, not shared ones! */
39 #define LocalBufHdrGetBlock(bufHdr) \
40  LocalBufferBlockPointers[-((bufHdr)->buf_id + 2)]
41 
42 int NLocBuffer = 0; /* until buffers are initialized */
43 
47 
48 static int nextFreeLocalBuf = 0;
49 
50 static HTAB *LocalBufHash = NULL;
51 
52 
53 static void InitLocalBuffers(void);
54 static Block GetLocalBufferStorage(void);
55 
56 
57 /*
58  * PrefetchLocalBuffer -
59  * initiate asynchronous read of a block of a relation
60  *
61  * Do PrefetchBuffer's work for temporary relations.
62  * No-op if prefetching isn't compiled in.
63  */
66  BlockNumber blockNum)
67 {
68  PrefetchBufferResult result = {InvalidBuffer, false};
69  BufferTag newTag; /* identity of requested block */
70  LocalBufferLookupEnt *hresult;
71 
72  InitBufferTag(&newTag, &smgr->smgr_rlocator.locator, forkNum, blockNum);
73 
74  /* Initialize local buffers if first request in this session */
75  if (LocalBufHash == NULL)
77 
78  /* See if the desired buffer already exists */
79  hresult = (LocalBufferLookupEnt *)
80  hash_search(LocalBufHash, &newTag, HASH_FIND, NULL);
81 
82  if (hresult)
83  {
84  /* Yes, so nothing to do */
85  result.recent_buffer = -hresult->id - 1;
86  }
87  else
88  {
89 #ifdef USE_PREFETCH
90  /* Not in buffers, so initiate prefetch */
91  smgrprefetch(smgr, forkNum, blockNum);
92  result.initiated_io = true;
93 #endif /* USE_PREFETCH */
94  }
95 
96  return result;
97 }
98 
99 
100 /*
101  * LocalBufferAlloc -
102  * Find or create a local buffer for the given page of the given relation.
103  *
104  * API is similar to bufmgr.c's BufferAlloc, except that we do not need
105  * to do any locking since this is all local. Also, IO_IN_PROGRESS
106  * does not get set. Lastly, we support only default access strategy
107  * (hence, usage_count is always advanced).
108  */
109 BufferDesc *
111  bool *foundPtr, IOContext *io_context)
112 {
113  BufferTag newTag; /* identity of requested block */
114  LocalBufferLookupEnt *hresult;
115  BufferDesc *bufHdr;
116  int b;
117  int trycounter;
118  bool found;
119  uint32 buf_state;
120 
121  InitBufferTag(&newTag, &smgr->smgr_rlocator.locator, forkNum, blockNum);
122 
123  /* Initialize local buffers if first request in this session */
124  if (LocalBufHash == NULL)
126 
127  /* See if the desired buffer already exists */
128  hresult = (LocalBufferLookupEnt *)
129  hash_search(LocalBufHash, &newTag, HASH_FIND, NULL);
130 
131  /*
132  * IO Operations on local buffers are only done in IOCONTEXT_NORMAL. Set
133  * io_context here (instead of after a buffer hit would have returned) for
134  * convenience since we don't have to worry about the overhead of calling
135  * IOContextForStrategy().
136  */
137  *io_context = IOCONTEXT_NORMAL;
138 
139  if (hresult)
140  {
141  b = hresult->id;
142  bufHdr = GetLocalBufferDescriptor(b);
143  Assert(BufferTagsEqual(&bufHdr->tag, &newTag));
144 #ifdef LBDEBUG
145  fprintf(stderr, "LB ALLOC (%u,%d,%d) %d\n",
146  smgr->smgr_rlocator.locator.relNumber, forkNum, blockNum, -b - 1);
147 #endif
148  buf_state = pg_atomic_read_u32(&bufHdr->state);
149 
150  /* this part is equivalent to PinBuffer for a shared buffer */
151  if (LocalRefCount[b] == 0)
152  {
154  {
155  buf_state += BUF_USAGECOUNT_ONE;
156  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
157  }
158  }
159  LocalRefCount[b]++;
161  BufferDescriptorGetBuffer(bufHdr));
162  if (buf_state & BM_VALID)
163  *foundPtr = true;
164  else
165  {
166  /* Previous read attempt must have failed; try again */
167  *foundPtr = false;
168  }
169  return bufHdr;
170  }
171 
172 #ifdef LBDEBUG
173  fprintf(stderr, "LB ALLOC (%u,%d,%d) %d\n",
174  smgr->smgr_rlocator.locator.relNumber, forkNum, blockNum,
175  -nextFreeLocalBuf - 1);
176 #endif
177 
178  /*
179  * Need to get a new buffer. We use a clock sweep algorithm (essentially
180  * the same as what freelist.c does now...)
181  */
182  trycounter = NLocBuffer;
183  for (;;)
184  {
186 
187  if (++nextFreeLocalBuf >= NLocBuffer)
188  nextFreeLocalBuf = 0;
189 
190  bufHdr = GetLocalBufferDescriptor(b);
191 
192  if (LocalRefCount[b] == 0)
193  {
194  buf_state = pg_atomic_read_u32(&bufHdr->state);
195 
196  if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0)
197  {
198  buf_state -= BUF_USAGECOUNT_ONE;
199  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
200  trycounter = NLocBuffer;
201  }
202  else
203  {
204  /* Found a usable buffer */
205  LocalRefCount[b]++;
207  BufferDescriptorGetBuffer(bufHdr));
208  break;
209  }
210  }
211  else if (--trycounter == 0)
212  ereport(ERROR,
213  (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
214  errmsg("no empty local buffer available")));
215  }
216 
217  /*
218  * this buffer is not referenced but it might still be dirty. if that's
219  * the case, write it out before reusing it!
220  */
221  if (buf_state & BM_DIRTY)
222  {
223  SMgrRelation oreln;
224  Page localpage = (char *) LocalBufHdrGetBlock(bufHdr);
225 
226  /* Find smgr relation for buffer */
227  oreln = smgropen(BufTagGetRelFileLocator(&bufHdr->tag), MyBackendId);
228 
229  PageSetChecksumInplace(localpage, bufHdr->tag.blockNum);
230 
231  /* And write... */
232  smgrwrite(oreln,
233  BufTagGetForkNum(&bufHdr->tag),
234  bufHdr->tag.blockNum,
235  localpage,
236  false);
237 
238  /* Mark not-dirty now in case we error out below */
239  buf_state &= ~BM_DIRTY;
240  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
241 
244  }
245 
246  /*
247  * lazy memory allocation: allocate space on first use of a buffer.
248  */
249  if (LocalBufHdrGetBlock(bufHdr) == NULL)
250  {
251  /* Set pointer for use by BufferGetBlock() macro */
253  }
254 
255  /*
256  * Update the hash table: remove old entry, if any, and make new one.
257  */
258  if (buf_state & BM_TAG_VALID)
259  {
260  hresult = (LocalBufferLookupEnt *)
261  hash_search(LocalBufHash, &bufHdr->tag, HASH_REMOVE, NULL);
262  if (!hresult) /* shouldn't happen */
263  elog(ERROR, "local buffer hash table corrupted");
264  /* mark buffer invalid just in case hash insert fails */
265  ClearBufferTag(&bufHdr->tag);
266  buf_state &= ~(BM_VALID | BM_TAG_VALID);
267  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
269  }
270 
271  hresult = (LocalBufferLookupEnt *)
272  hash_search(LocalBufHash, &newTag, HASH_ENTER, &found);
273  if (found) /* shouldn't happen */
274  elog(ERROR, "local buffer hash table corrupted");
275  hresult->id = b;
276 
277  /*
278  * it's all ours now.
279  */
280  bufHdr->tag = newTag;
281  buf_state &= ~(BM_VALID | BM_DIRTY | BM_JUST_DIRTIED | BM_IO_ERROR);
282  buf_state |= BM_TAG_VALID;
283  buf_state &= ~BUF_USAGECOUNT_MASK;
284  buf_state += BUF_USAGECOUNT_ONE;
285  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
286 
287  *foundPtr = false;
288  return bufHdr;
289 }
290 
291 /*
292  * MarkLocalBufferDirty -
293  * mark a local buffer dirty
294  */
295 void
297 {
298  int bufid;
299  BufferDesc *bufHdr;
300  uint32 buf_state;
301 
302  Assert(BufferIsLocal(buffer));
303 
304 #ifdef LBDEBUG
305  fprintf(stderr, "LB DIRTY %d\n", buffer);
306 #endif
307 
308  bufid = -(buffer + 1);
309 
310  Assert(LocalRefCount[bufid] > 0);
311 
312  bufHdr = GetLocalBufferDescriptor(bufid);
313 
314  buf_state = pg_atomic_read_u32(&bufHdr->state);
315 
316  if (!(buf_state & BM_DIRTY))
318 
319  buf_state |= BM_DIRTY;
320 
321  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
322 }
323 
324 /*
325  * DropRelationLocalBuffers
326  * This function removes from the buffer pool all the pages of the
327  * specified relation that have block numbers >= firstDelBlock.
328  * (In particular, with firstDelBlock = 0, all pages are removed.)
329  * Dirty pages are simply dropped, without bothering to write them
330  * out first. Therefore, this is NOT rollback-able, and so should be
331  * used only with extreme caution!
332  *
333  * See DropRelationBuffers in bufmgr.c for more notes.
334  */
335 void
337  BlockNumber firstDelBlock)
338 {
339  int i;
340 
341  for (i = 0; i < NLocBuffer; i++)
342  {
344  LocalBufferLookupEnt *hresult;
345  uint32 buf_state;
346 
347  buf_state = pg_atomic_read_u32(&bufHdr->state);
348 
349  if ((buf_state & BM_TAG_VALID) &&
350  BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator) &&
351  BufTagGetForkNum(&bufHdr->tag) == forkNum &&
352  bufHdr->tag.blockNum >= firstDelBlock)
353  {
354  if (LocalRefCount[i] != 0)
355  elog(ERROR, "block %u of %s is still referenced (local %u)",
356  bufHdr->tag.blockNum,
358  MyBackendId,
359  BufTagGetForkNum(&bufHdr->tag)),
360  LocalRefCount[i]);
361 
362  /* Remove entry from hashtable */
363  hresult = (LocalBufferLookupEnt *)
364  hash_search(LocalBufHash, &bufHdr->tag, HASH_REMOVE, NULL);
365  if (!hresult) /* shouldn't happen */
366  elog(ERROR, "local buffer hash table corrupted");
367  /* Mark buffer invalid */
368  ClearBufferTag(&bufHdr->tag);
369  buf_state &= ~BUF_FLAG_MASK;
370  buf_state &= ~BUF_USAGECOUNT_MASK;
371  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
372  }
373  }
374 }
375 
376 /*
377  * DropRelationAllLocalBuffers
378  * This function removes from the buffer pool all pages of all forks
379  * of the specified relation.
380  *
381  * See DropRelationsAllBuffers in bufmgr.c for more notes.
382  */
383 void
385 {
386  int i;
387 
388  for (i = 0; i < NLocBuffer; i++)
389  {
391  LocalBufferLookupEnt *hresult;
392  uint32 buf_state;
393 
394  buf_state = pg_atomic_read_u32(&bufHdr->state);
395 
396  if ((buf_state & BM_TAG_VALID) &&
397  BufTagMatchesRelFileLocator(&bufHdr->tag, &rlocator))
398  {
399  if (LocalRefCount[i] != 0)
400  elog(ERROR, "block %u of %s is still referenced (local %u)",
401  bufHdr->tag.blockNum,
403  MyBackendId,
404  BufTagGetForkNum(&bufHdr->tag)),
405  LocalRefCount[i]);
406  /* Remove entry from hashtable */
407  hresult = (LocalBufferLookupEnt *)
408  hash_search(LocalBufHash, &bufHdr->tag, HASH_REMOVE, NULL);
409  if (!hresult) /* shouldn't happen */
410  elog(ERROR, "local buffer hash table corrupted");
411  /* Mark buffer invalid */
412  ClearBufferTag(&bufHdr->tag);
413  buf_state &= ~BUF_FLAG_MASK;
414  buf_state &= ~BUF_USAGECOUNT_MASK;
415  pg_atomic_unlocked_write_u32(&bufHdr->state, buf_state);
416  }
417  }
418 }
419 
420 /*
421  * InitLocalBuffers -
422  * init the local buffer cache. Since most queries (esp. multi-user ones)
423  * don't involve local buffers, we delay allocating actual memory for the
424  * buffers until we need them; just make the buffer headers here.
425  */
426 static void
428 {
429  int nbufs = num_temp_buffers;
430  HASHCTL info;
431  int i;
432 
433  /*
434  * Parallel workers can't access data in temporary tables, because they
435  * have no visibility into the local buffers of their leader. This is a
436  * convenient, low-cost place to provide a backstop check for that. Note
437  * that we don't wish to prevent a parallel worker from accessing catalog
438  * metadata about a temp table, so checks at higher levels would be
439  * inappropriate.
440  */
441  if (IsParallelWorker())
442  ereport(ERROR,
443  (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
444  errmsg("cannot access temporary tables during a parallel operation")));
445 
446  /* Allocate and zero buffer headers and auxiliary arrays */
447  LocalBufferDescriptors = (BufferDesc *) calloc(nbufs, sizeof(BufferDesc));
448  LocalBufferBlockPointers = (Block *) calloc(nbufs, sizeof(Block));
449  LocalRefCount = (int32 *) calloc(nbufs, sizeof(int32));
451  ereport(FATAL,
452  (errcode(ERRCODE_OUT_OF_MEMORY),
453  errmsg("out of memory")));
454 
455  nextFreeLocalBuf = 0;
456 
457  /* initialize fields that need to start off nonzero */
458  for (i = 0; i < nbufs; i++)
459  {
461 
462  /*
463  * negative to indicate local buffer. This is tricky: shared buffers
464  * start with 0. We have to start with -2. (Note that the routine
465  * BufferDescriptorGetBuffer adds 1 to buf_id so our first buffer id
466  * is -1.)
467  */
468  buf->buf_id = -i - 2;
469 
470  /*
471  * Intentionally do not initialize the buffer's atomic variable
472  * (besides zeroing the underlying memory above). That way we get
473  * errors on platforms without atomics, if somebody (re-)introduces
474  * atomic operations for local buffers.
475  */
476  }
477 
478  /* Create the lookup hash table */
479  info.keysize = sizeof(BufferTag);
480  info.entrysize = sizeof(LocalBufferLookupEnt);
481 
482  LocalBufHash = hash_create("Local Buffer Lookup Table",
483  nbufs,
484  &info,
486 
487  if (!LocalBufHash)
488  elog(ERROR, "could not initialize local buffer hash table");
489 
490  /* Initialization done, mark buffers allocated */
491  NLocBuffer = nbufs;
492 }
493 
494 /*
495  * GUC check_hook for temp_buffers
496  */
497 bool
499 {
500  /*
501  * Once local buffers have been initialized, it's too late to change this.
502  * However, if this is only a test call, allow it.
503  */
504  if (source != PGC_S_TEST && NLocBuffer && NLocBuffer != *newval)
505  {
506  GUC_check_errdetail("\"temp_buffers\" cannot be changed after any temporary tables have been accessed in the session.");
507  return false;
508  }
509  return true;
510 }
511 
512 /*
513  * GetLocalBufferStorage - allocate memory for a local buffer
514  *
515  * The idea of this function is to aggregate our requests for storage
516  * so that the memory manager doesn't see a whole lot of relatively small
517  * requests. Since we'll never give back a local buffer once it's created
518  * within a particular process, no point in burdening memmgr with separately
519  * managed chunks.
520  */
521 static Block
523 {
524  static char *cur_block = NULL;
525  static int next_buf_in_block = 0;
526  static int num_bufs_in_block = 0;
527  static int total_bufs_allocated = 0;
528  static MemoryContext LocalBufferContext = NULL;
529 
530  char *this_buf;
531 
532  Assert(total_bufs_allocated < NLocBuffer);
533 
534  if (next_buf_in_block >= num_bufs_in_block)
535  {
536  /* Need to make a new request to memmgr */
537  int num_bufs;
538 
539  /*
540  * We allocate local buffers in a context of their own, so that the
541  * space eaten for them is easily recognizable in MemoryContextStats
542  * output. Create the context on first use.
543  */
544  if (LocalBufferContext == NULL)
545  LocalBufferContext =
547  "LocalBufferContext",
549 
550  /* Start with a 16-buffer request; subsequent ones double each time */
551  num_bufs = Max(num_bufs_in_block * 2, 16);
552  /* But not more than what we need for all remaining local bufs */
553  num_bufs = Min(num_bufs, NLocBuffer - total_bufs_allocated);
554  /* And don't overflow MaxAllocSize, either */
555  num_bufs = Min(num_bufs, MaxAllocSize / BLCKSZ);
556 
557  cur_block = (char *) MemoryContextAlloc(LocalBufferContext,
558  num_bufs * BLCKSZ);
559  next_buf_in_block = 0;
560  num_bufs_in_block = num_bufs;
561  }
562 
563  /* Allocate next buffer in current memory block */
564  this_buf = cur_block + next_buf_in_block * BLCKSZ;
565  next_buf_in_block++;
566  total_bufs_allocated++;
567 
568  return (Block) this_buf;
569 }
570 
571 /*
572  * CheckForLocalBufferLeaks - ensure this backend holds no local buffer pins
573  *
574  * This is just like CheckForBufferLeaks(), but for local buffers.
575  */
576 static void
578 {
579 #ifdef USE_ASSERT_CHECKING
580  if (LocalRefCount)
581  {
582  int RefCountErrors = 0;
583  int i;
584 
585  for (i = 0; i < NLocBuffer; i++)
586  {
587  if (LocalRefCount[i] != 0)
588  {
589  Buffer b = -i - 1;
590 
592  RefCountErrors++;
593  }
594  }
595  Assert(RefCountErrors == 0);
596  }
597 #endif
598 }
599 
600 /*
601  * AtEOXact_LocalBuffers - clean up at end of transaction.
602  *
603  * This is just like AtEOXact_Buffers, but for local buffers.
604  */
605 void
606 AtEOXact_LocalBuffers(bool isCommit)
607 {
609 }
610 
611 /*
612  * AtProcExit_LocalBuffers - ensure we have dropped pins during backend exit.
613  *
614  * This is just like AtProcExit_Buffers, but for local buffers.
615  */
616 void
618 {
619  /*
620  * We shouldn't be holding any remaining pins; if we are, and assertions
621  * aren't enabled, we'll fail later in DropRelationBuffers while trying to
622  * drop the temp rels.
623  */
625 }
static void pg_atomic_unlocked_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:272
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition: atomics.h:236
uint32 BlockNumber
Definition: block.h:31
int Buffer
Definition: buf.h:23
#define InvalidBuffer
Definition: buf.h:25
#define BufferIsLocal(buffer)
Definition: buf.h:37
#define BM_MAX_USAGE_COUNT
Definition: buf_internals.h:77
static void InitBufferTag(BufferTag *tag, const RelFileLocator *rlocator, ForkNumber forkNum, BlockNumber blockNum)
#define BM_TAG_VALID
Definition: buf_internals.h:62
#define BUF_USAGECOUNT_MASK
Definition: buf_internals.h:44
static ForkNumber BufTagGetForkNum(const BufferTag *tag)
static BufferDesc * GetLocalBufferDescriptor(uint32 id)
static bool BufferTagsEqual(const BufferTag *tag1, const BufferTag *tag2)
static bool BufTagMatchesRelFileLocator(const BufferTag *tag, const RelFileLocator *rlocator)
#define BUF_FLAG_MASK
Definition: buf_internals.h:47
#define BM_DIRTY
Definition: buf_internals.h:60
#define BM_JUST_DIRTIED
Definition: buf_internals.h:65
#define BUF_STATE_GET_USAGECOUNT(state)
Definition: buf_internals.h:51
static void ClearBufferTag(BufferTag *tag)
struct buftag BufferTag
#define BUF_USAGECOUNT_ONE
Definition: buf_internals.h:45
static RelFileLocator BufTagGetRelFileLocator(const BufferTag *tag)
#define BM_VALID
Definition: buf_internals.h:61
#define BM_IO_ERROR
Definition: buf_internals.h:64
static Buffer BufferDescriptorGetBuffer(const BufferDesc *bdesc)
void PrintBufferLeakWarning(Buffer buffer)
Definition: bufmgr.c:2743
void * Block
Definition: bufmgr.h:24
void PageSetChecksumInplace(Page page, BlockNumber blkno)
Definition: bufpage.c:1539
Pointer Page
Definition: bufpage.h:78
unsigned int uint32
Definition: c.h:490
#define Min(x, y)
Definition: c.h:988
signed int int32
Definition: c.h:478
#define Max(x, y)
Definition: c.h:982
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:350
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define FATAL
Definition: elog.h:41
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
BackendId MyBackendId
Definition: globals.c:85
#define newval
#define GUC_check_errdetail
Definition: guc.h:437
GucSource
Definition: guc.h:108
@ PGC_S_TEST
Definition: guc.h:121
int num_temp_buffers
Definition: guc_tables.c:507
#define calloc(a, b)
Definition: header.h:55
@ HASH_FIND
Definition: hsearch.h:113
@ HASH_REMOVE
Definition: hsearch.h:115
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
#define IsParallelWorker()
Definition: parallel.h:61
BufferUsage pgBufferUsage
Definition: instrument.c:20
int b
Definition: isn.c:70
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
int32 * LocalRefCount
Definition: localbuf.c:46
static HTAB * LocalBufHash
Definition: localbuf.c:50
void AtEOXact_LocalBuffers(bool isCommit)
Definition: localbuf.c:606
#define LocalBufHdrGetBlock(bufHdr)
Definition: localbuf.c:39
static void CheckForLocalBufferLeaks(void)
Definition: localbuf.c:577
void DropRelationLocalBuffers(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber firstDelBlock)
Definition: localbuf.c:336
static Block GetLocalBufferStorage(void)
Definition: localbuf.c:522
bool check_temp_buffers(int *newval, void **extra, GucSource source)
Definition: localbuf.c:498
void AtProcExit_LocalBuffers(void)
Definition: localbuf.c:617
BufferDesc * LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum, bool *foundPtr, IOContext *io_context)
Definition: localbuf.c:110
static void InitLocalBuffers(void)
Definition: localbuf.c:427
void MarkLocalBufferDirty(Buffer buffer)
Definition: localbuf.c:296
void DropRelationAllLocalBuffers(RelFileLocator rlocator)
Definition: localbuf.c:384
int NLocBuffer
Definition: localbuf.c:42
PrefetchBufferResult PrefetchLocalBuffer(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum)
Definition: localbuf.c:65
Block * LocalBufferBlockPointers
Definition: localbuf.c:45
BufferDesc * LocalBufferDescriptors
Definition: localbuf.c:44
static int nextFreeLocalBuf
Definition: localbuf.c:48
MemoryContext TopMemoryContext
Definition: mcxt.c:141
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1005
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
#define MaxAllocSize
Definition: memutils.h:40
static rewind_source * source
Definition: pg_rewind.c:87
static char * buf
Definition: pg_test_fsync.c:67
@ IOOBJECT_TEMP_RELATION
Definition: pgstat.h:278
IOContext
Definition: pgstat.h:284
@ IOCONTEXT_NORMAL
Definition: pgstat.h:287
@ IOOP_EVICT
Definition: pgstat.h:295
@ IOOP_WRITE
Definition: pgstat.h:300
void pgstat_count_io_op(IOObject io_object, IOContext io_context, IOOp io_op)
Definition: pgstat_io.c:66
#define fprintf
Definition: port.h:242
ForkNumber
Definition: relpath.h:48
#define relpathbackend(rlocator, backend, forknum)
Definition: relpath.h:85
ResourceOwner CurrentResourceOwner
Definition: resowner.c:146
void ResourceOwnerRememberBuffer(ResourceOwner owner, Buffer buffer)
Definition: resowner.c:963
bool smgrprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum)
Definition: smgr.c:518
void smgrwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, const void *buffer, bool skipFsync)
Definition: smgr.c:554
SMgrRelation smgropen(RelFileLocator rlocator, BackendId backend)
Definition: smgr.c:146
BufferTag tag
pg_atomic_uint32 state
int64 local_blks_written
Definition: instrument.h:33
int64 local_blks_dirtied
Definition: instrument.h:32
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
Definition: dynahash.c:220
Buffer recent_buffer
Definition: bufmgr.h:59
RelFileLocator locator
RelFileNumber relNumber
RelFileLocatorBackend smgr_rlocator
Definition: smgr.h:42
BlockNumber blockNum
Definition: buf_internals.h:97