|
24 | 24 | #include "miscadmin.h"
|
25 | 25 | #include "utils/memutils.h"
|
26 | 26 | #include "utils/rel.h"
|
| 27 | +#include "storage/indexfsm.h" |
27 | 28 |
|
28 | 29 | /* GUC parameter */
|
29 | 30 | int gin_pending_list_limit = 0;
|
@@ -521,10 +522,12 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
|
521 | 522 | int64 nDeletedHeapTuples = 0;
|
522 | 523 | ginxlogDeleteListPages data;
|
523 | 524 | Buffer buffers[GIN_NDELETE_AT_ONCE];
|
| 525 | + BlockNumber freespace[GIN_NDELETE_AT_ONCE]; |
524 | 526 |
|
525 | 527 | data.ndeleted = 0;
|
526 | 528 | while (data.ndeleted < GIN_NDELETE_AT_ONCE && blknoToDelete != newHead)
|
527 | 529 | {
|
| 530 | + freespace[data.ndeleted] = blknoToDelete; |
528 | 531 | buffers[data.ndeleted] = ReadBuffer(index, blknoToDelete);
|
529 | 532 | LockBuffer(buffers[data.ndeleted], GIN_EXCLUSIVE);
|
530 | 533 | page = BufferGetPage(buffers[data.ndeleted]);
|
@@ -609,6 +612,10 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
|
609 | 612 | UnlockReleaseBuffer(buffers[i]);
|
610 | 613 |
|
611 | 614 | END_CRIT_SECTION();
|
| 615 | + |
| 616 | + for (i = 0; i < data.ndeleted; i++) |
| 617 | + RecordFreeIndexPage(index, freespace[i]); |
| 618 | + |
612 | 619 | } while (blknoToDelete != newHead);
|
613 | 620 |
|
614 | 621 | return false;
|
@@ -744,6 +751,7 @@ ginInsertCleanup(GinState *ginstate,
|
744 | 751 | BuildAccumulator accum;
|
745 | 752 | KeyArray datums;
|
746 | 753 | BlockNumber blkno;
|
| 754 | + bool fsm_vac = false; |
747 | 755 |
|
748 | 756 | metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO);
|
749 | 757 | LockBuffer(metabuffer, GIN_SHARE);
|
@@ -793,6 +801,7 @@ ginInsertCleanup(GinState *ginstate,
|
793 | 801 | {
|
794 | 802 | /* another cleanup process is running concurrently */
|
795 | 803 | UnlockReleaseBuffer(buffer);
|
| 804 | + fsm_vac = false; |
796 | 805 | break;
|
797 | 806 | }
|
798 | 807 |
|
@@ -857,6 +866,7 @@ ginInsertCleanup(GinState *ginstate,
|
857 | 866 | /* another cleanup process is running concurrently */
|
858 | 867 | UnlockReleaseBuffer(buffer);
|
859 | 868 | LockBuffer(metabuffer, GIN_UNLOCK);
|
| 869 | + fsm_vac = false; |
860 | 870 | break;
|
861 | 871 | }
|
862 | 872 |
|
@@ -895,9 +905,13 @@ ginInsertCleanup(GinState *ginstate,
|
895 | 905 | {
|
896 | 906 | /* another cleanup process is running concurrently */
|
897 | 907 | LockBuffer(metabuffer, GIN_UNLOCK);
|
| 908 | + fsm_vac = false; |
898 | 909 | break;
|
899 | 910 | }
|
900 | 911 |
|
| 912 | + /* At this point, some pending pages have been freed up */ |
| 913 | + fsm_vac = true; |
| 914 | + |
901 | 915 | Assert(blkno == metadata->head);
|
902 | 916 | LockBuffer(metabuffer, GIN_UNLOCK);
|
903 | 917 |
|
@@ -931,6 +945,15 @@ ginInsertCleanup(GinState *ginstate,
|
931 | 945 |
|
932 | 946 | ReleaseBuffer(metabuffer);
|
933 | 947 |
|
| 948 | + /* |
| 949 | + * As pending list pages can have a high churn rate, it is |
| 950 | + * desirable to recycle them immediately to the FreeSpace Map when |
| 951 | + * ordinary backends clean the list. |
| 952 | + */ |
| 953 | + if (fsm_vac && !vac_delay) |
| 954 | + IndexFreeSpaceMapVacuum(index); |
| 955 | + |
| 956 | + |
934 | 957 | /* Clean up temporary space */
|
935 | 958 | MemoryContextSwitchTo(oldCtx);
|
936 | 959 | MemoryContextDelete(opCtx);
|
|
0 commit comments