|
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