Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e573459

Browse files
committed
Clean up API for ambulkdelete/amvacuumcleanup as per today's discussion.
This formulation requires every AM to provide amvacuumcleanup, unlike before, but it's surely a whole lot cleaner. Also, add an 'amstorage' column to pg_am so that we can get rid of hardwired knowledge in DefineOpClass().
1 parent d3171dd commit e573459

File tree

16 files changed

+308
-373
lines changed

16 files changed

+308
-373
lines changed

doc/src/sgml/catalogs.sgml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.121 2006/03/10 19:10:46 momjian Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.122 2006/05/02 22:25:09 tgl Exp $ -->
22
<!--
33
Documentation of the system catalogs, directed toward PostgreSQL developers
44
-->
@@ -394,13 +394,27 @@
394394
<entry>Does the access method support null index entries?</entry>
395395
</row>
396396

397+
<row>
398+
<entry><structfield>amstorage</structfield></entry>
399+
<entry><type>bool</type></entry>
400+
<entry></entry>
401+
<entry>Can index storage data type differ from column data type?</entry>
402+
</row>
403+
397404
<row>
398405
<entry><structfield>amconcurrent</structfield></entry>
399406
<entry><type>bool</type></entry>
400407
<entry></entry>
401408
<entry>Does the access method support concurrent updates?</entry>
402409
</row>
403410

411+
<row>
412+
<entry><structfield>amclusterable</structfield></entry>
413+
<entry><type>bool</type></entry>
414+
<entry></entry>
415+
<entry>Can an index of this type be CLUSTERed on?</entry>
416+
</row>
417+
404418
<row>
405419
<entry><structfield>aminsert</structfield></entry>
406420
<entry><type>regproc</type></entry>

doc/src/sgml/indexam.sgml

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.9 2006/03/10 19:10:48 momjian Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.10 2006/05/02 22:25:09 tgl Exp $ -->
22

33
<chapter id="indexam">
44
<title>Index Access Method Interface Definition</title>
@@ -184,44 +184,52 @@ aminsert (Relation indexRelation,
184184
<para>
185185
<programlisting>
186186
IndexBulkDeleteResult *
187-
ambulkdelete (Relation indexRelation,
187+
ambulkdelete (IndexVacuumInfo *info,
188+
IndexBulkDeleteResult *stats,
188189
IndexBulkDeleteCallback callback,
189190
void *callback_state);
190191
</programlisting>
191192
Delete tuple(s) from the index. This is a <quote>bulk delete</> operation
192193
that is intended to be implemented by scanning the whole index and checking
193194
each entry to see if it should be deleted.
194-
The passed-in <literal>callback</> function may be called, in the style
195+
The passed-in <literal>callback</> function must be called, in the style
195196
<literal>callback(<replaceable>TID</>, callback_state) returns bool</literal>,
196197
to determine whether any particular index entry, as identified by its
197198
referenced TID, is to be deleted. Must return either NULL or a palloc'd
198199
struct containing statistics about the effects of the deletion operation.
200+
It is OK to return NULL if no information needs to be passed on to
201+
<function>amvacuumcleanup</>.
199202
</para>
200203

201204
<para>
202-
If <literal>callback_state</> is NULL then no tuples are to be deleted.
203-
The index AM may choose to optimize this case (eg by not scanning the
204-
index) but it is still expected to deliver accurate statistics.
205+
Because of limited <varname>maintenance_work_mem</>,
206+
<function>ambulkdelete</> may need to be called more than once when many
207+
tuples are to be deleted. The <literal>stats</> argument is the result
208+
of the previous call for this index (it is NULL for the first call within a
209+
<command>VACUUM</> operation). This allows the AM to accumulate statistics
210+
across the whole operation. Typically, <function>ambulkdelete</> will
211+
modify and return the same struct if the passed <literal>stats</> is not
212+
null.
205213
</para>
206214

207215
<para>
208216
<programlisting>
209217
IndexBulkDeleteResult *
210-
amvacuumcleanup (Relation indexRelation,
211-
IndexVacuumCleanupInfo *info,
218+
amvacuumcleanup (IndexVacuumInfo *info,
212219
IndexBulkDeleteResult *stats);
213220
</programlisting>
214-
Clean up after a <command>VACUUM</command> operation (one or more
215-
<function>ambulkdelete</> calls). An index access method does not have
216-
to provide this function (if so, the entry in <structname>pg_am</> must
217-
be zero). If it is provided, it is typically used for bulk cleanup
218-
such as reclaiming empty index pages. <literal>info</>
219-
provides some additional arguments such as a message level for statistical
220-
reports, and <literal>stats</> is whatever the last
221-
<function>ambulkdelete</> call returned. <function>amvacuumcleanup</>
222-
may replace or modify this struct before returning it. If the result
223-
is not NULL it must be a palloc'd struct. The statistics it contains
224-
will be reported by <command>VACUUM</> if <literal>VERBOSE</> is given.
221+
Clean up after a <command>VACUUM</command> operation (zero or more
222+
<function>ambulkdelete</> calls). This does not have to do anything
223+
beyond returning index statistics, but it may perform bulk cleanup
224+
such as reclaiming empty index pages. <literal>stats</> is whatever the
225+
last <function>ambulkdelete</> call returned, or NULL if
226+
<function>ambulkdelete</> was not called because no tuples needed to be
227+
deleted. If the result is not NULL it must be a palloc'd struct.
228+
The statistics it contains will be used to update <structname>pg_class</>,
229+
and will be reported by <command>VACUUM</> if <literal>VERBOSE</> is given.
230+
It is OK to return NULL if the index was not changed at all during the
231+
<command>VACUUM</command> operation, but otherwise correct stats should
232+
be returned.
225233
</para>
226234

227235
<para>

src/backend/access/gin/ginvacuum.c

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.1 2006/05/02 11:28:54 teodor Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.2 2006/05/02 22:25:10 tgl Exp $
1212
*-------------------------------------------------------------------------
1313
*/
1414

@@ -474,17 +474,25 @@ ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint3
474474

475475
Datum
476476
ginbulkdelete(PG_FUNCTION_ARGS) {
477-
Relation index = (Relation) PG_GETARG_POINTER(0);
478-
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1);
479-
void *callback_state = (void *) PG_GETARG_POINTER(2);
477+
IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
478+
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
479+
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
480+
void *callback_state = (void *) PG_GETARG_POINTER(3);
481+
Relation index = info->index;
480482
BlockNumber blkno = GIN_ROOT_BLKNO;
481483
GinVacuumState gvs;
482484
Buffer buffer;
483485
BlockNumber rootOfPostingTree[ BLCKSZ/ (sizeof(IndexTupleData)+sizeof(ItemId)) ];
484486
uint32 nRoot;
485487

488+
/* first time through? */
489+
if (stats == NULL)
490+
stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
491+
/* we'll re-count the tuples each time */
492+
stats->num_index_tuples = 0;
493+
486494
gvs.index = index;
487-
gvs.result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
495+
gvs.result = stats;
488496
gvs.callback = callback;
489497
gvs.callback_state = callback_state;
490498
initGinState(&gvs.ginstate, index);
@@ -564,9 +572,9 @@ ginbulkdelete(PG_FUNCTION_ARGS) {
564572

565573
Datum
566574
ginvacuumcleanup(PG_FUNCTION_ARGS) {
567-
Relation index = (Relation) PG_GETARG_POINTER(0);
568-
IndexVacuumCleanupInfo *info = (IndexVacuumCleanupInfo *) PG_GETARG_POINTER(1);
569-
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(2);
575+
IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
576+
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
577+
Relation index = info->index;
570578
bool needLock = !RELATION_IS_LOCAL(index);
571579
BlockNumber npages,
572580
blkno;
@@ -576,6 +584,15 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
576584
BlockNumber lastBlock = GIN_ROOT_BLKNO,
577585
lastFilledBlock = GIN_ROOT_BLKNO;
578586

587+
/* Set up all-zero stats if ginbulkdelete wasn't called */
588+
if (stats == NULL)
589+
stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
590+
/*
591+
* XXX we always report the heap tuple count as the number of index
592+
* entries. This is bogus if the index is partial, but it's real hard
593+
* to tell how many distinct heap entries are referenced by a GIN index.
594+
*/
595+
stats->num_index_tuples = info->num_heap_tuples;
579596

580597
if (info->vacuum_full) {
581598
LockRelation(index, AccessExclusiveLock);

src/backend/access/gist/gistvacuum.c

Lines changed: 33 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.18 2006/03/31 23:32:05 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.19 2006/05/02 22:25:10 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -343,9 +343,9 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
343343
Datum
344344
gistvacuumcleanup(PG_FUNCTION_ARGS)
345345
{
346-
Relation rel = (Relation) PG_GETARG_POINTER(0);
347-
IndexVacuumCleanupInfo *info = (IndexVacuumCleanupInfo *) PG_GETARG_POINTER(1);
348-
GistBulkDeleteResult *stats = (GistBulkDeleteResult *) PG_GETARG_POINTER(2);
346+
IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
347+
GistBulkDeleteResult *stats = (GistBulkDeleteResult *) PG_GETARG_POINTER(1);
348+
Relation rel = info->index;
349349
BlockNumber npages,
350350
blkno;
351351
BlockNumber nFreePages,
@@ -355,6 +355,19 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
355355
lastFilledBlock = GIST_ROOT_BLKNO;
356356
bool needLock;
357357

358+
/* Set up all-zero stats if gistbulkdelete wasn't called */
359+
if (stats == NULL)
360+
{
361+
stats = (GistBulkDeleteResult *) palloc0(sizeof(GistBulkDeleteResult));
362+
/* use heap's tuple count */
363+
Assert(info->num_heap_tuples >= 0);
364+
stats->std.num_index_tuples = info->num_heap_tuples;
365+
/*
366+
* XXX the above is wrong if index is partial. Would it be OK to
367+
* just return NULL, or is there work we must do below?
368+
*/
369+
}
370+
358371
/* gistVacuumUpdate may cause hard work */
359372
if (info->vacuum_full)
360373
{
@@ -460,13 +473,6 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
460473
if (info->vacuum_full)
461474
UnlockRelation(rel, AccessExclusiveLock);
462475

463-
/* if gistbulkdelete skipped the scan, use heap's tuple count */
464-
if (stats->std.num_index_tuples < 0)
465-
{
466-
Assert(info->num_heap_tuples >= 0);
467-
stats->std.num_index_tuples = info->num_heap_tuples;
468-
}
469-
470476
PG_RETURN_POINTER(stats);
471477
}
472478

@@ -509,36 +515,22 @@ pushStackIfSplited(Page page, GistBDItem *stack)
509515
Datum
510516
gistbulkdelete(PG_FUNCTION_ARGS)
511517
{
512-
Relation rel = (Relation) PG_GETARG_POINTER(0);
513-
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1);
514-
void *callback_state = (void *) PG_GETARG_POINTER(2);
515-
GistBulkDeleteResult *result;
518+
IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
519+
GistBulkDeleteResult *stats = (GistBulkDeleteResult *) PG_GETARG_POINTER(1);
520+
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
521+
void *callback_state = (void *) PG_GETARG_POINTER(3);
522+
Relation rel = info->index;
516523
GistBDItem *stack,
517524
*ptr;
518-
bool needLock;
519525

520-
result = (GistBulkDeleteResult *) palloc0(sizeof(GistBulkDeleteResult));
526+
/* first time through? */
527+
if (stats == NULL)
528+
stats = (GistBulkDeleteResult *) palloc0(sizeof(GistBulkDeleteResult));
529+
/* we'll re-count the tuples each time */
530+
stats->std.num_index_tuples = 0;
521531

522-
/*
523-
* We can skip the scan entirely if there's nothing to delete (indicated
524-
* by callback_state == NULL) and the index isn't partial. For a partial
525-
* index we must scan in order to derive a trustworthy tuple count.
526-
*
527-
* XXX as of PG 8.2 this is dead code because GIST indexes are always
528-
* effectively partial ... but keep it anyway in case our null-handling
529-
* gets fixed.
530-
*/
531-
if (callback_state || vac_is_partial_index(rel))
532-
{
533-
stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
534-
stack->blkno = GIST_ROOT_BLKNO;
535-
}
536-
else
537-
{
538-
/* skip scan and set flag for gistvacuumcleanup */
539-
stack = NULL;
540-
result->std.num_index_tuples = -1;
541-
}
532+
stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
533+
stack->blkno = GIST_ROOT_BLKNO;
542534

543535
while (stack)
544536
{
@@ -601,11 +593,11 @@ gistbulkdelete(PG_FUNCTION_ARGS)
601593
i--;
602594
maxoff--;
603595
ntodelete++;
604-
result->std.tuples_removed += 1;
596+
stats->std.tuples_removed += 1;
605597
Assert(maxoff == PageGetMaxOffsetNumber(page));
606598
}
607599
else
608-
result->std.num_index_tuples += 1;
600+
stats->std.num_index_tuples += 1;
609601
}
610602

611603
if (ntodelete)
@@ -658,7 +650,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
658650
stack->next = ptr;
659651

660652
if (GistTupleIsInvalid(idxtuple))
661-
result->needFullVacuum = true;
653+
stats->needFullVacuum = true;
662654
}
663655
}
664656

@@ -671,13 +663,5 @@ gistbulkdelete(PG_FUNCTION_ARGS)
671663
vacuum_delay_point();
672664
}
673665

674-
needLock = !RELATION_IS_LOCAL(rel);
675-
676-
if (needLock)
677-
LockRelationForExtension(rel, ExclusiveLock);
678-
result->std.num_pages = RelationGetNumberOfBlocks(rel);
679-
if (needLock)
680-
UnlockRelationForExtension(rel, ExclusiveLock);
681-
682-
PG_RETURN_POINTER(result);
666+
PG_RETURN_POINTER(stats);
683667
}

0 commit comments

Comments
 (0)