Skip to content

Commit 52d2010

Browse files
committed
PG: Handle locks without relation like transactionid locks
In postgres, a transaction can wait for another transaction to end by trying to acquire a sharelock on the target transactionid's lock. We currently exclude those due to the join on relname/schema/db as they have null values. This PR convert pg_locks to a dynamic query and handles locks with null relname/schema/db.
1 parent aad28cc commit 52d2010

File tree

3 files changed

+80
-24
lines changed

3 files changed

+80
-24
lines changed

postgres/changelog.d/21393.changed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PG: Handle locks without relations like transactionid or virtualxid locks

postgres/datadog_checks/postgres/relationsmanager.py

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,7 @@
2929

3030
# The view pg_locks provides access to information about the locks held by active processes within the database server.
3131
LOCK_METRICS = {
32-
'descriptors': [
33-
('mode', 'lock_mode'),
34-
('locktype', 'lock_type'),
35-
('nspname', 'schema'),
36-
('datname', 'db'),
37-
('relname', 'table'),
38-
('granted', 'granted'),
39-
('fastpath', 'fastpath'),
40-
],
41-
'metrics': {'lock_count': ('locks', AgentCheck.gauge)},
32+
'name': 'pg_locks',
4233
'query': """
4334
SELECT mode,
4435
locktype,
@@ -47,17 +38,25 @@
4738
pc.relname,
4839
granted,
4940
fastpath,
50-
count(*) AS {metrics_columns}
41+
count(*)
5142
FROM pg_locks l
52-
JOIN pg_database pd ON (l.database = pd.oid)
53-
JOIN pg_class pc ON (l.relation = pc.oid)
43+
LEFT JOIN pg_database pd ON (l.database = pd.oid)
44+
LEFT JOIN pg_class pc ON (l.relation = pc.oid)
5445
LEFT JOIN pg_namespace pn ON (pn.oid = pc.relnamespace)
55-
WHERE {relations}
46+
WHERE (pc IS NULL OR ({relations} AND pc.relname NOT LIKE 'pg^_%%' ESCAPE '^'))
5647
AND l.mode IS NOT NULL
57-
AND pc.relname NOT LIKE 'pg^_%%' ESCAPE '^'
58-
GROUP BY pd.datname, pc.relname, pn.nspname, locktype, mode, granted, fastpath""",
59-
'relation': True,
60-
'name': 'lock_metrics',
48+
GROUP BY pd.datname, pc.relname, pn.nspname, locktype, mode, granted, fastpath
49+
""",
50+
'columns': [
51+
{'name': 'lock_mode', 'type': 'tag'},
52+
{'name': 'lock_type', 'type': 'tag'},
53+
{'name': 'schema', 'type': 'tag_not_null'},
54+
{'name': 'db', 'type': 'tag_not_null'},
55+
{'name': 'table', 'type': 'tag_not_null'},
56+
{'name': 'granted', 'type': 'tag'},
57+
{'name': 'fastpath', 'type': 'tag'},
58+
{'name': 'locks', 'type': 'gauge'},
59+
],
6160
}
6261

6362

@@ -414,8 +413,8 @@
414413
'name': 'index_bloat_metrics',
415414
}
416415

417-
RELATION_METRICS = [LOCK_METRICS, STATIO_METRICS]
418-
DYNAMIC_RELATION_QUERIES = [QUERY_PG_CLASS, QUERY_PG_CLASS_SIZE, IDX_METRICS]
416+
RELATION_METRICS = [STATIO_METRICS]
417+
DYNAMIC_RELATION_QUERIES = [QUERY_PG_CLASS, QUERY_PG_CLASS_SIZE, IDX_METRICS, LOCK_METRICS]
419418

420419

421420
class RelationsManager(object):

postgres/tests/test_relations.py

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -411,30 +411,86 @@ def test_vacuum_age(aggregator, integration_check, pg_instance):
411411
[{"relation_regex": "perso.*", "relkind": ["r"]}],
412412
1,
413413
"persons",
414-
None,
414+
[
415+
"db:datadog_test",
416+
"lock_mode:AccessExclusiveLock",
417+
"lock_type:relation",
418+
"granted:True",
419+
"fastpath:False",
420+
"table:persons",
421+
"schema:public",
422+
],
415423
id="test with matching relkind should return 1",
416424
),
417425
pytest.param(
418426
[{"relation_regex": "perso.*", "relkind": ["i"]}],
419427
0,
420428
"persons",
421-
None,
429+
[
430+
"db:datadog_test",
431+
"lock_mode:AccessExclusiveLock",
432+
"lock_type:relation",
433+
"granted:True",
434+
"fastpath:False",
435+
"table:persons",
436+
"schema:public",
437+
],
422438
id="test without matching relkind should return 0",
423439
),
424440
pytest.param(
425441
["pgtable"],
426442
1,
427443
"pgtable",
428-
None,
444+
[
445+
"db:datadog_test",
446+
"lock_mode:AccessExclusiveLock",
447+
"lock_type:relation",
448+
"granted:True",
449+
"fastpath:False",
450+
"table:pgtable",
451+
"schema:public",
452+
],
429453
id="pgtable should be included in lock metrics",
430454
),
431455
pytest.param(
432456
["pg_newtable"],
433457
0,
434458
"pg_newtable",
435-
None,
459+
[
460+
"db:datadog_test",
461+
"lock_mode:AccessExclusiveLock",
462+
"lock_type:relation",
463+
"granted:True",
464+
"fastpath:False",
465+
"table:pg_newtable",
466+
"schema:public",
467+
],
436468
id="pg_newtable should be excluded from query since it starts with `pg_`",
437469
),
470+
pytest.param(
471+
['persons'],
472+
1,
473+
'persons',
474+
[
475+
"lock_mode:ExclusiveLock",
476+
"lock_type:transactionid",
477+
"granted:True",
478+
"fastpath:False",
479+
],
480+
id="transactionid lock should be visible",
481+
),
482+
pytest.param(
483+
['persons'],
484+
1,
485+
'persons',
486+
[
487+
"lock_mode:ExclusiveLock",
488+
"lock_type:virtualxid",
489+
"granted:True",
490+
"fastpath:True",
491+
],
492+
id="virtualxid lock should be visible",
493+
),
438494
],
439495
)
440496
def test_locks_metrics(aggregator, integration_check, pg_instance, relations, lock_count, lock_table_name, tags):

0 commit comments

Comments
 (0)