PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
hashovfl.c File Reference
#include "postgres.h"
#include "access/hash.h"
#include "access/hash_xlog.h"
#include "miscadmin.h"
#include "utils/rel.h"
Include dependency graph for hashovfl.c:

Go to the source code of this file.

Functions

static uint32 _hash_firstfreebit (uint32 map)
 
static BlockNumber bitno_to_blkno (HashMetaPage metap, uint32 ovflbitnum)
 
uint32 _hash_ovflblkno_to_bitno (HashMetaPage metap, BlockNumber ovflblkno)
 
Buffer _hash_addovflpage (Relation rel, Buffer metabuf, Buffer buf, bool retain_pin)
 
BlockNumber _hash_freeovflpage (Relation rel, Buffer bucketbuf, Buffer ovflbuf, Buffer wbuf, IndexTuple *itups, OffsetNumber *itup_offsets, Size *tups_size, uint16 nitups, BufferAccessStrategy bstrategy)
 
void _hash_initbitmapbuffer (Buffer buf, uint16 bmsize, bool initpage)
 
void _hash_squeezebucket (Relation rel, Bucket bucket, BlockNumber bucket_blkno, Buffer bucket_buf, BufferAccessStrategy bstrategy)
 

Function Documentation

Buffer _hash_addovflpage ( Relation  rel,
Buffer  metabuf,
Buffer  buf,
bool  retain_pin 
)

Definition at line 110 of file hashovfl.c.

References _hash_checkpage(), _hash_firstfreebit(), _hash_getbuf(), _hash_getinitbuf(), _hash_getnewbuf(), _hash_initbitmapbuffer(), _hash_relbuf(), ALL_SET, Assert, bit(), bitno_to_blkno(), BITS_PER_MAP, BlockNumberIsValid, xl_hash_add_ovfl_page::bmpage_found, BMPG_MASK, BMPG_SHIFT, BMPGSZ_BIT, xl_hash_add_ovfl_page::bmsize, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage, BufferIsValid, END_CRIT_SECTION, ereport, errcode(), errmsg(), ERROR, HASH_MAX_BITMAPS, HASH_WRITE, HashMetaPageData::hashm_bmsize, HashMetaPageData::hashm_firstfree, HashMetaPageData::hashm_mapp, HashMetaPageData::hashm_nmaps, HashMetaPageData::hashm_ovflpoint, HashMetaPageData::hashm_spares, HashPageOpaqueData::hasho_bucket, HashPageOpaqueData::hasho_flag, HashPageOpaqueData::hasho_nextblkno, HashPageOpaqueData::hasho_page_id, HASHO_PAGE_ID, HashPageOpaqueData::hasho_prevblkno, HashPageGetBitmap, HashPageGetMeta, i, InvalidBlockNumber, InvalidBuffer, LH_BITMAP_PAGE, LH_BUCKET_PAGE, LH_META_PAGE, LH_OVERFLOW_PAGE, LockBuffer(), MAIN_FORKNUM, MarkBufferDirty(), NULL, PageGetSpecialPointer, PageSetLSN, REGBUF_STANDARD, REGBUF_WILL_INIT, RelationGetRelationName, RelationNeedsWAL, SETBIT, SizeOfHashAddOvflPage, START_CRIT_SECTION, XLOG_HASH_ADD_OVFL_PAGE, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by _hash_doinsert(), and _hash_splitbucket().

111 {
112  Buffer ovflbuf;
113  Page page;
114  Page ovflpage;
115  HashPageOpaque pageopaque;
116  HashPageOpaque ovflopaque;
117  HashMetaPage metap;
118  Buffer mapbuf = InvalidBuffer;
119  Buffer newmapbuf = InvalidBuffer;
120  BlockNumber blkno;
121  uint32 orig_firstfree;
122  uint32 splitnum;
123  uint32 *freep = NULL;
124  uint32 max_ovflpg;
125  uint32 bit;
126  uint32 bitmap_page_bit;
127  uint32 first_page;
128  uint32 last_bit;
129  uint32 last_page;
130  uint32 i,
131  j;
132  bool page_found = false;
133 
134  /*
135  * Write-lock the tail page. Here, we need to maintain locking order such
136  * that, first acquire the lock on tail page of bucket, then on meta page
137  * to find and lock the bitmap page and if it is found, then lock on meta
138  * page is released, then finally acquire the lock on new overflow buffer.
139  * We need this locking order to avoid deadlock with backends that are
140  * doing inserts.
141  *
142  * Note: We could have avoided locking many buffers here if we made two
143  * WAL records for acquiring an overflow page (one to allocate an overflow
144  * page and another to add it to overflow bucket chain). However, doing
145  * so can leak an overflow page, if the system crashes after allocation.
146  * Needless to say, it is better to have a single record from a
147  * performance point of view as well.
148  */
150 
151  /* probably redundant... */
153 
154  /* loop to find current tail page, in case someone else inserted too */
155  for (;;)
156  {
157  BlockNumber nextblkno;
158 
159  page = BufferGetPage(buf);
160  pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
161  nextblkno = pageopaque->hasho_nextblkno;
162 
163  if (!BlockNumberIsValid(nextblkno))
164  break;
165 
166  /* we assume we do not need to write the unmodified page */
167  if (retain_pin)
168  {
169  /* pin will be retained only for the primary bucket page */
170  Assert(pageopaque->hasho_flag & LH_BUCKET_PAGE);
172  }
173  else
174  _hash_relbuf(rel, buf);
175 
176  retain_pin = false;
177 
178  buf = _hash_getbuf(rel, nextblkno, HASH_WRITE, LH_OVERFLOW_PAGE);
179  }
180 
181  /* Get exclusive lock on the meta page */
183 
184  _hash_checkpage(rel, metabuf, LH_META_PAGE);
185  metap = HashPageGetMeta(BufferGetPage(metabuf));
186 
187  /* start search at hashm_firstfree */
188  orig_firstfree = metap->hashm_firstfree;
189  first_page = orig_firstfree >> BMPG_SHIFT(metap);
190  bit = orig_firstfree & BMPG_MASK(metap);
191  i = first_page;
192  j = bit / BITS_PER_MAP;
193  bit &= ~(BITS_PER_MAP - 1);
194 
195  /* outer loop iterates once per bitmap page */
196  for (;;)
197  {
198  BlockNumber mapblkno;
199  Page mappage;
200  uint32 last_inpage;
201 
202  /* want to end search with the last existing overflow page */
203  splitnum = metap->hashm_ovflpoint;
204  max_ovflpg = metap->hashm_spares[splitnum] - 1;
205  last_page = max_ovflpg >> BMPG_SHIFT(metap);
206  last_bit = max_ovflpg & BMPG_MASK(metap);
207 
208  if (i > last_page)
209  break;
210 
211  Assert(i < metap->hashm_nmaps);
212  mapblkno = metap->hashm_mapp[i];
213 
214  if (i == last_page)
215  last_inpage = last_bit;
216  else
217  last_inpage = BMPGSZ_BIT(metap) - 1;
218 
219  /* Release exclusive lock on metapage while reading bitmap page */
220  LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
221 
222  mapbuf = _hash_getbuf(rel, mapblkno, HASH_WRITE, LH_BITMAP_PAGE);
223  mappage = BufferGetPage(mapbuf);
224  freep = HashPageGetBitmap(mappage);
225 
226  for (; bit <= last_inpage; j++, bit += BITS_PER_MAP)
227  {
228  if (freep[j] != ALL_SET)
229  {
230  page_found = true;
231 
232  /* Reacquire exclusive lock on the meta page */
234 
235  /* convert bit to bit number within page */
236  bit += _hash_firstfreebit(freep[j]);
237  bitmap_page_bit = bit;
238 
239  /* convert bit to absolute bit number */
240  bit += (i << BMPG_SHIFT(metap));
241  /* Calculate address of the recycled overflow page */
242  blkno = bitno_to_blkno(metap, bit);
243 
244  /* Fetch and init the recycled page */
245  ovflbuf = _hash_getinitbuf(rel, blkno);
246 
247  goto found;
248  }
249  }
250 
251  /* No free space here, try to advance to next map page */
252  _hash_relbuf(rel, mapbuf);
253  mapbuf = InvalidBuffer;
254  i++;
255  j = 0; /* scan from start of next map page */
256  bit = 0;
257 
258  /* Reacquire exclusive lock on the meta page */
260  }
261 
262  /*
263  * No free pages --- have to extend the relation to add an overflow page.
264  * First, check to see if we have to add a new bitmap page too.
265  */
266  if (last_bit == (uint32) (BMPGSZ_BIT(metap) - 1))
267  {
268  /*
269  * We create the new bitmap page with all pages marked "in use".
270  * Actually two pages in the new bitmap's range will exist
271  * immediately: the bitmap page itself, and the following page which
272  * is the one we return to the caller. Both of these are correctly
273  * marked "in use". Subsequent pages do not exist yet, but it is
274  * convenient to pre-mark them as "in use" too.
275  */
276  bit = metap->hashm_spares[splitnum];
277 
278  /* metapage already has a write lock */
279  if (metap->hashm_nmaps >= HASH_MAX_BITMAPS)
280  ereport(ERROR,
281  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
282  errmsg("out of overflow pages in hash index \"%s\"",
283  RelationGetRelationName(rel))));
284 
285  newmapbuf = _hash_getnewbuf(rel, bitno_to_blkno(metap, bit), MAIN_FORKNUM);
286  }
287  else
288  {
289  /*
290  * Nothing to do here; since the page will be past the last used page,
291  * we know its bitmap bit was preinitialized to "in use".
292  */
293  }
294 
295  /* Calculate address of the new overflow page */
296  bit = BufferIsValid(newmapbuf) ?
297  metap->hashm_spares[splitnum] + 1 : metap->hashm_spares[splitnum];
298  blkno = bitno_to_blkno(metap, bit);
299 
300  /*
301  * Fetch the page with _hash_getnewbuf to ensure smgr's idea of the
302  * relation length stays in sync with ours. XXX It's annoying to do this
303  * with metapage write lock held; would be better to use a lock that
304  * doesn't block incoming searches.
305  *
306  * It is okay to hold two buffer locks here (one on tail page of bucket
307  * and other on new overflow page) since there cannot be anyone else
308  * contending for access to ovflbuf.
309  */
310  ovflbuf = _hash_getnewbuf(rel, blkno, MAIN_FORKNUM);
311 
312 found:
313 
314  /*
315  * Do the update. No ereport(ERROR) until changes are logged. We want to
316  * log the changes for bitmap page and overflow page together to avoid
317  * loss of pages in case the new page is added.
318  */
320 
321  if (page_found)
322  {
323  Assert(BufferIsValid(mapbuf));
324 
325  /* mark page "in use" in the bitmap */
326  SETBIT(freep, bitmap_page_bit);
327  MarkBufferDirty(mapbuf);
328  }
329  else
330  {
331  /* update the count to indicate new overflow page is added */
332  metap->hashm_spares[splitnum]++;
333 
334  if (BufferIsValid(newmapbuf))
335  {
336  _hash_initbitmapbuffer(newmapbuf, metap->hashm_bmsize, false);
337  MarkBufferDirty(newmapbuf);
338 
339  /* add the new bitmap page to the metapage's list of bitmaps */
340  metap->hashm_mapp[metap->hashm_nmaps] = BufferGetBlockNumber(newmapbuf);
341  metap->hashm_nmaps++;
342  metap->hashm_spares[splitnum]++;
343  MarkBufferDirty(metabuf);
344  }
345 
346  /*
347  * for new overflow page, we don't need to explicitly set the bit in
348  * bitmap page, as by default that will be set to "in use".
349  */
350  }
351 
352  /*
353  * Adjust hashm_firstfree to avoid redundant searches. But don't risk
354  * changing it if someone moved it while we were searching bitmap pages.
355  */
356  if (metap->hashm_firstfree == orig_firstfree)
357  {
358  metap->hashm_firstfree = bit + 1;
359  MarkBufferDirty(metabuf);
360  }
361 
362  /* initialize new overflow page */
363  ovflpage = BufferGetPage(ovflbuf);
364  ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
366  ovflopaque->hasho_nextblkno = InvalidBlockNumber;
367  ovflopaque->hasho_bucket = pageopaque->hasho_bucket;
368  ovflopaque->hasho_flag = LH_OVERFLOW_PAGE;
369  ovflopaque->hasho_page_id = HASHO_PAGE_ID;
370 
371  MarkBufferDirty(ovflbuf);
372 
373  /* logically chain overflow page to previous page */
374  pageopaque->hasho_nextblkno = BufferGetBlockNumber(ovflbuf);
375 
377 
378  /* XLOG stuff */
379  if (RelationNeedsWAL(rel))
380  {
381  XLogRecPtr recptr;
382  xl_hash_add_ovfl_page xlrec;
383 
384  xlrec.bmpage_found = page_found;
385  xlrec.bmsize = metap->hashm_bmsize;
386 
387  XLogBeginInsert();
388  XLogRegisterData((char *) &xlrec, SizeOfHashAddOvflPage);
389 
391  XLogRegisterBufData(0, (char *) &pageopaque->hasho_bucket, sizeof(Bucket));
392 
394 
395  if (BufferIsValid(mapbuf))
396  {
398  XLogRegisterBufData(2, (char *) &bitmap_page_bit, sizeof(uint32));
399  }
400 
401  if (BufferIsValid(newmapbuf))
402  XLogRegisterBuffer(3, newmapbuf, REGBUF_WILL_INIT);
403 
404  XLogRegisterBuffer(4, metabuf, REGBUF_STANDARD);
405  XLogRegisterBufData(4, (char *) &metap->hashm_firstfree, sizeof(uint32));
406 
407  recptr = XLogInsert(RM_HASH_ID, XLOG_HASH_ADD_OVFL_PAGE);
408 
409  PageSetLSN(BufferGetPage(ovflbuf), recptr);
410  PageSetLSN(BufferGetPage(buf), recptr);
411 
412  if (BufferIsValid(mapbuf))
413  PageSetLSN(BufferGetPage(mapbuf), recptr);
414 
415  if (BufferIsValid(newmapbuf))
416  PageSetLSN(BufferGetPage(newmapbuf), recptr);
417 
418  PageSetLSN(BufferGetPage(metabuf), recptr);
419  }
420 
422 
423  if (retain_pin)
425  else
426  _hash_relbuf(rel, buf);
427 
428  if (BufferIsValid(mapbuf))
429  _hash_relbuf(rel, mapbuf);
430 
431  LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
432 
433  if (BufferIsValid(newmapbuf))
434  _hash_relbuf(rel, newmapbuf);
435 
436  return ovflbuf;
437 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
uint16 hasho_page_id
Definition: hash.h:82
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
#define SETBIT(x, i)
Definition: blutils.c:33
#define HashPageGetBitmap(page)
Definition: hash.h:243
#define LH_BITMAP_PAGE
Definition: hash.h:55
static BlockNumber bitno_to_blkno(HashMetaPage metap, uint32 ovflbitnum)
Definition: hashovfl.c:34
#define LH_META_PAGE
Definition: hash.h:56
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define END_CRIT_SECTION()
Definition: miscadmin.h:132
#define InvalidBuffer
Definition: buf.h:25
#define REGBUF_WILL_INIT
Definition: xloginsert.h:32
#define ALL_SET
Definition: hash.h:229
#define START_CRIT_SECTION()
Definition: miscadmin.h:130
int errcode(int sqlerrcode)
Definition: elog.c:575
uint32 BlockNumber
Definition: block.h:31
Buffer _hash_getnewbuf(Relation rel, BlockNumber blkno, ForkNumber forkNum)
Definition: hashpage.c:206
Buffer _hash_getinitbuf(Relation rel, BlockNumber blkno)
Definition: hashpage.c:143
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition: hashpage.c:78
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:89
static uint32 _hash_firstfreebit(uint32 map)
Definition: hashovfl.c:445
uint32 Bucket
Definition: hash.h:34
BlockNumber hasho_prevblkno
Definition: hash.h:78
#define ERROR
Definition: elog.h:43
#define XLOG_HASH_ADD_OVFL_PAGE
Definition: hash_xlog.h:30
uint32 hashm_nmaps
Definition: hash.h:202
static char * buf
Definition: pg_test_fsync.c:65
#define HASH_WRITE
Definition: hash.h:267
#define BMPG_MASK(metap)
Definition: hash.h:241
#define REGBUF_STANDARD
Definition: xloginsert.h:35
#define RelationGetRelationName(relation)
Definition: rel.h:437
unsigned int uint32
Definition: c.h:268
#define BITS_PER_MAP
Definition: hash.h:256
#define BMPG_SHIFT(metap)
Definition: hash.h:240
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
#define HASH_MAX_BITMAPS
Definition: hash.h:184
uint32 hashm_ovflpoint
Definition: hash.h:199
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
void _hash_checkpage(Relation rel, Buffer buf, int flags)
Definition: hashutil.c:159
#define LH_OVERFLOW_PAGE
Definition: hash.h:53
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
uint32 hashm_firstfree
Definition: hash.h:201
uint32 hashm_spares[HASH_MAX_SPLITPOINTS]
Definition: hash.h:204
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:274
void _hash_initbitmapbuffer(Buffer buf, uint16 bmsize, bool initpage)
Definition: hashovfl.c:727
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define LH_BUCKET_PAGE
Definition: hash.h:54
#define NULL
Definition: c.h:229
Datum bit(PG_FUNCTION_ARGS)
Definition: varbit.c:361
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:675
Bucket hasho_bucket
Definition: hash.h:80
#define PageGetSpecialPointer(page)
Definition: bufpage.h:323
#define InvalidBlockNumber
Definition: block.h:33
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:85
#define HASHO_PAGE_ID
Definition: hash.h:98
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
#define RelationNeedsWAL(relation)
Definition: rel.h:506
#define SizeOfHashAddOvflPage
Definition: hash_xlog.h:100
uint16 hasho_flag
Definition: hash.h:81
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define HashPageGetMeta(page)
Definition: hash.h:250
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
BlockNumber hasho_nextblkno
Definition: hash.h:79
uint16 hashm_bmsize
Definition: hash.h:193
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:365
BlockNumber hashm_mapp[HASH_MAX_BITMAPS]
Definition: hash.h:206
int Buffer
Definition: buf.h:23
#define BMPGSZ_BIT(metap)
Definition: hash.h:239
Pointer Page
Definition: bufpage.h:74
static uint32 _hash_firstfreebit ( uint32  map)
static

Definition at line 445 of file hashovfl.c.

References BITS_PER_MAP, elog, ERROR, and i.

Referenced by _hash_addovflpage().

446 {
447  uint32 i,
448  mask;
449 
450  mask = 0x1;
451  for (i = 0; i < BITS_PER_MAP; i++)
452  {
453  if (!(mask & map))
454  return i;
455  mask <<= 1;
456  }
457 
458  elog(ERROR, "firstfreebit found no free bit");
459 
460  return 0; /* keep compiler quiet */
461 }
#define ERROR
Definition: elog.h:43
unsigned int uint32
Definition: c.h:268
#define BITS_PER_MAP
Definition: hash.h:256
int i
#define elog
Definition: elog.h:219
BlockNumber _hash_freeovflpage ( Relation  rel,
Buffer  bucketbuf,
Buffer  ovflbuf,
Buffer  wbuf,
IndexTuple itups,
OffsetNumber itup_offsets,
Size tups_size,
uint16  nitups,
BufferAccessStrategy  bstrategy 
)

Definition at line 487 of file hashovfl.c.

References _hash_checkpage(), _hash_getbuf(), _hash_getbuf_with_strategy(), _hash_ovflblkno_to_bitno(), _hash_pageinit(), _hash_pgaddmultitup(), _hash_relbuf(), Assert, BlockNumberIsValid, BMPG_MASK, BMPG_SHIFT, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage, BufferGetPageSize, BufferIsValid, CLRBIT, elog, END_CRIT_SECTION, ERROR, HASH_METAPAGE, HASH_READ, HASH_WRITE, HASH_XLOG_FREE_OVFL_BUFS, HashMetaPageData::hashm_firstfree, HashMetaPageData::hashm_mapp, HashMetaPageData::hashm_nmaps, HashPageOpaqueData::hasho_bucket, HashPageOpaqueData::hasho_nextblkno, HashPageOpaqueData::hasho_prevblkno, HashPageGetBitmap, HashPageGetMeta, i, InvalidBuffer, xl_hash_squeeze_page::is_prev_bucket_same_wrt, xl_hash_squeeze_page::is_prim_bucket_same_wrt, ISSET, LH_BITMAP_PAGE, LH_BUCKET_PAGE, LH_META_PAGE, LH_OVERFLOW_PAGE, LockBuffer(), MarkBufferDirty(), xl_hash_squeeze_page::nextblkno, xl_hash_squeeze_page::ntups, PageGetSpecialPointer, PageSetLSN, PG_USED_FOR_ASSERTS_ONLY, xl_hash_squeeze_page::prevblkno, REGBUF_NO_IMAGE, REGBUF_STANDARD, RelationNeedsWAL, SizeOfHashSqueezePage, START_CRIT_SECTION, XLOG_HASH_SQUEEZE_PAGE, XLogBeginInsert(), XLogEnsureRecordSpace(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by _hash_squeezebucket().

491 {
492  HashMetaPage metap;
493  Buffer metabuf;
494  Buffer mapbuf;
495  BlockNumber ovflblkno;
496  BlockNumber prevblkno;
497  BlockNumber blkno;
498  BlockNumber nextblkno;
499  BlockNumber writeblkno;
500  HashPageOpaque ovflopaque;
501  Page ovflpage;
502  Page mappage;
503  uint32 *freep;
504  uint32 ovflbitno;
505  int32 bitmappage,
506  bitmapbit;
508  Buffer prevbuf = InvalidBuffer;
509  Buffer nextbuf = InvalidBuffer;
510  bool update_metap = false;
511 
512  /* Get information from the doomed page */
513  _hash_checkpage(rel, ovflbuf, LH_OVERFLOW_PAGE);
514  ovflblkno = BufferGetBlockNumber(ovflbuf);
515  ovflpage = BufferGetPage(ovflbuf);
516  ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
517  nextblkno = ovflopaque->hasho_nextblkno;
518  prevblkno = ovflopaque->hasho_prevblkno;
519  writeblkno = BufferGetBlockNumber(wbuf);
520  bucket = ovflopaque->hasho_bucket;
521 
522  /*
523  * Fix up the bucket chain. this is a doubly-linked list, so we must fix
524  * up the bucket chain members behind and ahead of the overflow page being
525  * deleted. Concurrency issues are avoided by using lock chaining as
526  * described atop hashbucketcleanup.
527  */
528  if (BlockNumberIsValid(prevblkno))
529  {
530  if (prevblkno == writeblkno)
531  prevbuf = wbuf;
532  else
533  prevbuf = _hash_getbuf_with_strategy(rel,
534  prevblkno,
535  HASH_WRITE,
537  bstrategy);
538  }
539  if (BlockNumberIsValid(nextblkno))
540  nextbuf = _hash_getbuf_with_strategy(rel,
541  nextblkno,
542  HASH_WRITE,
544  bstrategy);
545 
546  /* Note: bstrategy is intentionally not used for metapage and bitmap */
547 
548  /* Read the metapage so we can determine which bitmap page to use */
550  metap = HashPageGetMeta(BufferGetPage(metabuf));
551 
552  /* Identify which bit to set */
553  ovflbitno = _hash_ovflblkno_to_bitno(metap, ovflblkno);
554 
555  bitmappage = ovflbitno >> BMPG_SHIFT(metap);
556  bitmapbit = ovflbitno & BMPG_MASK(metap);
557 
558  if (bitmappage >= metap->hashm_nmaps)
559  elog(ERROR, "invalid overflow bit number %u", ovflbitno);
560  blkno = metap->hashm_mapp[bitmappage];
561 
562  /* Release metapage lock while we access the bitmap page */
563  LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
564 
565  /* read the bitmap page to clear the bitmap bit */
566  mapbuf = _hash_getbuf(rel, blkno, HASH_WRITE, LH_BITMAP_PAGE);
567  mappage = BufferGetPage(mapbuf);
568  freep = HashPageGetBitmap(mappage);
569  Assert(ISSET(freep, bitmapbit));
570 
571  /* Get write-lock on metapage to update firstfree */
573 
574  /* This operation needs to log multiple tuples, prepare WAL for that */
575  if (RelationNeedsWAL(rel))
577 
579 
580  /*
581  * we have to insert tuples on the "write" page, being careful to preserve
582  * hashkey ordering. (If we insert many tuples into the same "write" page
583  * it would be worth qsort'ing them).
584  */
585  if (nitups > 0)
586  {
587  _hash_pgaddmultitup(rel, wbuf, itups, itup_offsets, nitups);
588  MarkBufferDirty(wbuf);
589  }
590 
591  /*
592  * Initialize the freed overflow page. Just zeroing the page won't work,
593  * because WAL replay routines expect pages to be initialized. See
594  * explanation of RBM_NORMAL mode atop XLogReadBufferExtended.
595  */
596  _hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf));
597  MarkBufferDirty(ovflbuf);
598 
599  if (BufferIsValid(prevbuf))
600  {
601  Page prevpage = BufferGetPage(prevbuf);
602  HashPageOpaque prevopaque = (HashPageOpaque) PageGetSpecialPointer(prevpage);
603 
604  Assert(prevopaque->hasho_bucket == bucket);
605  prevopaque->hasho_nextblkno = nextblkno;
606  MarkBufferDirty(prevbuf);
607  }
608  if (BufferIsValid(nextbuf))
609  {
610  Page nextpage = BufferGetPage(nextbuf);
611  HashPageOpaque nextopaque = (HashPageOpaque) PageGetSpecialPointer(nextpage);
612 
613  Assert(nextopaque->hasho_bucket == bucket);
614  nextopaque->hasho_prevblkno = prevblkno;
615  MarkBufferDirty(nextbuf);
616  }
617 
618  /* Clear the bitmap bit to indicate that this overflow page is free */
619  CLRBIT(freep, bitmapbit);
620  MarkBufferDirty(mapbuf);
621 
622  /* if this is now the first free page, update hashm_firstfree */
623  if (ovflbitno < metap->hashm_firstfree)
624  {
625  metap->hashm_firstfree = ovflbitno;
626  update_metap = true;
627  MarkBufferDirty(metabuf);
628  }
629 
630  /* XLOG stuff */
631  if (RelationNeedsWAL(rel))
632  {
633  xl_hash_squeeze_page xlrec;
634  XLogRecPtr recptr;
635  int i;
636 
637  xlrec.prevblkno = prevblkno;
638  xlrec.nextblkno = nextblkno;
639  xlrec.ntups = nitups;
640  xlrec.is_prim_bucket_same_wrt = (wbuf == bucketbuf);
641  xlrec.is_prev_bucket_same_wrt = (wbuf == prevbuf);
642 
643  XLogBeginInsert();
644  XLogRegisterData((char *) &xlrec, SizeOfHashSqueezePage);
645 
646  /*
647  * bucket buffer needs to be registered to ensure that we can acquire
648  * a cleanup lock on it during replay.
649  */
650  if (!xlrec.is_prim_bucket_same_wrt)
652 
654  if (xlrec.ntups > 0)
655  {
656  XLogRegisterBufData(1, (char *) itup_offsets,
657  nitups * sizeof(OffsetNumber));
658  for (i = 0; i < nitups; i++)
659  XLogRegisterBufData(1, (char *) itups[i], tups_size[i]);
660  }
661 
662  XLogRegisterBuffer(2, ovflbuf, REGBUF_STANDARD);
663 
664  /*
665  * If prevpage and the writepage (block in which we are moving tuples
666  * from overflow) are same, then no need to separately register
667  * prevpage. During replay, we can directly update the nextblock in
668  * writepage.
669  */
670  if (BufferIsValid(prevbuf) && !xlrec.is_prev_bucket_same_wrt)
671  XLogRegisterBuffer(3, prevbuf, REGBUF_STANDARD);
672 
673  if (BufferIsValid(nextbuf))
674  XLogRegisterBuffer(4, nextbuf, REGBUF_STANDARD);
675 
677  XLogRegisterBufData(5, (char *) &bitmapbit, sizeof(uint32));
678 
679  if (update_metap)
680  {
681  XLogRegisterBuffer(6, metabuf, REGBUF_STANDARD);
682  XLogRegisterBufData(6, (char *) &metap->hashm_firstfree, sizeof(uint32));
683  }
684 
685  recptr = XLogInsert(RM_HASH_ID, XLOG_HASH_SQUEEZE_PAGE);
686 
687  PageSetLSN(BufferGetPage(wbuf), recptr);
688  PageSetLSN(BufferGetPage(ovflbuf), recptr);
689 
690  if (BufferIsValid(prevbuf) && !xlrec.is_prev_bucket_same_wrt)
691  PageSetLSN(BufferGetPage(prevbuf), recptr);
692  if (BufferIsValid(nextbuf))
693  PageSetLSN(BufferGetPage(nextbuf), recptr);
694 
695  PageSetLSN(BufferGetPage(mapbuf), recptr);
696 
697  if (update_metap)
698  PageSetLSN(BufferGetPage(metabuf), recptr);
699  }
700 
702 
703  /* release previous bucket if it is not same as write bucket */
704  if (BufferIsValid(prevbuf) && prevblkno != writeblkno)
705  _hash_relbuf(rel, prevbuf);
706 
707  if (BufferIsValid(ovflbuf))
708  _hash_relbuf(rel, ovflbuf);
709 
710  if (BufferIsValid(nextbuf))
711  _hash_relbuf(rel, nextbuf);
712 
713  _hash_relbuf(rel, mapbuf);
714  _hash_relbuf(rel, metabuf);
715 
716  return nextblkno;
717 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
void _hash_pgaddmultitup(Relation rel, Buffer buf, IndexTuple *itups, OffsetNumber *itup_offsets, uint16 nitups)
Definition: hashinsert.c:298
#define HashPageGetBitmap(page)
Definition: hash.h:243
#define LH_BITMAP_PAGE
Definition: hash.h:55
void _hash_pageinit(Page page, Size size)
Definition: hashpage.c:592
#define LH_META_PAGE
Definition: hash.h:56
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
Buffer _hash_getbuf_with_strategy(Relation rel, BlockNumber blkno, int access, int flags, BufferAccessStrategy bstrategy)
Definition: hashpage.c:247
#define END_CRIT_SECTION()
Definition: miscadmin.h:132
#define InvalidBuffer
Definition: buf.h:25
#define START_CRIT_SECTION()
Definition: miscadmin.h:130
uint32 BlockNumber
Definition: block.h:31
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition: hashpage.c:78
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:89
signed int int32
Definition: c.h:256
BlockNumber prevblkno
Definition: hash_xlog.h:175
bool is_prim_bucket_same_wrt
Definition: hash_xlog.h:178
uint16 OffsetNumber
Definition: off.h:24
#define HASH_READ
Definition: hash.h:266
uint32 Bucket
Definition: hash.h:34
#define SizeOfHashSqueezePage
Definition: hash_xlog.h:187
BlockNumber hasho_prevblkno
Definition: hash.h:78
#define ERROR
Definition: elog.h:43
BlockNumber nextblkno
Definition: hash_xlog.h:176
uint32 hashm_nmaps
Definition: hash.h:202
#define HASH_WRITE
Definition: hash.h:267
#define BMPG_MASK(metap)
Definition: hash.h:241
#define REGBUF_STANDARD
Definition: xloginsert.h:35
unsigned int uint32
Definition: c.h:268
#define BMPG_SHIFT(metap)
Definition: hash.h:240
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define HASH_XLOG_FREE_OVFL_BUFS
Definition: hash_xlog.h:22
#define ISSET(A, N)
Definition: hash.h:261
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
void _hash_checkpage(Relation rel, Buffer buf, int flags)
Definition: hashutil.c:159
#define CLRBIT(x, i)
Definition: blutils.c:32
#define HASH_METAPAGE
Definition: hash.h:158
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:147
#define LH_OVERFLOW_PAGE
Definition: hash.h:53
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
uint32 hashm_firstfree
Definition: hash.h:201
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:274
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
#define LH_BUCKET_PAGE
Definition: hash.h:54
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:675
Bucket hasho_bucket
Definition: hash.h:80
bool is_prev_bucket_same_wrt
Definition: hash_xlog.h:181
#define PageGetSpecialPointer(page)
Definition: bufpage.h:323
#define REGBUF_NO_IMAGE
Definition: xloginsert.h:31
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:85
void XLogEnsureRecordSpace(int max_block_id, int ndatas)
Definition: xloginsert.c:146
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
#define RelationNeedsWAL(relation)
Definition: rel.h:506
uint32 _hash_ovflblkno_to_bitno(HashMetaPage metap, BlockNumber ovflblkno)
Definition: hashovfl.c:61
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define HashPageGetMeta(page)
Definition: hash.h:250
int i
#define XLOG_HASH_SQUEEZE_PAGE
Definition: hash_xlog.h:37
BlockNumber hasho_nextblkno
Definition: hash.h:79
#define elog
Definition: elog.h:219
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:990
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:365
BlockNumber hashm_mapp[HASH_MAX_BITMAPS]
Definition: hash.h:206
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74
void _hash_initbitmapbuffer ( Buffer  buf,
uint16  bmsize,
bool  initpage 
)

Definition at line 727 of file hashovfl.c.

References _hash_pageinit(), BufferGetPage, BufferGetPageSize, HashPageOpaqueData::hasho_bucket, HashPageOpaqueData::hasho_flag, HashPageOpaqueData::hasho_nextblkno, HashPageOpaqueData::hasho_page_id, HASHO_PAGE_ID, HashPageOpaqueData::hasho_prevblkno, HashPageGetBitmap, InvalidBlockNumber, LH_BITMAP_PAGE, MemSet, and PageGetSpecialPointer.

Referenced by _hash_addovflpage(), _hash_init(), hash_xlog_add_ovfl_page(), and hash_xlog_init_bitmap_page().

728 {
729  Page pg;
730  HashPageOpaque op;
731  uint32 *freep;
732 
733  pg = BufferGetPage(buf);
734 
735  /* initialize the page */
736  if (initpage)
738 
739  /* initialize the page's special space */
743  op->hasho_bucket = -1;
746 
747  /* set all of the bits to 1 */
748  freep = HashPageGetBitmap(pg);
749  MemSet(freep, 0xFF, bmsize);
750 
751  /*
752  * Set pd_lower just past the end of the bitmap page data. We could even
753  * set pd_lower equal to pd_upper, but this is more precise and makes the
754  * page look compressible to xlog.c.
755  */
756  ((PageHeader) pg)->pd_lower = ((char *) freep + bmsize) - (char *) pg;
757 }
uint16 hasho_page_id
Definition: hash.h:82
#define HashPageGetBitmap(page)
Definition: hash.h:243
#define LH_BITMAP_PAGE
Definition: hash.h:55
void _hash_pageinit(Page page, Size size)
Definition: hashpage.c:592
#define MemSet(start, val, len)
Definition: c.h:857
BlockNumber hasho_prevblkno
Definition: hash.h:78
static char * buf
Definition: pg_test_fsync.c:65
unsigned int uint32
Definition: c.h:268
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:147
PageHeaderData * PageHeader
Definition: bufpage.h:162
Bucket hasho_bucket
Definition: hash.h:80
#define PageGetSpecialPointer(page)
Definition: bufpage.h:323
#define InvalidBlockNumber
Definition: block.h:33
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:85
#define HASHO_PAGE_ID
Definition: hash.h:98
uint16 hasho_flag
Definition: hash.h:81
BlockNumber hasho_nextblkno
Definition: hash.h:79
Pointer Page
Definition: bufpage.h:74
uint32 _hash_ovflblkno_to_bitno ( HashMetaPage  metap,
BlockNumber  ovflblkno 
)

Definition at line 61 of file hashovfl.c.

References ereport, errcode(), errmsg(), ERROR, HashMetaPageData::hashm_ovflpoint, HashMetaPageData::hashm_spares, and i.

Referenced by _hash_freeovflpage(), and hash_bitmap_info().

62 {
63  uint32 splitnum = metap->hashm_ovflpoint;
64  uint32 i;
65  uint32 bitnum;
66 
67  /* Determine the split number containing this page */
68  for (i = 1; i <= splitnum; i++)
69  {
70  if (ovflblkno <= (BlockNumber) (1 << i))
71  break; /* oops */
72  bitnum = ovflblkno - (1 << i);
73 
74  /*
75  * bitnum has to be greater than number of overflow page added in
76  * previous split point. The overflow page at this splitnum (i) if any
77  * should start from ((2 ^ i) + metap->hashm_spares[i - 1] + 1).
78  */
79  if (bitnum > metap->hashm_spares[i - 1] &&
80  bitnum <= metap->hashm_spares[i])
81  return bitnum - 1; /* -1 to convert 1-based to 0-based */
82  }
83 
84  ereport(ERROR,
85  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
86  errmsg("invalid overflow block number %u", ovflblkno)));
87  return 0; /* keep compiler quiet */
88 }
int errcode(int sqlerrcode)
Definition: elog.c:575
uint32 BlockNumber
Definition: block.h:31
#define ERROR
Definition: elog.h:43
unsigned int uint32
Definition: c.h:268
#define ereport(elevel, rest)
Definition: elog.h:122
uint32 hashm_ovflpoint
Definition: hash.h:199
uint32 hashm_spares[HASH_MAX_SPLITPOINTS]
Definition: hash.h:204
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
void _hash_squeezebucket ( Relation  rel,
Bucket  bucket,
BlockNumber  bucket_blkno,
Buffer  bucket_buf,
BufferAccessStrategy  bstrategy 
)

Definition at line 792 of file hashovfl.c.

References _hash_freeovflpage(), _hash_getbuf_with_strategy(), _hash_pgaddmultitup(), _hash_relbuf(), Assert, BlockNumberIsValid, BUFFER_LOCK_UNLOCK, BufferGetPage, CopyIndexTuple(), END_CRIT_SECTION, FirstOffsetNumber, HASH_WRITE, HashPageOpaqueData::hasho_bucket, HashPageOpaqueData::hasho_nextblkno, HashPageOpaqueData::hasho_prevblkno, i, IndexTupleDSize, InvalidBuffer, xl_hash_move_page_contents::is_prim_bucket_same_wrt, ItemIdIsDead, LH_OVERFLOW_PAGE, LockBuffer(), MarkBufferDirty(), MAXALIGN, MaxIndexTuplesPerPage, MaxOffsetNumber, xl_hash_move_page_contents::ntups, OffsetNumberNext, PageGetFreeSpaceForMultipleTuples(), PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageGetSpecialPointer, PageIndexMultiDelete(), PageIsEmpty, PageSetLSN, pfree(), REGBUF_NO_IMAGE, REGBUF_STANDARD, RelationNeedsWAL, SizeOfHashMovePageContents, START_CRIT_SECTION, XLOG_HASH_MOVE_PAGE_CONTENTS, XLogBeginInsert(), XLogEnsureRecordSpace(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by hashbucketcleanup().

797 {
798  BlockNumber wblkno;
799  BlockNumber rblkno;
800  Buffer wbuf;
801  Buffer rbuf;
802  Page wpage;
803  Page rpage;
804  HashPageOpaque wopaque;
805  HashPageOpaque ropaque;
806 
807  /*
808  * start squeezing into the primary bucket page.
809  */
810  wblkno = bucket_blkno;
811  wbuf = bucket_buf;
812  wpage = BufferGetPage(wbuf);
813  wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage);
814 
815  /*
816  * if there aren't any overflow pages, there's nothing to squeeze. caller
817  * is responsible for releasing the pin on primary bucket page.
818  */
819  if (!BlockNumberIsValid(wopaque->hasho_nextblkno))
820  {
822  return;
823  }
824 
825  /*
826  * Find the last page in the bucket chain by starting at the base bucket
827  * page and working forward. Note: we assume that a hash bucket chain is
828  * usually smaller than the buffer ring being used by VACUUM, else using
829  * the access strategy here would be counterproductive.
830  */
831  rbuf = InvalidBuffer;
832  ropaque = wopaque;
833  do
834  {
835  rblkno = ropaque->hasho_nextblkno;
836  if (rbuf != InvalidBuffer)
837  _hash_relbuf(rel, rbuf);
838  rbuf = _hash_getbuf_with_strategy(rel,
839  rblkno,
840  HASH_WRITE,
842  bstrategy);
843  rpage = BufferGetPage(rbuf);
844  ropaque = (HashPageOpaque) PageGetSpecialPointer(rpage);
845  Assert(ropaque->hasho_bucket == bucket);
846  } while (BlockNumberIsValid(ropaque->hasho_nextblkno));
847 
848  /*
849  * squeeze the tuples.
850  */
851  for (;;)
852  {
853  OffsetNumber roffnum;
854  OffsetNumber maxroffnum;
855  OffsetNumber deletable[MaxOffsetNumber];
857  Size tups_size[MaxIndexTuplesPerPage];
858  OffsetNumber itup_offsets[MaxIndexTuplesPerPage];
859  uint16 ndeletable = 0;
860  uint16 nitups = 0;
861  Size all_tups_size = 0;
862  int i;
863  bool retain_pin = false;
864 
865 readpage:
866  /* Scan each tuple in "read" page */
867  maxroffnum = PageGetMaxOffsetNumber(rpage);
868  for (roffnum = FirstOffsetNumber;
869  roffnum <= maxroffnum;
870  roffnum = OffsetNumberNext(roffnum))
871  {
872  IndexTuple itup;
873  Size itemsz;
874 
875  /* skip dead tuples */
876  if (ItemIdIsDead(PageGetItemId(rpage, roffnum)))
877  continue;
878 
879  itup = (IndexTuple) PageGetItem(rpage,
880  PageGetItemId(rpage, roffnum));
881  itemsz = IndexTupleDSize(*itup);
882  itemsz = MAXALIGN(itemsz);
883 
884  /*
885  * Walk up the bucket chain, looking for a page big enough for
886  * this item and all other accumulated items. Exit if we reach
887  * the read page.
888  */
889  while (PageGetFreeSpaceForMultipleTuples(wpage, nitups + 1) < (all_tups_size + itemsz))
890  {
891  Buffer next_wbuf = InvalidBuffer;
892  bool tups_moved = false;
893 
894  Assert(!PageIsEmpty(wpage));
895 
896  if (wblkno == bucket_blkno)
897  retain_pin = true;
898 
899  wblkno = wopaque->hasho_nextblkno;
900  Assert(BlockNumberIsValid(wblkno));
901 
902  /* don't need to move to next page if we reached the read page */
903  if (wblkno != rblkno)
904  next_wbuf = _hash_getbuf_with_strategy(rel,
905  wblkno,
906  HASH_WRITE,
908  bstrategy);
909 
910  if (nitups > 0)
911  {
912  Assert(nitups == ndeletable);
913 
914  /*
915  * This operation needs to log multiple tuples, prepare
916  * WAL for that.
917  */
918  if (RelationNeedsWAL(rel))
919  XLogEnsureRecordSpace(0, 3 + nitups);
920 
922 
923  /*
924  * we have to insert tuples on the "write" page, being
925  * careful to preserve hashkey ordering. (If we insert
926  * many tuples into the same "write" page it would be
927  * worth qsort'ing them).
928  */
929  _hash_pgaddmultitup(rel, wbuf, itups, itup_offsets, nitups);
930  MarkBufferDirty(wbuf);
931 
932  /* Delete tuples we already moved off read page */
933  PageIndexMultiDelete(rpage, deletable, ndeletable);
934  MarkBufferDirty(rbuf);
935 
936  /* XLOG stuff */
937  if (RelationNeedsWAL(rel))
938  {
939  XLogRecPtr recptr;
941 
942  xlrec.ntups = nitups;
943  xlrec.is_prim_bucket_same_wrt = (wbuf == bucket_buf) ? true : false;
944 
945  XLogBeginInsert();
947 
948  /*
949  * bucket buffer needs to be registered to ensure that
950  * we can acquire a cleanup lock on it during replay.
951  */
952  if (!xlrec.is_prim_bucket_same_wrt)
954 
956  XLogRegisterBufData(1, (char *) itup_offsets,
957  nitups * sizeof(OffsetNumber));
958  for (i = 0; i < nitups; i++)
959  XLogRegisterBufData(1, (char *) itups[i], tups_size[i]);
960 
962  XLogRegisterBufData(2, (char *) deletable,
963  ndeletable * sizeof(OffsetNumber));
964 
965  recptr = XLogInsert(RM_HASH_ID, XLOG_HASH_MOVE_PAGE_CONTENTS);
966 
967  PageSetLSN(BufferGetPage(wbuf), recptr);
968  PageSetLSN(BufferGetPage(rbuf), recptr);
969  }
970 
972 
973  tups_moved = true;
974  }
975 
976  /*
977  * release the lock on previous page after acquiring the lock
978  * on next page
979  */
980  if (retain_pin)
982  else
983  _hash_relbuf(rel, wbuf);
984 
985  /* nothing more to do if we reached the read page */
986  if (rblkno == wblkno)
987  {
988  _hash_relbuf(rel, rbuf);
989  return;
990  }
991 
992  wbuf = next_wbuf;
993  wpage = BufferGetPage(wbuf);
994  wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage);
995  Assert(wopaque->hasho_bucket == bucket);
996  retain_pin = false;
997 
998  /* be tidy */
999  for (i = 0; i < nitups; i++)
1000  pfree(itups[i]);
1001  nitups = 0;
1002  all_tups_size = 0;
1003  ndeletable = 0;
1004 
1005  /*
1006  * after moving the tuples, rpage would have been compacted,
1007  * so we need to rescan it.
1008  */
1009  if (tups_moved)
1010  goto readpage;
1011  }
1012 
1013  /* remember tuple for deletion from "read" page */
1014  deletable[ndeletable++] = roffnum;
1015 
1016  /*
1017  * we need a copy of index tuples as they can be freed as part of
1018  * overflow page, however we need them to write a WAL record in
1019  * _hash_freeovflpage.
1020  */
1021  itups[nitups] = CopyIndexTuple(itup);
1022  tups_size[nitups++] = itemsz;
1023  all_tups_size += itemsz;
1024  }
1025 
1026  /*
1027  * If we reach here, there are no live tuples on the "read" page ---
1028  * it was empty when we got to it, or we moved them all. So we can
1029  * just free the page without bothering with deleting tuples
1030  * individually. Then advance to the previous "read" page.
1031  *
1032  * Tricky point here: if our read and write pages are adjacent in the
1033  * bucket chain, our write lock on wbuf will conflict with
1034  * _hash_freeovflpage's attempt to update the sibling links of the
1035  * removed page. In that case, we don't need to lock it again.
1036  */
1037  rblkno = ropaque->hasho_prevblkno;
1038  Assert(BlockNumberIsValid(rblkno));
1039 
1040  /* free this overflow page (releases rbuf) */
1041  _hash_freeovflpage(rel, bucket_buf, rbuf, wbuf, itups, itup_offsets,
1042  tups_size, nitups, bstrategy);
1043 
1044  /* be tidy */
1045  for (i = 0; i < nitups; i++)
1046  pfree(itups[i]);
1047 
1048  /* are we freeing the page adjacent to wbuf? */
1049  if (rblkno == wblkno)
1050  {
1051  /* retain the pin on primary bucket page till end of bucket scan */
1052  if (wblkno == bucket_blkno)
1054  else
1055  _hash_relbuf(rel, wbuf);
1056  return;
1057  }
1058 
1059  rbuf = _hash_getbuf_with_strategy(rel,
1060  rblkno,
1061  HASH_WRITE,
1063  bstrategy);
1064  rpage = BufferGetPage(rbuf);
1065  ropaque = (HashPageOpaque) PageGetSpecialPointer(rpage);
1066  Assert(ropaque->hasho_bucket == bucket);
1067  }
1068 
1069  /* NOTREACHED */
1070 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
void _hash_pgaddmultitup(Relation rel, Buffer buf, IndexTuple *itups, OffsetNumber *itup_offsets, uint16 nitups)
Definition: hashinsert.c:298
#define PageIsEmpty(page)
Definition: bufpage.h:219
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define MaxOffsetNumber
Definition: off.h:28
Buffer _hash_getbuf_with_strategy(Relation rel, BlockNumber blkno, int access, int flags, BufferAccessStrategy bstrategy)
Definition: hashpage.c:247
#define END_CRIT_SECTION()
Definition: miscadmin.h:132
#define InvalidBuffer
Definition: buf.h:25
#define START_CRIT_SECTION()
Definition: miscadmin.h:130
uint32 BlockNumber
Definition: block.h:31
#define SizeOfHashMovePageContents
Definition: hash_xlog.h:158
#define ItemIdIsDead(itemId)
Definition: itemid.h:112
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:354
uint16 OffsetNumber
Definition: off.h:24
unsigned short uint16
Definition: c.h:267
void pfree(void *pointer)
Definition: mcxt.c:950
BlockNumber hasho_prevblkno
Definition: hash.h:78
IndexTuple CopyIndexTuple(IndexTuple source)
Definition: indextuple.c:434
#define IndexTupleDSize(itup)
Definition: itup.h:71
#define HASH_WRITE
Definition: hash.h:267
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
#define REGBUF_STANDARD
Definition: xloginsert.h:35
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
#define XLOG_HASH_MOVE_PAGE_CONTENTS
Definition: hash_xlog.h:35
#define LH_OVERFLOW_PAGE
Definition: hash.h:53
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
Size PageGetFreeSpaceForMultipleTuples(Page page, int ntups)
Definition: bufpage.c:609
void _hash_relbuf(Relation rel, Buffer buf)
Definition: hashpage.c:274
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:675
Bucket hasho_bucket
Definition: hash.h:80
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:836
#define OffsetNumberNext(offsetNumber)
Definition: off.h:53
size_t Size
Definition: c.h:356
#define PageGetSpecialPointer(page)
Definition: bufpage.h:323
#define REGBUF_NO_IMAGE
Definition: xloginsert.h:31
HashPageOpaqueData * HashPageOpaque
Definition: hash.h:85
void XLogEnsureRecordSpace(int max_block_id, int ndatas)
Definition: xloginsert.c:146
#define MAXALIGN(LEN)
Definition: c.h:588
#define RelationNeedsWAL(relation)
Definition: rel.h:506
BlockNumber _hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf, Buffer wbuf, IndexTuple *itups, OffsetNumber *itup_offsets, Size *tups_size, uint16 nitups, BufferAccessStrategy bstrategy)
Definition: hashovfl.c:487
#define MaxIndexTuplesPerPage
Definition: itup.h:137
int i
BlockNumber hasho_nextblkno
Definition: hash.h:79
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:365
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
Pointer Page
Definition: bufpage.h:74
static BlockNumber bitno_to_blkno ( HashMetaPage  metap,
uint32  ovflbitnum 
)
static

Definition at line 34 of file hashovfl.c.

References HashMetaPageData::hashm_ovflpoint, HashMetaPageData::hashm_spares, and i.

Referenced by _hash_addovflpage().

35 {
36  uint32 splitnum = metap->hashm_ovflpoint;
37  uint32 i;
38 
39  /* Convert zero-based bitnumber to 1-based page number */
40  ovflbitnum += 1;
41 
42  /* Determine the split number for this page (must be >= 1) */
43  for (i = 1;
44  i < splitnum && ovflbitnum > metap->hashm_spares[i];
45  i++)
46  /* loop */ ;
47 
48  /*
49  * Convert to absolute page number by adding the number of bucket pages
50  * that exist before this split point.
51  */
52  return (BlockNumber) ((1 << i) + ovflbitnum);
53 }
uint32 BlockNumber
Definition: block.h:31
unsigned int uint32
Definition: c.h:268
uint32 hashm_ovflpoint
Definition: hash.h:199
uint32 hashm_spares[HASH_MAX_SPLITPOINTS]
Definition: hash.h:204
int i