|
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_OS_PAGES_ELEM 3 |
30 | 33 |
|
@@ -101,6 +104,9 @@ PG_FUNCTION_INFO_V1(pg_buffercache_usage_counts); |
101 | 104 | PG_FUNCTION_INFO_V1(pg_buffercache_evict); |
102 | 105 | PG_FUNCTION_INFO_V1(pg_buffercache_evict_relation); |
103 | 106 | PG_FUNCTION_INFO_V1(pg_buffercache_evict_all); |
| 107 | +PG_FUNCTION_INFO_V1(pg_buffercache_mark_dirty); |
| 108 | +PG_FUNCTION_INFO_V1(pg_buffercache_mark_dirty_relation); |
| 109 | +PG_FUNCTION_INFO_V1(pg_buffercache_mark_dirty_all); |
104 | 110 |
|
105 | 111 |
|
106 | 112 | /* Only need to touch memory once per backend process lifetime */ |
@@ -826,3 +832,119 @@ pg_buffercache_evict_all(PG_FUNCTION_ARGS) |
826 | 832 |
|
827 | 833 | PG_RETURN_DATUM(result); |
828 | 834 | } |
| 835 | + |
| 836 | +/* |
| 837 | + * Try to mark a shared buffer as dirty. |
| 838 | + */ |
| 839 | +Datum |
| 840 | +pg_buffercache_mark_dirty(PG_FUNCTION_ARGS) |
| 841 | +{ |
| 842 | + |
| 843 | + Datum result; |
| 844 | + TupleDesc tupledesc; |
| 845 | + HeapTuple tuple; |
| 846 | + Datum values[NUM_BUFFERCACHE_MARK_DIRTY_ELEM]; |
| 847 | + bool nulls[NUM_BUFFERCACHE_MARK_DIRTY_ELEM] = {0}; |
| 848 | + |
| 849 | + Buffer buf = PG_GETARG_INT32(0); |
| 850 | + bool buffer_already_dirty; |
| 851 | + |
| 852 | + if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE) |
| 853 | + elog(ERROR, "return type must be a row type"); |
| 854 | + |
| 855 | + pg_buffercache_superuser_check("pg_buffercache_mark_dirty"); |
| 856 | + |
| 857 | + if (buf < 1 || buf > NBuffers) |
| 858 | + elog(ERROR, "bad buffer ID: %d", buf); |
| 859 | + |
| 860 | + values[0] = BoolGetDatum(MarkDirtyUnpinnedBuffer(buf, &buffer_already_dirty)); |
| 861 | + values[1] = BoolGetDatum(buffer_already_dirty); |
| 862 | + |
| 863 | + tuple = heap_form_tuple(tupledesc, values, nulls); |
| 864 | + result = HeapTupleGetDatum(tuple); |
| 865 | + |
| 866 | + PG_RETURN_DATUM(result); |
| 867 | +} |
| 868 | + |
| 869 | +/* |
| 870 | + * Try to mark all the shared buffers of a relation as dirty. |
| 871 | + */ |
| 872 | +Datum |
| 873 | +pg_buffercache_mark_dirty_relation(PG_FUNCTION_ARGS) |
| 874 | +{ |
| 875 | + Datum result; |
| 876 | + TupleDesc tupledesc; |
| 877 | + HeapTuple tuple; |
| 878 | + Datum values[NUM_BUFFERCACHE_MARK_DIRTY_RELATION_ELEM]; |
| 879 | + bool nulls[NUM_BUFFERCACHE_MARK_DIRTY_RELATION_ELEM] = {0}; |
| 880 | + |
| 881 | + Oid relOid; |
| 882 | + Relation rel; |
| 883 | + |
| 884 | + int32 buffers_already_dirty = 0; |
| 885 | + int32 buffers_dirtied = 0; |
| 886 | + int32 buffers_skipped = 0; |
| 887 | + |
| 888 | + if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE) |
| 889 | + elog(ERROR, "return type must be a row type"); |
| 890 | + |
| 891 | + pg_buffercache_superuser_check("pg_buffercache_mark_dirty_relation"); |
| 892 | + |
| 893 | + relOid = PG_GETARG_OID(0); |
| 894 | + |
| 895 | + rel = relation_open(relOid, AccessShareLock); |
| 896 | + |
| 897 | + if (RelationUsesLocalBuffers(rel)) |
| 898 | + ereport(ERROR, |
| 899 | + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| 900 | + errmsg("relation uses local buffers, %s() is intended to be used for shared buffers only", |
| 901 | + "pg_buffercache_mark_dirty_relation"))); |
| 902 | + |
| 903 | + MarkDirtyRelUnpinnedBuffers(rel, &buffers_dirtied, &buffers_already_dirty, |
| 904 | + &buffers_skipped); |
| 905 | + |
| 906 | + relation_close(rel, AccessShareLock); |
| 907 | + |
| 908 | + values[0] = Int32GetDatum(buffers_dirtied); |
| 909 | + values[1] = Int32GetDatum(buffers_already_dirty); |
| 910 | + values[2] = Int32GetDatum(buffers_skipped); |
| 911 | + |
| 912 | + tuple = heap_form_tuple(tupledesc, values, nulls); |
| 913 | + result = HeapTupleGetDatum(tuple); |
| 914 | + |
| 915 | + PG_RETURN_DATUM(result); |
| 916 | +} |
| 917 | + |
| 918 | +/* |
| 919 | + * Try to mark all the shared buffers as dirty. |
| 920 | + */ |
| 921 | +Datum |
| 922 | +pg_buffercache_mark_dirty_all(PG_FUNCTION_ARGS) |
| 923 | +{ |
| 924 | + Datum result; |
| 925 | + TupleDesc tupledesc; |
| 926 | + HeapTuple tuple; |
| 927 | + Datum values[NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM]; |
| 928 | + bool nulls[NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM] = {0}; |
| 929 | + |
| 930 | + int32 buffers_already_dirty = 0; |
| 931 | + int32 buffers_dirtied = 0; |
| 932 | + int32 buffers_skipped = 0; |
| 933 | + |
| 934 | + if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE) |
| 935 | + elog(ERROR, "return type must be a row type"); |
| 936 | + |
| 937 | + pg_buffercache_superuser_check("pg_buffercache_mark_dirty_all"); |
| 938 | + |
| 939 | + MarkDirtyAllUnpinnedBuffers(&buffers_dirtied, &buffers_already_dirty, |
| 940 | + &buffers_skipped); |
| 941 | + |
| 942 | + values[0] = Int32GetDatum(buffers_dirtied); |
| 943 | + values[1] = Int32GetDatum(buffers_already_dirty); |
| 944 | + values[2] = Int32GetDatum(buffers_skipped); |
| 945 | + |
| 946 | + tuple = heap_form_tuple(tupledesc, values, nulls); |
| 947 | + result = HeapTupleGetDatum(tuple); |
| 948 | + |
| 949 | + PG_RETURN_DATUM(result); |
| 950 | +} |
0 commit comments