PostgreSQL Source Code  git master
hio.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/hio.h"
#include "access/htup_details.h"
#include "access/visibilitymap.h"
#include "storage/bufmgr.h"
#include "storage/freespace.h"
#include "storage/lmgr.h"
#include "storage/smgr.h"
Include dependency graph for hio.c:

Go to the source code of this file.

Functions

void RelationPutHeapTuple (Relation relation, Buffer buffer, HeapTuple tuple, bool token)
 
static Buffer ReadBufferBI (Relation relation, BlockNumber targetBlock, ReadBufferMode mode, BulkInsertState bistate)
 
static void GetVisibilityMapPins (Relation relation, Buffer buffer1, Buffer buffer2, BlockNumber block1, BlockNumber block2, Buffer *vmbuffer1, Buffer *vmbuffer2)
 
static void RelationAddExtraBlocks (Relation relation, BulkInsertState bistate)
 
Buffer RelationGetBufferForTuple (Relation relation, Size len, Buffer otherBuffer, int options, BulkInsertState bistate, Buffer *vmbuffer, Buffer *vmbuffer_other)
 

Function Documentation

◆ GetVisibilityMapPins()

static void GetVisibilityMapPins ( Relation  relation,
Buffer  buffer1,
Buffer  buffer2,
BlockNumber  block1,
BlockNumber  block2,
Buffer vmbuffer1,
Buffer vmbuffer2 
)
static

Definition at line 141 of file hio.c.

References Assert, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetPage, BufferIsValid, InvalidBuffer, LockBuffer(), PageIsAllVisible, visibilitymap_pin(), and visibilitymap_pin_ok().

Referenced by RelationGetBufferForTuple().

144 {
145  bool need_to_pin_buffer1;
146  bool need_to_pin_buffer2;
147 
148  Assert(BufferIsValid(buffer1));
149  Assert(buffer2 == InvalidBuffer || block1 <= block2);
150 
151  while (1)
152  {
153  /* Figure out which pins we need but don't have. */
154  need_to_pin_buffer1 = PageIsAllVisible(BufferGetPage(buffer1))
155  && !visibilitymap_pin_ok(block1, *vmbuffer1);
156  need_to_pin_buffer2 = buffer2 != InvalidBuffer
157  && PageIsAllVisible(BufferGetPage(buffer2))
158  && !visibilitymap_pin_ok(block2, *vmbuffer2);
159  if (!need_to_pin_buffer1 && !need_to_pin_buffer2)
160  return;
161 
162  /* We must unlock both buffers before doing any I/O. */
163  LockBuffer(buffer1, BUFFER_LOCK_UNLOCK);
164  if (buffer2 != InvalidBuffer && buffer2 != buffer1)
165  LockBuffer(buffer2, BUFFER_LOCK_UNLOCK);
166 
167  /* Get pins. */
168  if (need_to_pin_buffer1)
169  visibilitymap_pin(relation, block1, vmbuffer1);
170  if (need_to_pin_buffer2)
171  visibilitymap_pin(relation, block2, vmbuffer2);
172 
173  /* Relock buffers. */
175  if (buffer2 != InvalidBuffer && buffer2 != buffer1)
177 
178  /*
179  * If there are two buffers involved and we pinned just one of them,
180  * it's possible that the second one became all-visible while we were
181  * busy pinning the first one. If it looks like that's a possible
182  * scenario, we'll need to make a second pass through this loop.
183  */
184  if (buffer2 == InvalidBuffer || buffer1 == buffer2
185  || (need_to_pin_buffer1 && need_to_pin_buffer2))
186  break;
187  }
188 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
#define PageIsAllVisible(page)
Definition: bufpage.h:385
void visibilitymap_pin(Relation rel, BlockNumber heapBlk, Buffer *buf)
#define InvalidBuffer
Definition: buf.h:25
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:98
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3750
#define Assert(condition)
Definition: c.h:746
#define BufferIsValid(bufnum)
Definition: bufmgr.h:123
bool visibilitymap_pin_ok(BlockNumber heapBlk, Buffer buf)

◆ ReadBufferBI()

static Buffer ReadBufferBI ( Relation  relation,
BlockNumber  targetBlock,
ReadBufferMode  mode,
BulkInsertState  bistate 
)
static

Definition at line 91 of file hio.c.

References Assert, BufferGetBlockNumber(), BulkInsertStateData::current_buf, IncrBufferRefCount(), InvalidBuffer, MAIN_FORKNUM, RBM_ZERO_AND_CLEANUP_LOCK, RBM_ZERO_AND_LOCK, ReadBufferExtended(), ReleaseBuffer(), and BulkInsertStateData::strategy.

Referenced by RelationAddExtraBlocks(), and RelationGetBufferForTuple().

93 {
94  Buffer buffer;
95 
96  /* If not bulk-insert, exactly like ReadBuffer */
97  if (!bistate)
98  return ReadBufferExtended(relation, MAIN_FORKNUM, targetBlock,
99  mode, NULL);
100 
101  /* If we have the desired block already pinned, re-pin and return it */
102  if (bistate->current_buf != InvalidBuffer)
103  {
104  if (BufferGetBlockNumber(bistate->current_buf) == targetBlock)
105  {
106  /*
107  * Currently the LOCK variants are only used for extending
108  * relation, which should never reach this branch.
109  */
112 
114  return bistate->current_buf;
115  }
116  /* ... else drop the old buffer */
117  ReleaseBuffer(bistate->current_buf);
118  bistate->current_buf = InvalidBuffer;
119  }
120 
121  /* Perform a read using the buffer strategy */
122  buffer = ReadBufferExtended(relation, MAIN_FORKNUM, targetBlock,
123  mode, bistate->strategy);
124 
125  /* Save the selected block as target for future inserts */
126  IncrBufferRefCount(buffer);
127  bistate->current_buf = buffer;
128 
129  return buffer;
130 }
static PgChecksumMode mode
Definition: pg_checksums.c:61
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:653
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3511
#define Assert(condition)
Definition: c.h:746
BufferAccessStrategy strategy
Definition: hio.h:31
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2661
int Buffer
Definition: buf.h:23
void IncrBufferRefCount(Buffer buffer)
Definition: bufmgr.c:3549
Buffer current_buf
Definition: hio.h:32

◆ RelationAddExtraBlocks()

static void RelationAddExtraBlocks ( Relation  relation,
BulkInsertState  bistate 
)
static

Definition at line 197 of file hio.c.

References BufferGetBlockNumber(), BufferGetPage, BufferGetPageSize, elog, ERROR, FreeSpaceMapVacuumRange(), InvalidBlockNumber, Min, P_NEW, PageIsNew, RBM_ZERO_AND_LOCK, ReadBufferBI(), RecordPageWithFreeSpace(), RelationExtensionLockWaiterCount(), RelationGetRelationName, SizeOfPageHeaderData, and UnlockReleaseBuffer().

Referenced by RelationGetBufferForTuple().

198 {
199  BlockNumber blockNum,
200  firstBlock = InvalidBlockNumber;
201  int extraBlocks;
202  int lockWaiters;
203 
204  /* Use the length of the lock wait queue to judge how much to extend. */
205  lockWaiters = RelationExtensionLockWaiterCount(relation);
206  if (lockWaiters <= 0)
207  return;
208 
209  /*
210  * It might seem like multiplying the number of lock waiters by as much as
211  * 20 is too aggressive, but benchmarking revealed that smaller numbers
212  * were insufficient. 512 is just an arbitrary cap to prevent
213  * pathological results.
214  */
215  extraBlocks = Min(512, lockWaiters * 20);
216 
217  do
218  {
219  Buffer buffer;
220  Page page;
221  Size freespace;
222 
223  /*
224  * Extend by one page. This should generally match the main-line
225  * extension code in RelationGetBufferForTuple, except that we hold
226  * the relation extension lock throughout, and we don't immediately
227  * initialize the page (see below).
228  */
229  buffer = ReadBufferBI(relation, P_NEW, RBM_ZERO_AND_LOCK, bistate);
230  page = BufferGetPage(buffer);
231 
232  if (!PageIsNew(page))
233  elog(ERROR, "page %u of relation \"%s\" should be empty but is not",
234  BufferGetBlockNumber(buffer),
235  RelationGetRelationName(relation));
236 
237  /*
238  * Add the page to the FSM without initializing. If we were to
239  * initialize here, the page would potentially get flushed out to disk
240  * before we add any useful content. There's no guarantee that that'd
241  * happen before a potential crash, so we need to deal with
242  * uninitialized pages anyway, thus avoid the potential for
243  * unnecessary writes.
244  */
245 
246  /* we'll need this info below */
247  blockNum = BufferGetBlockNumber(buffer);
248  freespace = BufferGetPageSize(buffer) - SizeOfPageHeaderData;
249 
250  UnlockReleaseBuffer(buffer);
251 
252  /* Remember first block number thus added. */
253  if (firstBlock == InvalidBlockNumber)
254  firstBlock = blockNum;
255 
256  /*
257  * Immediately update the bottom level of the FSM. This has a good
258  * chance of making this page visible to other concurrently inserting
259  * backends, and we want that to happen without delay.
260  */
261  RecordPageWithFreeSpace(relation, blockNum, freespace);
262  }
263  while (--extraBlocks > 0);
264 
265  /*
266  * Updating the upper levels of the free space map is too expensive to do
267  * for every block, but it's worth doing once at the end to make sure that
268  * subsequent insertion activity sees all of those nifty free pages we
269  * just inserted.
270  */
271  FreeSpaceMapVacuumRange(relation, firstBlock, blockNum + 1);
272 }
int RelationExtensionLockWaiterCount(Relation relation)
Definition: lmgr.c:437
void RecordPageWithFreeSpace(Relation rel, BlockNumber heapBlk, Size spaceAvail)
Definition: freespace.c:181
#define Min(x, y)
Definition: c.h:928
uint32 BlockNumber
Definition: block.h:31
#define P_NEW
Definition: bufmgr.h:91
#define SizeOfPageHeaderData
Definition: bufpage.h:216
static Buffer ReadBufferBI(Relation relation, BlockNumber targetBlock, ReadBufferMode mode, BulkInsertState bistate)
Definition: hio.c:91
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3534
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:490
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:156
size_t Size
Definition: c.h:474
#define InvalidBlockNumber
Definition: block.h:33
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2661
#define PageIsNew(page)
Definition: bufpage.h:229
#define elog(elevel,...)
Definition: elog.h:214
int Buffer
Definition: buf.h:23
void FreeSpaceMapVacuumRange(Relation rel, BlockNumber start, BlockNumber end)
Definition: freespace.c:354
Pointer Page
Definition: bufpage.h:78

◆ RelationGetBufferForTuple()

Buffer RelationGetBufferForTuple ( Relation  relation,
Size  len,
Buffer  otherBuffer,
int  options,
BulkInsertState  bistate,
Buffer vmbuffer,
Buffer vmbuffer_other 
)

Definition at line 331 of file hio.c.

References Assert, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage, BufferGetPageSize, ConditionalLockBuffer(), ConditionalLockRelationForExtension(), BulkInsertStateData::current_buf, elog, ereport, errcode(), errmsg(), ERROR, ExclusiveLock, GetPageWithFreeSpace(), GetVisibilityMapPins(), HEAP_DEFAULT_FILLFACTOR, HEAP_INSERT_SKIP_FSM, InvalidBlockNumber, InvalidBuffer, LockBuffer(), LockRelationForExtension(), MarkBufferDirty(), MAXALIGN, MaxHeapTupleSize, P_NEW, PageGetHeapFreeSpace(), PageInit(), PageIsAllVisible, PageIsNew, PANIC, RBM_NORMAL, RBM_ZERO_AND_LOCK, ReadBuffer(), ReadBufferBI(), RecordAndGetPageWithFreeSpace(), RELATION_IS_LOCAL, RelationAddExtraBlocks(), RelationGetNumberOfBlocks, RelationGetRelationName, RelationGetTargetBlock, RelationGetTargetPageFreeSpace, RelationSetTargetBlock, ReleaseBuffer(), unlikely, UnlockRelationForExtension(), UnlockReleaseBuffer(), and visibilitymap_pin().

Referenced by heap_insert(), heap_multi_insert(), and heap_update().

335 {
336  bool use_fsm = !(options & HEAP_INSERT_SKIP_FSM);
337  Buffer buffer = InvalidBuffer;
338  Page page;
339  Size pageFreeSpace = 0,
340  saveFreeSpace = 0;
341  BlockNumber targetBlock,
342  otherBlock;
343  bool needLock;
344 
345  len = MAXALIGN(len); /* be conservative */
346 
347  /* Bulk insert is not supported for updates, only inserts. */
348  Assert(otherBuffer == InvalidBuffer || !bistate);
349 
350  /*
351  * If we're gonna fail for oversize tuple, do it right away
352  */
353  if (len > MaxHeapTupleSize)
354  ereport(ERROR,
355  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
356  errmsg("row is too big: size %zu, maximum size %zu",
357  len, MaxHeapTupleSize)));
358 
359  /* Compute desired extra freespace due to fillfactor option */
360  saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
362 
363  if (otherBuffer != InvalidBuffer)
364  otherBlock = BufferGetBlockNumber(otherBuffer);
365  else
366  otherBlock = InvalidBlockNumber; /* just to keep compiler quiet */
367 
368  /*
369  * We first try to put the tuple on the same page we last inserted a tuple
370  * on, as cached in the BulkInsertState or relcache entry. If that
371  * doesn't work, we ask the Free Space Map to locate a suitable page.
372  * Since the FSM's info might be out of date, we have to be prepared to
373  * loop around and retry multiple times. (To insure this isn't an infinite
374  * loop, we must update the FSM with the correct amount of free space on
375  * each page that proves not to be suitable.) If the FSM has no record of
376  * a page with enough free space, we give up and extend the relation.
377  *
378  * When use_fsm is false, we either put the tuple onto the existing target
379  * page or extend the relation.
380  */
381  if (len + saveFreeSpace > MaxHeapTupleSize)
382  {
383  /* can't fit, don't bother asking FSM */
384  targetBlock = InvalidBlockNumber;
385  use_fsm = false;
386  }
387  else if (bistate && bistate->current_buf != InvalidBuffer)
388  targetBlock = BufferGetBlockNumber(bistate->current_buf);
389  else
390  targetBlock = RelationGetTargetBlock(relation);
391 
392  if (targetBlock == InvalidBlockNumber && use_fsm)
393  {
394  /*
395  * We have no cached target page, so ask the FSM for an initial
396  * target.
397  */
398  targetBlock = GetPageWithFreeSpace(relation, len + saveFreeSpace);
399 
400  /*
401  * If the FSM knows nothing of the rel, try the last page before we
402  * give up and extend. This avoids one-tuple-per-page syndrome during
403  * bootstrapping or in a recently-started system.
404  */
405  if (targetBlock == InvalidBlockNumber)
406  {
407  BlockNumber nblocks = RelationGetNumberOfBlocks(relation);
408 
409  if (nblocks > 0)
410  targetBlock = nblocks - 1;
411  }
412  }
413 
414 loop:
415  while (targetBlock != InvalidBlockNumber)
416  {
417  /*
418  * Read and exclusive-lock the target block, as well as the other
419  * block if one was given, taking suitable care with lock ordering and
420  * the possibility they are the same block.
421  *
422  * If the page-level all-visible flag is set, caller will need to
423  * clear both that and the corresponding visibility map bit. However,
424  * by the time we return, we'll have x-locked the buffer, and we don't
425  * want to do any I/O while in that state. So we check the bit here
426  * before taking the lock, and pin the page if it appears necessary.
427  * Checking without the lock creates a risk of getting the wrong
428  * answer, so we'll have to recheck after acquiring the lock.
429  */
430  if (otherBuffer == InvalidBuffer)
431  {
432  /* easy case */
433  buffer = ReadBufferBI(relation, targetBlock, RBM_NORMAL, bistate);
434  if (PageIsAllVisible(BufferGetPage(buffer)))
435  visibilitymap_pin(relation, targetBlock, vmbuffer);
437  }
438  else if (otherBlock == targetBlock)
439  {
440  /* also easy case */
441  buffer = otherBuffer;
442  if (PageIsAllVisible(BufferGetPage(buffer)))
443  visibilitymap_pin(relation, targetBlock, vmbuffer);
445  }
446  else if (otherBlock < targetBlock)
447  {
448  /* lock other buffer first */
449  buffer = ReadBuffer(relation, targetBlock);
450  if (PageIsAllVisible(BufferGetPage(buffer)))
451  visibilitymap_pin(relation, targetBlock, vmbuffer);
452  LockBuffer(otherBuffer, BUFFER_LOCK_EXCLUSIVE);
454  }
455  else
456  {
457  /* lock target buffer first */
458  buffer = ReadBuffer(relation, targetBlock);
459  if (PageIsAllVisible(BufferGetPage(buffer)))
460  visibilitymap_pin(relation, targetBlock, vmbuffer);
462  LockBuffer(otherBuffer, BUFFER_LOCK_EXCLUSIVE);
463  }
464 
465  /*
466  * We now have the target page (and the other buffer, if any) pinned
467  * and locked. However, since our initial PageIsAllVisible checks
468  * were performed before acquiring the lock, the results might now be
469  * out of date, either for the selected victim buffer, or for the
470  * other buffer passed by the caller. In that case, we'll need to
471  * give up our locks, go get the pin(s) we failed to get earlier, and
472  * re-lock. That's pretty painful, but hopefully shouldn't happen
473  * often.
474  *
475  * Note that there's a small possibility that we didn't pin the page
476  * above but still have the correct page pinned anyway, either because
477  * we've already made a previous pass through this loop, or because
478  * caller passed us the right page anyway.
479  *
480  * Note also that it's possible that by the time we get the pin and
481  * retake the buffer locks, the visibility map bit will have been
482  * cleared by some other backend anyway. In that case, we'll have
483  * done a bit of extra work for no gain, but there's no real harm
484  * done.
485  */
486  if (otherBuffer == InvalidBuffer || targetBlock <= otherBlock)
487  GetVisibilityMapPins(relation, buffer, otherBuffer,
488  targetBlock, otherBlock, vmbuffer,
489  vmbuffer_other);
490  else
491  GetVisibilityMapPins(relation, otherBuffer, buffer,
492  otherBlock, targetBlock, vmbuffer_other,
493  vmbuffer);
494 
495  /*
496  * Now we can check to see if there's enough free space here. If so,
497  * we're done.
498  */
499  page = BufferGetPage(buffer);
500 
501  /*
502  * If necessary initialize page, it'll be used soon. We could avoid
503  * dirtying the buffer here, and rely on the caller to do so whenever
504  * it puts a tuple onto the page, but there seems not much benefit in
505  * doing so.
506  */
507  if (PageIsNew(page))
508  {
509  PageInit(page, BufferGetPageSize(buffer), 0);
510  MarkBufferDirty(buffer);
511  }
512 
513  pageFreeSpace = PageGetHeapFreeSpace(page);
514  if (len + saveFreeSpace <= pageFreeSpace)
515  {
516  /* use this page as future insert target, too */
517  RelationSetTargetBlock(relation, targetBlock);
518  return buffer;
519  }
520 
521  /*
522  * Not enough space, so we must give up our page locks and pin (if
523  * any) and prepare to look elsewhere. We don't care which order we
524  * unlock the two buffers in, so this can be slightly simpler than the
525  * code above.
526  */
528  if (otherBuffer == InvalidBuffer)
529  ReleaseBuffer(buffer);
530  else if (otherBlock != targetBlock)
531  {
532  LockBuffer(otherBuffer, BUFFER_LOCK_UNLOCK);
533  ReleaseBuffer(buffer);
534  }
535 
536  /* Without FSM, always fall out of the loop and extend */
537  if (!use_fsm)
538  break;
539 
540  /*
541  * Update FSM as to condition of this page, and ask for another page
542  * to try.
543  */
544  targetBlock = RecordAndGetPageWithFreeSpace(relation,
545  targetBlock,
546  pageFreeSpace,
547  len + saveFreeSpace);
548  }
549 
550  /*
551  * Have to extend the relation.
552  *
553  * We have to use a lock to ensure no one else is extending the rel at the
554  * same time, else we will both try to initialize the same new page. We
555  * can skip locking for new or temp relations, however, since no one else
556  * could be accessing them.
557  */
558  needLock = !RELATION_IS_LOCAL(relation);
559 
560  /*
561  * If we need the lock but are not able to acquire it immediately, we'll
562  * consider extending the relation by multiple blocks at a time to manage
563  * contention on the relation extension lock. However, this only makes
564  * sense if we're using the FSM; otherwise, there's no point.
565  */
566  if (needLock)
567  {
568  if (!use_fsm)
571  {
572  /* Couldn't get the lock immediately; wait for it. */
574 
575  /*
576  * Check if some other backend has extended a block for us while
577  * we were waiting on the lock.
578  */
579  targetBlock = GetPageWithFreeSpace(relation, len + saveFreeSpace);
580 
581  /*
582  * If some other waiter has already extended the relation, we
583  * don't need to do so; just use the existing freespace.
584  */
585  if (targetBlock != InvalidBlockNumber)
586  {
588  goto loop;
589  }
590 
591  /* Time to bulk-extend. */
592  RelationAddExtraBlocks(relation, bistate);
593  }
594  }
595 
596  /*
597  * In addition to whatever extension we performed above, we always add at
598  * least one block to satisfy our own request.
599  *
600  * XXX This does an lseek - rather expensive - but at the moment it is the
601  * only way to accurately determine how many blocks are in a relation. Is
602  * it worth keeping an accurate file length in shared memory someplace,
603  * rather than relying on the kernel to do it for us?
604  */
605  buffer = ReadBufferBI(relation, P_NEW, RBM_ZERO_AND_LOCK, bistate);
606 
607  /*
608  * We need to initialize the empty new page. Double-check that it really
609  * is empty (this should never happen, but if it does we don't want to
610  * risk wiping out valid data).
611  */
612  page = BufferGetPage(buffer);
613 
614  if (!PageIsNew(page))
615  elog(ERROR, "page %u of relation \"%s\" should be empty but is not",
616  BufferGetBlockNumber(buffer),
617  RelationGetRelationName(relation));
618 
619  PageInit(page, BufferGetPageSize(buffer), 0);
620  MarkBufferDirty(buffer);
621 
622  /*
623  * Release the file-extension lock; it's now OK for someone else to extend
624  * the relation some more.
625  */
626  if (needLock)
628 
629  /*
630  * Lock the other buffer. It's guaranteed to be of a lower page number
631  * than the new page. To conform with the deadlock prevent rules, we ought
632  * to lock otherBuffer first, but that would give other backends a chance
633  * to put tuples on our page. To reduce the likelihood of that, attempt to
634  * lock the other buffer conditionally, that's very likely to work.
635  * Otherwise we need to lock buffers in the correct order, and retry if
636  * the space has been used in the mean time.
637  *
638  * Alternatively, we could acquire the lock on otherBuffer before
639  * extending the relation, but that'd require holding the lock while
640  * performing IO, which seems worse than an unlikely retry.
641  */
642  if (otherBuffer != InvalidBuffer)
643  {
644  Assert(otherBuffer != buffer);
645 
646  if (unlikely(!ConditionalLockBuffer(otherBuffer)))
647  {
649  LockBuffer(otherBuffer, BUFFER_LOCK_EXCLUSIVE);
651 
652  /*
653  * Because the buffer was unlocked for a while, it's possible,
654  * although unlikely, that the page was filled. If so, just retry
655  * from start.
656  */
657  if (len > PageGetHeapFreeSpace(page))
658  {
659  LockBuffer(otherBuffer, BUFFER_LOCK_UNLOCK);
660  UnlockReleaseBuffer(buffer);
661 
662  goto loop;
663  }
664  }
665  }
666 
667  if (len > PageGetHeapFreeSpace(page))
668  {
669  /* We should not get here given the test at the top */
670  elog(PANIC, "tuple is too big: size %zu", len);
671  }
672 
673  /*
674  * Remember the new page as our target for future insertions.
675  *
676  * XXX should we enter the new page into the free space map immediately,
677  * or just keep it for this backend's exclusive use in the short run
678  * (until VACUUM sees it)? Seems to depend on whether you expect the
679  * current backend to make more insertions or not, which is probably a
680  * good bet most of the time. So for now, don't add it to FSM yet.
681  */
682  RelationSetTargetBlock(relation, BufferGetBlockNumber(buffer));
683 
684  return buffer;
685 }
bool ConditionalLockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:420
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
#define PageIsAllVisible(page)
Definition: bufpage.h:385
void visibilitymap_pin(Relation rel, BlockNumber heapBlk, Buffer *buf)
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1469
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:583
#define InvalidBuffer
Definition: buf.h:25
int errcode(int sqlerrcode)
Definition: elog.c:610
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3511
#define P_NEW
Definition: bufmgr.h:91
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:98
#define PANIC
Definition: elog.h:53
#define RelationGetTargetBlock(relation)
Definition: rel.h:541
static Buffer ReadBufferBI(Relation relation, BlockNumber targetBlock, ReadBufferMode mode, BulkInsertState bistate)
Definition: hio.c:91
static void GetVisibilityMapPins(Relation relation, Buffer buffer1, Buffer buffer2, BlockNumber block1, BlockNumber block2, Buffer *vmbuffer1, Buffer *vmbuffer2)
Definition: hio.c:141
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3534
#define ERROR
Definition: elog.h:43
Size PageGetHeapFreeSpace(Page page)
Definition: bufpage.c:866
#define MaxHeapTupleSize
Definition: htup_details.h:560
#define RelationGetRelationName(relation)
Definition: rel.h:490
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3776
#define RelationGetTargetPageFreeSpace(relation, defaultff)
Definition: rel.h:340
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:402
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:452
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:156
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3750
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:211
#define ereport(elevel,...)
Definition: elog.h:144
#define Assert(condition)
Definition: c.h:746
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:607
#define RelationSetTargetBlock(relation, targblock)
Definition: rel.h:548
size_t Size
Definition: c.h:474
#define InvalidBlockNumber
Definition: block.h:33
#define MAXALIGN(LEN)
Definition: c.h:699
#define HEAP_INSERT_SKIP_FSM
Definition: heapam.h:34
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2661
static void RelationAddExtraBlocks(Relation relation, BulkInsertState bistate)
Definition: hio.c:197
#define PageIsNew(page)
Definition: bufpage.h:229
int errmsg(const char *fmt,...)
Definition: elog.c:821
#define elog(elevel,...)
Definition: elog.h:214
BlockNumber GetPageWithFreeSpace(Relation rel, Size spaceNeeded)
Definition: freespace.c:132
#define unlikely(x)
Definition: c.h:207
BlockNumber RecordAndGetPageWithFreeSpace(Relation rel, BlockNumber oldPage, Size oldSpaceAvail, Size spaceNeeded)
Definition: freespace.c:149
#define HEAP_DEFAULT_FILLFACTOR
Definition: rel.h:311
int Buffer
Definition: buf.h:23
Buffer current_buf
Definition: hio.h:32
Pointer Page
Definition: bufpage.h:78
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:42

◆ RelationPutHeapTuple()

void RelationPutHeapTuple ( Relation  relation,
Buffer  buffer,
HeapTuple  tuple,
bool  token 
)

Definition at line 36 of file hio.c.

References Assert, BufferGetBlockNumber(), BufferGetPage, elog, HEAP_KEYS_UPDATED, HEAP_XMAX_COMMITTED, HEAP_XMAX_IS_MULTI, HEAP_XMAX_LOCK_ONLY, HeapTupleHeaderIsSpeculative, InvalidOffsetNumber, ItemPointerSet, PageAddItem, PageGetItem, PageGetItemId, PANIC, HeapTupleHeaderData::t_ctid, HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, HeapTupleHeaderData::t_infomask2, HeapTupleData::t_len, and HeapTupleData::t_self.

Referenced by heap_insert(), heap_multi_insert(), and heap_update().

40 {
41  Page pageHeader;
42  OffsetNumber offnum;
43 
44  /*
45  * A tuple that's being inserted speculatively should already have its
46  * token set.
47  */
48  Assert(!token || HeapTupleHeaderIsSpeculative(tuple->t_data));
49 
50  /*
51  * Do not allow tuples with invalid combinations of hint bits to be placed
52  * on a page. These combinations are detected as corruption by the
53  * contrib/amcheck logic, so if you disable one or both of these
54  * assertions, make corresponding changes there.
55  */
57  (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)));
59  (tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI)));
60 
61  /* Add the tuple to the page */
62  pageHeader = BufferGetPage(buffer);
63 
64  offnum = PageAddItem(pageHeader, (Item) tuple->t_data,
65  tuple->t_len, InvalidOffsetNumber, false, true);
66 
67  if (offnum == InvalidOffsetNumber)
68  elog(PANIC, "failed to add tuple to page");
69 
70  /* Update tuple->t_self to the actual position where it was stored */
71  ItemPointerSet(&(tuple->t_self), BufferGetBlockNumber(buffer), offnum);
72 
73  /*
74  * Insert the correct position into CTID of the stored tuple, too (unless
75  * this is a speculative insertion, in which case the token is held in
76  * CTID field instead)
77  */
78  if (!token)
79  {
80  ItemId itemId = PageGetItemId(pageHeader, offnum);
81  HeapTupleHeader item = (HeapTupleHeader) PageGetItem(pageHeader, itemId);
82 
83  item->t_ctid = tuple->t_self;
84  }
85 }
#define HEAP_XMAX_LOCK_ONLY
Definition: htup_details.h:196
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
Pointer Item
Definition: item.h:17
#define HeapTupleHeaderIsSpeculative(tup)
Definition: htup_details.h:429
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:410
#define HEAP_XMAX_COMMITTED
Definition: htup_details.h:206
#define PANIC
Definition: elog.h:53
uint16 OffsetNumber
Definition: off.h:24
HeapTupleHeader t_data
Definition: htup.h:68
ItemPointerData t_ctid
Definition: htup_details.h:160
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
#define HEAP_KEYS_UPDATED
Definition: htup_details.h:278
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:208
#define InvalidOffsetNumber
Definition: off.h:26
#define Assert(condition)
Definition: c.h:746
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2661
#define elog(elevel,...)
Definition: elog.h:214
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:127