|
25 | 25 | #define NUM_BUFFERCACHE_EVICT_ELEM 2 |
26 | 26 | #define NUM_BUFFERCACHE_EVICT_RELATION_ELEM 3 |
27 | 27 | #define NUM_BUFFERCACHE_EVICT_ALL_ELEM 3 |
| 28 | +#define NUM_BUFFERCACHE_MARK_DIRTY_ELEM 2 |
| 29 | +#define NUM_BUFFERCACHE_MARK_DIRTY_RELATION_ELEM 3 |
| 30 | +#define NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM 3 |
28 | 31 |
|
29 | 32 | #define NUM_BUFFERCACHE_NUMA_ELEM 3 |
30 | 33 |
|
@@ -100,6 +103,9 @@ PG_FUNCTION_INFO_V1(pg_buffercache_usage_counts); |
100 | 103 | PG_FUNCTION_INFO_V1(pg_buffercache_evict); |
101 | 104 | PG_FUNCTION_INFO_V1(pg_buffercache_evict_relation); |
102 | 105 | PG_FUNCTION_INFO_V1(pg_buffercache_evict_all); |
| 106 | +PG_FUNCTION_INFO_V1(pg_buffercache_mark_dirty); |
| 107 | +PG_FUNCTION_INFO_V1(pg_buffercache_mark_dirty_relation); |
| 108 | +PG_FUNCTION_INFO_V1(pg_buffercache_mark_dirty_all); |
103 | 109 |
|
104 | 110 |
|
105 | 111 | /* Only need to touch memory once per backend process lifetime */ |
@@ -777,3 +783,120 @@ pg_buffercache_evict_all(PG_FUNCTION_ARGS) |
777 | 783 |
|
778 | 784 | PG_RETURN_DATUM(result); |
779 | 785 | } |
| 786 | + |
| 787 | +/* |
| 788 | + * Try to mark a shared buffer as dirty. |
| 789 | + */ |
| 790 | +Datum |
| 791 | +pg_buffercache_mark_dirty(PG_FUNCTION_ARGS) |
| 792 | +{ |
| 793 | + |
| 794 | + Datum result; |
| 795 | + TupleDesc tupledesc; |
| 796 | + HeapTuple tuple; |
| 797 | + Datum values[NUM_BUFFERCACHE_MARK_DIRTY_ELEM]; |
| 798 | + bool nulls[NUM_BUFFERCACHE_MARK_DIRTY_ELEM] = {0}; |
| 799 | + |
| 800 | + Buffer buf = PG_GETARG_INT32(0); |
| 801 | + bool buffer_already_dirty; |
| 802 | + |
| 803 | + if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE) |
| 804 | + elog(ERROR, "return type must be a row type"); |
| 805 | + |
| 806 | + pg_buffercache_superuser_check("pg_buffercache_mark_dirty"); |
| 807 | + |
| 808 | + if (buf < 1 || buf > NBuffers) |
| 809 | + elog(ERROR, "bad buffer ID: %d", buf); |
| 810 | + |
| 811 | + |
| 812 | + values[0] = BoolGetDatum(MarkDirtyUnpinnedBuffer(buf, &buffer_already_dirty)); |
| 813 | + values[1] = BoolGetDatum(buffer_already_dirty); |
| 814 | + |
| 815 | + tuple = heap_form_tuple(tupledesc, values, nulls); |
| 816 | + result = HeapTupleGetDatum(tuple); |
| 817 | + |
| 818 | + PG_RETURN_DATUM(result); |
| 819 | +} |
| 820 | + |
| 821 | +/* |
| 822 | + * Try to mark specified relation dirty. |
| 823 | + */ |
| 824 | +Datum |
| 825 | +pg_buffercache_mark_dirty_relation(PG_FUNCTION_ARGS) |
| 826 | +{ |
| 827 | + Datum result; |
| 828 | + TupleDesc tupledesc; |
| 829 | + HeapTuple tuple; |
| 830 | + Datum values[NUM_BUFFERCACHE_MARK_DIRTY_RELATION_ELEM]; |
| 831 | + bool nulls[NUM_BUFFERCACHE_MARK_DIRTY_RELATION_ELEM] = {0}; |
| 832 | + |
| 833 | + Oid relOid; |
| 834 | + Relation rel; |
| 835 | + |
| 836 | + int32 buffers_already_dirty = 0; |
| 837 | + int32 buffers_dirtied = 0; |
| 838 | + int32 buffers_skipped = 0; |
| 839 | + |
| 840 | + if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE) |
| 841 | + elog(ERROR, "return type must be a row type"); |
| 842 | + |
| 843 | + pg_buffercache_superuser_check("pg_buffercache_mark_dirty_relation"); |
| 844 | + |
| 845 | + relOid = PG_GETARG_OID(0); |
| 846 | + |
| 847 | + rel = relation_open(relOid, AccessShareLock); |
| 848 | + |
| 849 | + if (RelationUsesLocalBuffers(rel)) |
| 850 | + ereport(ERROR, |
| 851 | + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 852 | + errmsg("relation uses local buffers, %s() is intended to be used for shared buffers only", |
| 853 | + "pg_buffercache_mark_dirty_relation"))); |
| 854 | + |
| 855 | + MarkDirtyRelUnpinnedBuffers(rel, &buffers_dirtied, &buffers_already_dirty, |
| 856 | + &buffers_skipped); |
| 857 | + |
| 858 | + relation_close(rel, AccessShareLock); |
| 859 | + |
| 860 | + values[0] = Int32GetDatum(buffers_dirtied); |
| 861 | + values[1] = Int32GetDatum(buffers_already_dirty); |
| 862 | + values[2] = Int32GetDatum(buffers_skipped); |
| 863 | + |
| 864 | + tuple = heap_form_tuple(tupledesc, values, nulls); |
| 865 | + result = HeapTupleGetDatum(tuple); |
| 866 | + |
| 867 | + PG_RETURN_DATUM(result); |
| 868 | +} |
| 869 | + |
| 870 | +/* |
| 871 | + * Try to mark all the shared buffers as dirty. |
| 872 | + */ |
| 873 | +Datum |
| 874 | +pg_buffercache_mark_dirty_all(PG_FUNCTION_ARGS) |
| 875 | +{ |
| 876 | + Datum result; |
| 877 | + TupleDesc tupledesc; |
| 878 | + HeapTuple tuple; |
| 879 | + Datum values[NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM]; |
| 880 | + bool nulls[NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM] = {0}; |
| 881 | + |
| 882 | + int32 buffers_already_dirty = 0; |
| 883 | + int32 buffers_dirtied = 0; |
| 884 | + int32 buffers_skipped = 0; |
| 885 | + |
| 886 | + if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE) |
| 887 | + elog(ERROR, "return type must be a row type"); |
| 888 | + |
| 889 | + pg_buffercache_superuser_check("pg_buffercache_mark_dirty_all"); |
| 890 | + |
| 891 | + MarkDirtyAllUnpinnedBuffers(&buffers_dirtied, &buffers_already_dirty, |
| 892 | + &buffers_skipped); |
| 893 | + |
| 894 | + values[0] = Int32GetDatum(buffers_dirtied); |
| 895 | + values[1] = Int32GetDatum(buffers_already_dirty); |
| 896 | + values[2] = Int32GetDatum(buffers_skipped); |
| 897 | + |
| 898 | + tuple = heap_form_tuple(tupledesc, values, nulls); |
| 899 | + result = HeapTupleGetDatum(tuple); |
| 900 | + |
| 901 | + PG_RETURN_DATUM(result); |
| 902 | +} |
0 commit comments