diff --git a/contrib/pg_buffercache/Makefile b/contrib/pg_buffercache/Makefile index 18f7a87..3629337 100644 --- a/contrib/pg_buffercache/Makefile +++ b/contrib/pg_buffercache/Makefile @@ -4,7 +4,8 @@ MODULE_big = pg_buffercache OBJS = pg_buffercache_pages.o $(WIN32RES) EXTENSION = pg_buffercache -DATA = pg_buffercache--1.2.sql pg_buffercache--1.2--1.3.sql \ +DATA = pg_buffercache--1.4.sql pg_buffercache--1.3--1.4.sql \ + pg_buffercache--1.2.sql pg_buffercache--1.2--1.3.sql \ pg_buffercache--1.1--1.2.sql pg_buffercache--1.0--1.1.sql \ pg_buffercache--unpackaged--1.0.sql PGFILEDESC = "pg_buffercache - monitoring of shared buffer cache in real-time" diff --git a/contrib/pg_buffercache/pg_buffercache--1.3--1.4.sql b/contrib/pg_buffercache/pg_buffercache--1.3--1.4.sql new file mode 100644 index 0000000..c5d3523 --- /dev/null +++ b/contrib/pg_buffercache/pg_buffercache--1.3--1.4.sql @@ -0,0 +1,16 @@ +/* contrib/pg_buffercache/pg_buffercache--1.3--1.4.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION pg_buffercache UPDATE TO '1.4'" to load this file. \quit + +-- Upgrade view to 1.4. format +CREATE OR REPLACE VIEW pg_buffercache AS + SELECT P.* FROM pg_buffercache_pages() AS P + (bufferid integer, relfilenode oid, reltablespace oid, reldatabase oid, + relforknumber int2, relblocknumber int8, isdirty bool, usagecount int2, + pinning_backends int4, buffer_state int8); + +-- Create a function for print of buffer status. +CREATE FUNCTION pg_buffercache_state_print(buffer_state int8) +RETURNS text[] STRICT LANGUAGE 'c' +AS 'MODULE_PATHNAME', 'pg_buffercache_status_print'; diff --git a/contrib/pg_buffercache/pg_buffercache--1.4.sql b/contrib/pg_buffercache/pg_buffercache--1.4.sql new file mode 100644 index 0000000..c5b4ff0 --- /dev/null +++ b/contrib/pg_buffercache/pg_buffercache--1.4.sql @@ -0,0 +1,28 @@ +/* contrib/pg_buffercache/pg_buffercache--1.4.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION pg_buffercache" to load this file. \quit + +-- Register the function. +CREATE FUNCTION pg_buffercache_pages() +RETURNS SETOF RECORD +AS 'MODULE_PATHNAME', 'pg_buffercache_pages' +LANGUAGE C PARALLEL SAFE; + +-- Create a view for convenient access. +CREATE VIEW pg_buffercache AS + SELECT P.* FROM pg_buffercache_pages() AS P + (bufferid integer, relfilenode oid, reltablespace oid, reldatabase oid, + relforknumber int2, relblocknumber int8, isdirty bool, usagecount int2, + pinning_backends int4, buffer_state int8); + +-- Create a function for print of buffer status. +CREATE FUNCTION pg_buffercache_state_print(buffer_state int8) +RETURNS text[] STRICT LANGUAGE 'c' +AS 'MODULE_PATHNAME', 'pg_buffercache_state_print'; + + +-- Don't want these to be available to public. +REVOKE ALL ON FUNCTION pg_buffercache_pages() FROM PUBLIC; +REVOKE ALL ON pg_buffercache FROM PUBLIC; +REVOKE ALL ON FUNCTION pg_buffercache_state_print(buffer_state int8) FROM PUBLIC; diff --git a/contrib/pg_buffercache/pg_buffercache.control b/contrib/pg_buffercache/pg_buffercache.control index 8c060ae..a82ae5f 100644 --- a/contrib/pg_buffercache/pg_buffercache.control +++ b/contrib/pg_buffercache/pg_buffercache.control @@ -1,5 +1,5 @@ # pg_buffercache extension comment = 'examine the shared buffer cache' -default_version = '1.3' +default_version = '1.4' module_pathname = '$libdir/pg_buffercache' relocatable = true diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index b410aaf..055b9b4 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -13,11 +13,14 @@ #include "funcapi.h" #include "storage/buf_internals.h" #include "storage/bufmgr.h" +#include "utils/builtins.h" +#define NUM_BUFFERCACHE_PAGES_MIN_ELEM 8 +#define NUM_BUFFERCACHE_PAGES_ELEM 9 +#define NUM_BUFFERCACHE_PAGES_VERSION_1_4_ELEM 10 -#define NUM_BUFFERCACHE_PAGES_MIN_ELEM 8 -#define NUM_BUFFERCACHE_PAGES_ELEM 9 - +#define NUM_TYPE_OF_STATE 10 +#define LENGTH_OF_STATE_NAME 25 PG_MODULE_MAGIC; /* @@ -41,6 +44,8 @@ typedef struct * because of bufmgr.c's PrivateRefCount infrastructure. */ int32 pinning_backends; + + uint32 buffer_state; } BufferCachePagesRec; @@ -53,6 +58,11 @@ typedef struct BufferCachePagesRec *record; } BufferCachePagesContext; +struct BufferStateInfomation +{ + uint32 state_value; + const char state_name[LENGTH_OF_STATE_NAME]; +}; /* * Function returning data from the shared buffer cache - buffer number, @@ -95,7 +105,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) elog(ERROR, "return type must be a row type"); if (expected_tupledesc->natts < NUM_BUFFERCACHE_PAGES_MIN_ELEM || - expected_tupledesc->natts > NUM_BUFFERCACHE_PAGES_ELEM) + expected_tupledesc->natts > NUM_BUFFERCACHE_PAGES_VERSION_1_4_ELEM) elog(ERROR, "incorrect number of output arguments"); /* Construct a tuple descriptor for the result rows. */ @@ -117,12 +127,15 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) TupleDescInitEntry(tupledesc, (AttrNumber) 8, "usage_count", INT2OID, -1, 0); - if (expected_tupledesc->natts == NUM_BUFFERCACHE_PAGES_ELEM) + if (expected_tupledesc->natts == NUM_BUFFERCACHE_PAGES_ELEM || + expected_tupledesc->natts == NUM_BUFFERCACHE_PAGES_VERSION_1_4_ELEM) TupleDescInitEntry(tupledesc, (AttrNumber) 9, "pinning_backends", INT4OID, -1, 0); + if (expected_tupledesc->natts == NUM_BUFFERCACHE_PAGES_VERSION_1_4_ELEM) + TupleDescInitEntry(tupledesc, (AttrNumber) 10, "buffer_state", + INT8OID, -1, 0); fctx->tupdesc = BlessTupleDesc(tupledesc); - /* Allocate NBuffers worth of BufferCachePagesRec records. */ fctx->record = (BufferCachePagesRec *) MemoryContextAllocHuge(CurrentMemoryContext, @@ -160,6 +173,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) fctx->record[i].blocknum = bufHdr->tag.blockNum; fctx->record[i].usagecount = BUF_STATE_GET_USAGECOUNT(buf_state); fctx->record[i].pinning_backends = BUF_STATE_GET_REFCOUNT(buf_state); + fctx->record[i].buffer_state = buf_state; if (buf_state & BM_DIRTY) fctx->record[i].isdirty = true; @@ -180,12 +194,11 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) /* Get the saved state */ fctx = funcctx->user_fctx; - if (funcctx->call_cntr < funcctx->max_calls) { uint32 i = funcctx->call_cntr; - Datum values[NUM_BUFFERCACHE_PAGES_ELEM]; - bool nulls[NUM_BUFFERCACHE_PAGES_ELEM]; + Datum values[NUM_BUFFERCACHE_PAGES_VERSION_1_4_ELEM]; + bool nulls[NUM_BUFFERCACHE_PAGES_VERSION_1_4_ELEM]; values[0] = Int32GetDatum(fctx->record[i].bufferid); nulls[0] = false; @@ -206,6 +219,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) nulls[7] = true; /* unused for v1.0 callers, but the array is always long enough */ nulls[8] = true; + nulls[9] = true; } else { @@ -226,14 +240,61 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) /* unused for v1.0 callers, but the array is always long enough */ values[8] = Int32GetDatum(fctx->record[i].pinning_backends); nulls[8] = false; + /* unused for v1.3 callers, but the array is always long enough */ + values[9] = Int64GetDatum((int64)fctx->record[i].buffer_state); + nulls[9] = false; } - /* Build and return the tuple. */ tuple = heap_form_tuple(fctx->tupdesc, values, nulls); result = HeapTupleGetDatum(tuple); - SRF_RETURN_NEXT(funcctx, result); } else SRF_RETURN_DONE(funcctx); } + +PG_FUNCTION_INFO_V1(pg_buffercache_state_print); + +static struct BufferStateInfomation state_list[NUM_TYPE_OF_STATE] = +{ + {(uint32)BM_LOCKED, "LOCKED"}, + {(uint32)BM_DIRTY, "DIRTY"}, + {(uint32)BM_VALID, "VALID"}, + {(uint32)BM_TAG_VALID, "TAG_VALID"}, + {(uint32)BM_IO_IN_PROGRESS, "IO_IN_PROGRESS"}, + {(uint32)BM_IO_ERROR, "IO_ERROR"}, + {(uint32)BM_JUST_DIRTIED, "JUST_DIRTIED"}, + {(uint32)BM_PIN_COUNT_WAITER, "PIN_COUNT_WAITER"}, + {(uint32)BM_CHECKPOINT_NEEDED, "CHECKPOINT_NEEDED"}, + {(uint32)BM_PERMANENT, "PERMANENT"}, +}; + +Datum +pg_buffercache_state_print(PG_FUNCTION_ARGS) +{ + int64 buffer_state = PG_GETARG_INT64(0); + ArrayType *string_array; + Datum *string_data; + int array_size = 0; + int list_num = 0; + + if( buffer_state == 0 ) + { + string_array = construct_empty_array(TEXTOID); + PG_RETURN_POINTER(string_array); + } + + string_data = (Datum *) palloc(sizeof(Datum) * NUM_TYPE_OF_STATE ); + + for( list_num = 0; list_num < NUM_TYPE_OF_STATE; list_num ++ ) + { + if( buffer_state & state_list[list_num].state_value ) + string_data[array_size++] = + CStringGetTextDatum(state_list[list_num].state_name); + } + + string_array = construct_array( string_data, array_size, TEXTOID, -1, false, 'i'); + + pfree(string_data); + PG_RETURN_POINTER(string_array); +} diff --git a/doc/src/sgml/pgbuffercache.sgml b/doc/src/sgml/pgbuffercache.sgml index 18ac781..b02dc19 100644 --- a/doc/src/sgml/pgbuffercache.sgml +++ b/doc/src/sgml/pgbuffercache.sgml @@ -114,6 +114,13 @@ Number of backends pinning this buffer + + buffer_state + integer + + Hex value of Buffer state + + @@ -145,6 +152,27 @@ + General Functions + + + + + pg_buffercache_state_print return text[] + + pg_buffercache_state_print + + + + + + pg_buffercache_state_print Outputs the value of + the buffer status in hexadecimal to text[] in easy-readable. + + + + + + Sample Output @@ -174,6 +202,34 @@ regression=# SELECT c.relname, count(*) AS buffers + pg_buffercache_state_print Fuction Sample Output + +regression=# SELECT pg_buffercache_state_print(2203320320); + +pg_buffercache_state_print +------------------------------------ +{LOCKED,VALID,TAG_VALID,PERMANENT} +(1 row) + +regression=# SELECT bufferid, relfilenode, buffer_state, state_text FROM pg_buffercache, + LATERAL pg_buffercache_state_print(buffer_state) M(state_text) + WHERE bufferid < 10; + +bufferid | relfilenode | buffer_state | state_text +----------+-------------+--------------+------------------------------------------------------- + 1 | 1262 | 2203320320 | {LOCKED,VALID,TAG_VALID,PERMANENT} + 2 | 1260 | 2202533888 | {LOCKED,VALID,TAG_VALID,PERMANENT} + 3 | 1259 | 2480144384 | {LOCKED,DIRTY,VALID,TAG_VALID,JUST_DIRTIED,PERMANENT} + 4 | 1259 | 2203320320 | {LOCKED,VALID,TAG_VALID,PERMANENT} + 5 | 1259 | 2203320320 | {LOCKED,VALID,TAG_VALID,PERMANENT} + 6 | 1249 | 2203320320 | {LOCKED,VALID,TAG_VALID,PERMANENT} + 7 | 1249 | 2203320320 | {LOCKED,VALID,TAG_VALID,PERMANENT} + 8 | 1249 | 2203320320 | {LOCKED,VALID,TAG_VALID,PERMANENT} + 9 | 1249 | 2203320320 | {LOCKED,VALID,TAG_VALID,PERMANENT} +(9 rows) + + + Authors