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