You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

blvacuum.c 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*-------------------------------------------------------------------------
  2. *
  3. * blvacuum.c
  4. * Bloom VACUUM functions.
  5. *
  6. * Copyright (c) 2016-2019, PostgreSQL Global Development Group
  7. *
  8. * IDENTIFICATION
  9. * contrib/bloom/blvacuum.c
  10. *
  11. *-------------------------------------------------------------------------
  12. */
  13. #include "postgres.h"
  14. #include "access/genam.h"
  15. #include "bloom.h"
  16. #include "catalog/storage.h"
  17. #include "commands/vacuum.h"
  18. #include "miscadmin.h"
  19. #include "postmaster/autovacuum.h"
  20. #include "storage/bufmgr.h"
  21. #include "storage/indexfsm.h"
  22. #include "storage/lmgr.h"
  23. /*
  24. * Bulk deletion of all index entries pointing to a set of heap tuples.
  25. * The set of target tuples is specified via a callback routine that tells
  26. * whether any given heap tuple (identified by ItemPointer) is being deleted.
  27. *
  28. * Result: a palloc'd struct containing statistical info for VACUUM displays.
  29. */
  30. IndexBulkDeleteResult *
  31. blbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
  32. IndexBulkDeleteCallback callback, void *callback_state)
  33. {
  34. Relation index = info->index;
  35. BlockNumber blkno,
  36. npages;
  37. FreeBlockNumberArray notFullPage;
  38. int countPage = 0;
  39. BloomState state;
  40. Buffer buffer;
  41. Page page;
  42. BloomMetaPageData *metaData;
  43. GenericXLogState *gxlogState;
  44. if (stats == NULL)
  45. stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
  46. initBloomState(&state, index);
  47. /*
  48. * Iterate over the pages. We don't care about concurrently added pages,
  49. * they can't contain tuples to delete.
  50. */
  51. npages = RelationGetNumberOfBlocks(index);
  52. for (blkno = BLOOM_HEAD_BLKNO; blkno < npages; blkno++)
  53. {
  54. BloomTuple *itup,
  55. *itupPtr,
  56. *itupEnd;
  57. vacuum_delay_point();
  58. buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
  59. RBM_NORMAL, info->strategy);
  60. LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  61. gxlogState = GenericXLogStart(index);
  62. page = GenericXLogRegisterBuffer(gxlogState, buffer, 0);
  63. /* Ignore empty/deleted pages until blvacuumcleanup() */
  64. if (PageIsNew(page) || BloomPageIsDeleted(page))
  65. {
  66. UnlockReleaseBuffer(buffer);
  67. GenericXLogAbort(gxlogState);
  68. continue;
  69. }
  70. /*
  71. * Iterate over the tuples. itup points to current tuple being
  72. * scanned, itupPtr points to where to save next non-deleted tuple.
  73. */
  74. itup = itupPtr = BloomPageGetTuple(&state, page, FirstOffsetNumber);
  75. itupEnd = BloomPageGetTuple(&state, page,
  76. OffsetNumberNext(BloomPageGetMaxOffset(page)));
  77. while (itup < itupEnd)
  78. {
  79. /* Do we have to delete this tuple? */
  80. if (callback(&itup->heapPtr, callback_state))
  81. {
  82. /* Yes; adjust count of tuples that will be left on page */
  83. BloomPageGetOpaque(page)->maxoff--;
  84. stats->tuples_removed += 1;
  85. }
  86. else
  87. {
  88. /* No; copy it to itupPtr++, but skip copy if not needed */
  89. if (itupPtr != itup)
  90. memmove((Pointer) itupPtr, (Pointer) itup,
  91. state.sizeOfBloomTuple);
  92. itupPtr = BloomPageGetNextTuple(&state, itupPtr);
  93. }
  94. itup = BloomPageGetNextTuple(&state, itup);
  95. }
  96. /* Assert that we counted correctly */
  97. Assert(itupPtr == BloomPageGetTuple(&state, page,
  98. OffsetNumberNext(BloomPageGetMaxOffset(page))));
  99. /*
  100. * Add page to new notFullPage list if we will not mark page as
  101. * deleted and there is free space on it
  102. */
  103. if (BloomPageGetMaxOffset(page) != 0 &&
  104. BloomPageGetFreeSpace(&state, page) >= state.sizeOfBloomTuple &&
  105. countPage < BloomMetaBlockN)
  106. notFullPage[countPage++] = blkno;
  107. /* Did we delete something? */
  108. if (itupPtr != itup)
  109. {
  110. /* Is it empty page now? */
  111. if (BloomPageGetMaxOffset(page) == 0)
  112. BloomPageSetDeleted(page);
  113. /* Adjust pd_lower */
  114. ((PageHeader) page)->pd_lower = (Pointer) itupPtr - page;
  115. /* Finish WAL-logging */
  116. GenericXLogFinish(gxlogState);
  117. }
  118. else
  119. {
  120. /* Didn't change anything: abort WAL-logging */
  121. GenericXLogAbort(gxlogState);
  122. }
  123. UnlockReleaseBuffer(buffer);
  124. }
  125. /*
  126. * Update the metapage's notFullPage list with whatever we found. Our
  127. * info could already be out of date at this point, but blinsert() will
  128. * cope if so.
  129. */
  130. buffer = ReadBuffer(index, BLOOM_METAPAGE_BLKNO);
  131. LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  132. gxlogState = GenericXLogStart(index);
  133. page = GenericXLogRegisterBuffer(gxlogState, buffer, 0);
  134. metaData = BloomPageGetMeta(page);
  135. memcpy(metaData->notFullPage, notFullPage, sizeof(BlockNumber) * countPage);
  136. metaData->nStart = 0;
  137. metaData->nEnd = countPage;
  138. GenericXLogFinish(gxlogState);
  139. UnlockReleaseBuffer(buffer);
  140. return stats;
  141. }
  142. /*
  143. * Post-VACUUM cleanup.
  144. *
  145. * Result: a palloc'd struct containing statistical info for VACUUM displays.
  146. */
  147. IndexBulkDeleteResult *
  148. blvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
  149. {
  150. Relation index = info->index;
  151. BlockNumber npages,
  152. blkno;
  153. if (info->analyze_only)
  154. return stats;
  155. if (stats == NULL)
  156. stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
  157. /*
  158. * Iterate over the pages: insert deleted pages into FSM and collect
  159. * statistics.
  160. */
  161. npages = RelationGetNumberOfBlocks(index);
  162. stats->num_pages = npages;
  163. stats->pages_free = 0;
  164. stats->num_index_tuples = 0;
  165. for (blkno = BLOOM_HEAD_BLKNO; blkno < npages; blkno++)
  166. {
  167. Buffer buffer;
  168. Page page;
  169. vacuum_delay_point();
  170. buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
  171. RBM_NORMAL, info->strategy);
  172. LockBuffer(buffer, BUFFER_LOCK_SHARE);
  173. page = (Page) BufferGetPage(buffer);
  174. if (PageIsNew(page) || BloomPageIsDeleted(page))
  175. {
  176. RecordFreeIndexPage(index, blkno);
  177. stats->pages_free++;
  178. }
  179. else
  180. {
  181. stats->num_index_tuples += BloomPageGetMaxOffset(page);
  182. }
  183. UnlockReleaseBuffer(buffer);
  184. }
  185. IndexFreeSpaceMapVacuum(info->index);
  186. return stats;
  187. }