Skip to content

Commit

Permalink
Add telemetry for access methods
Browse files Browse the repository at this point in the history
Add telemetry for tracking access methods used, number of pages for
each access method, and number of instances using each access method.
  • Loading branch information
mkindahl committed Apr 10, 2024
1 parent 7ffdd07 commit 3709adc
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/code_style.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
- name: Run codespell
run: |
find . -type f \( -name "*.c" -or -name "*.h" -or -name "*.yaml" -or -name "*.sh" \) \
-exec codespell -L "inh,larg,inout" {} \+
-exec codespell -L "brin,inh,larg,inout" {} \+
cc_checks:
name: Check code formatting
Expand Down
1 change: 1 addition & 0 deletions .unreleased/pr_6810
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implements: #6810 Add telemetry for access methods
39 changes: 39 additions & 0 deletions src/jsonb_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,45 @@ ts_jsonb_add_str(JsonbParseState *state, const char *key, const char *value)
ts_jsonb_add_value(state, key, &json_value);
}

void
ts_jsonb_set_value_by_type(JsonbValue *value, Oid typeid, Datum datum)
{
switch (typeid)
{
Oid typeOut;
bool isvarlena;
char *str;

case INT8OID:
value->type = jbvNumeric;
value->val.numeric = DatumGetNumeric(DirectFunctionCall1(int8_numeric, datum));
break;

case INT2OID:
value->type = jbvNumeric;
value->val.numeric = DatumGetNumeric(DirectFunctionCall1(int2_numeric, datum));
break;

Check warning on line 77 in src/jsonb_utils.c

View check run for this annotation

Codecov / codecov/patch

src/jsonb_utils.c#L74-L77

Added lines #L74 - L77 were not covered by tests

case INT4OID:
value->type = jbvNumeric;
value->val.numeric = DatumGetNumeric(DirectFunctionCall1(int4_numeric, datum));
break;

Check warning on line 82 in src/jsonb_utils.c

View check run for this annotation

Codecov / codecov/patch

src/jsonb_utils.c#L79-L82

Added lines #L79 - L82 were not covered by tests

case NUMERICOID:
value->type = jbvNumeric;
value->val.numeric = DatumGetNumeric(datum);
break;

Check warning on line 87 in src/jsonb_utils.c

View check run for this annotation

Codecov / codecov/patch

src/jsonb_utils.c#L84-L87

Added lines #L84 - L87 were not covered by tests

default:
getTypeOutputInfo(typeid, &typeOut, &isvarlena);
str = OidOutputFunctionCall(typeOut, datum);
value->type = jbvString;
value->val.string.val = str;
value->val.string.len = strlen(str);
break;

Check warning on line 95 in src/jsonb_utils.c

View check run for this annotation

Codecov / codecov/patch

src/jsonb_utils.c#L89-L95

Added lines #L89 - L95 were not covered by tests
}
}

void
ts_jsonb_add_int32(JsonbParseState *state, const char *key, const int32 int_value)
{
Expand Down
1 change: 1 addition & 0 deletions src/jsonb_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ extern TSDLLEXPORT void ts_jsonb_add_int64(JsonbParseState *state, const char *k
const int64 value);
extern TSDLLEXPORT void ts_jsonb_add_numeric(JsonbParseState *state, const char *key,
const Numeric value);
extern TSDLLEXPORT void ts_jsonb_set_value_by_type(JsonbValue *value, Oid typeid, Datum datum);

extern void ts_jsonb_add_value(JsonbParseState *state, const char *key, JsonbValue *value);

Expand Down
96 changes: 96 additions & 0 deletions src/telemetry/telemetry.c
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,93 @@ add_replication_telemetry(JsonbParseState *state)
#define REQ_RELS_CONTINUOUS_AGGS "continuous_aggregates"
#define REQ_FUNCTIONS_USED "functions_used"
#define REQ_REPLICATION "replication"
#define REQ_ACCESS_METHODS "access_methods"

/*
* Add the result of a query as a sub-object to the JSONB.
*
* Each row from the query generates a separate object keyed by one of the
* columns. Each row will be represented as an object and stored under the
* "key" column. For example, with this query:
*
* select amname as name,
* sum(relpages) as pages,
* count(*) as instances
* from pg_class join pg_am on relam = pg_am.oid
* group by pg_am.oid;
*
* might generate the object
*
* {
* "brin" : {
* "instances" : 44,
* "pages" : 432
* },
* "btree" : {
* "instances" : 99,
* "pages" : 1234
* }
* }
*/
static void
add_query_result_dict(JsonbParseState *state, const char *query)
{
MemoryContext orig_context = CurrentMemoryContext;

int res;
if (SPI_connect() != SPI_OK_CONNECT)
elog(ERROR, "could not connect to SPI");

/* Lock down search_path */
res = SPI_execute("SET LOCAL search_path TO pg_catalog, pg_temp", false, 0);
Ensure(res >= 0, "could not set search path");

res = SPI_execute(query, true, 0);
Ensure(res >= 0, "could not execute query");

MemoryContext spi_context = MemoryContextSwitchTo(orig_context);

(void) pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
for (uint64 r = 0; r < SPI_processed; r++)
{
char *key_string = SPI_getvalue(SPI_tuptable->vals[r], SPI_tuptable->tupdesc, 1);
JsonbValue key = {
.type = jbvString,
.val.string.val = pstrdup(key_string),
.val.string.len = strlen(key_string),
};

(void) pushJsonbValue(&state, WJB_KEY, &key);

(void) pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
for (int c = 1; c < SPI_tuptable->tupdesc->natts; ++c)
{
bool isnull;
Datum val_datum =
SPI_getbinval(SPI_tuptable->vals[r], SPI_tuptable->tupdesc, c + 1, &isnull);
if (!isnull)
{
char *key_string = SPI_fname(SPI_tuptable->tupdesc, c + 1);
JsonbValue key = {
.type = jbvString,
.val.string.val = pstrdup(key_string),
.val.string.len = strlen(key_string),
};
JsonbValue value;
ts_jsonb_set_value_by_type(&value,
SPI_gettypeid(SPI_tuptable->tupdesc, c + 1),
val_datum);
(void) pushJsonbValue(&state, WJB_KEY, &key);
(void) pushJsonbValue(&state, WJB_VALUE, &value);
}
}
pushJsonbValue(&state, WJB_END_OBJECT, NULL);
}
MemoryContextSwitchTo(spi_context);
res = SPI_finish();
Assert(res == SPI_OK_FINISH);
(void) pushJsonbValue(&state, WJB_END_OBJECT, NULL);
}

static Jsonb *
build_telemetry_report()
Expand Down Expand Up @@ -937,6 +1024,15 @@ build_telemetry_report()
add_replication_telemetry(parse_state);
pushJsonbValue(&parse_state, WJB_END_OBJECT, NULL);

key.type = jbvString;
key.val.string.val = REQ_ACCESS_METHODS;
key.val.string.len = strlen(REQ_ACCESS_METHODS);
(void) pushJsonbValue(&parse_state, WJB_KEY, &key);
add_query_result_dict(parse_state,
"SELECT amname AS name, sum(relpages) AS pages, count(*) AS "
"instances FROM pg_class JOIN pg_am ON relam = pg_am.oid "
"GROUP BY amname");

/* end of telemetry object */
result = pushJsonbValue(&parse_state, WJB_END_OBJECT, NULL);

Expand Down
14 changes: 13 additions & 1 deletion test/expected/telemetry.out
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ WHERE key != 'os_name_pretty';
db_metadata
replication
build_os_name
access_methods
functions_used
install_method
installed_time
Expand Down Expand Up @@ -377,7 +378,7 @@ WHERE key != 'os_name_pretty';
num_compression_policies_fixed
num_user_defined_actions_fixed
num_continuous_aggs_policies_fixed
(37 rows)
(38 rows)

CREATE MATERIALIZED VIEW telemetry_report AS
SELECT t FROM get_telemetry_report() t;
Expand All @@ -395,6 +396,17 @@ SELECT t -> 'instance_metadata' FROM telemetry_report;
{"cloud": "ci"}
(1 row)

-- Check access methods
SELECT t->'access_methods' ? 'btree',
t->'access_methods' ? 'heap',
CAST(t->'access_methods'->'btree'->'pages' AS int) > 0,
CAST(t->'access_methods'->'btree'->'instances' AS int) > 0
FROM telemetry_report;
?column? | ?column? | ?column? | ?column?
----------+----------+----------+----------
t | t | t | t
(1 row)

WITH t AS (
SELECT t -> 'relations' AS rels
FROM telemetry_report
Expand Down
7 changes: 7 additions & 0 deletions test/sql/telemetry.sql
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,13 @@ SELECT t -> 'db_metadata' FROM telemetry_report;
-- check timescaledb_telemetry.cloud
SELECT t -> 'instance_metadata' FROM telemetry_report;

-- Check access methods
SELECT t->'access_methods' ? 'btree',
t->'access_methods' ? 'heap',
CAST(t->'access_methods'->'btree'->'pages' AS int) > 0,
CAST(t->'access_methods'->'btree'->'instances' AS int) > 0
FROM telemetry_report;

WITH t AS (
SELECT t -> 'relations' AS rels
FROM telemetry_report
Expand Down

0 comments on commit 3709adc

Please sign in to comment.