taurusdb-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/README.md +21 -0
  2. package/dist/auth/secret-resolver.d.ts +16 -0
  3. package/dist/auth/secret-resolver.js +64 -0
  4. package/dist/auth/sql-profile-loader/env-source.d.ts +3 -0
  5. package/dist/auth/sql-profile-loader/env-source.js +94 -0
  6. package/dist/auth/sql-profile-loader/file-source.d.ts +6 -0
  7. package/dist/auth/sql-profile-loader/file-source.js +40 -0
  8. package/dist/auth/sql-profile-loader/loader.d.ts +16 -0
  9. package/dist/auth/sql-profile-loader/loader.js +81 -0
  10. package/dist/auth/sql-profile-loader/parsing.d.ts +14 -0
  11. package/dist/auth/sql-profile-loader/parsing.js +216 -0
  12. package/dist/auth/sql-profile-loader/runtime-override.d.ts +14 -0
  13. package/dist/auth/sql-profile-loader/runtime-override.js +52 -0
  14. package/dist/auth/sql-profile-loader/types.d.ts +64 -0
  15. package/dist/auth/sql-profile-loader/types.js +1 -0
  16. package/dist/auth/sql-profile-loader.d.ts +4 -0
  17. package/dist/auth/sql-profile-loader.js +3 -0
  18. package/dist/capability/feature-matrix.d.ts +5 -0
  19. package/dist/capability/feature-matrix.js +237 -0
  20. package/dist/capability/probe.d.ts +19 -0
  21. package/dist/capability/probe.js +139 -0
  22. package/dist/capability/types.d.ts +49 -0
  23. package/dist/capability/types.js +16 -0
  24. package/dist/capability/version.d.ts +3 -0
  25. package/dist/capability/version.js +47 -0
  26. package/dist/cloud/auth.d.ts +26 -0
  27. package/dist/cloud/auth.js +198 -0
  28. package/dist/cloud/instances.d.ts +46 -0
  29. package/dist/cloud/instances.js +224 -0
  30. package/dist/config/env.d.ts +1 -0
  31. package/dist/config/env.js +194 -0
  32. package/dist/config/index.d.ts +6 -0
  33. package/dist/config/index.js +21 -0
  34. package/dist/config/redaction.d.ts +2 -0
  35. package/dist/config/redaction.js +19 -0
  36. package/dist/config/schema.d.ts +417 -0
  37. package/dist/config/schema.js +100 -0
  38. package/dist/context/datasource-resolver.d.ts +19 -0
  39. package/dist/context/datasource-resolver.js +71 -0
  40. package/dist/context/session-context.d.ts +26 -0
  41. package/dist/context/session-context.js +1 -0
  42. package/dist/diagnostics/metrics-source.d.ts +65 -0
  43. package/dist/diagnostics/metrics-source.js +280 -0
  44. package/dist/diagnostics/slow-sql-source/das-source.d.ts +43 -0
  45. package/dist/diagnostics/slow-sql-source/das-source.js +170 -0
  46. package/dist/diagnostics/slow-sql-source/factory.d.ts +5 -0
  47. package/dist/diagnostics/slow-sql-source/factory.js +87 -0
  48. package/dist/diagnostics/slow-sql-source/parsers.d.ts +7 -0
  49. package/dist/diagnostics/slow-sql-source/parsers.js +125 -0
  50. package/dist/diagnostics/slow-sql-source/taurus-api-source.d.ts +42 -0
  51. package/dist/diagnostics/slow-sql-source/taurus-api-source.js +149 -0
  52. package/dist/diagnostics/slow-sql-source/types.d.ts +40 -0
  53. package/dist/diagnostics/slow-sql-source/types.js +1 -0
  54. package/dist/diagnostics/slow-sql-source/utils.d.ts +20 -0
  55. package/dist/diagnostics/slow-sql-source/utils.js +170 -0
  56. package/dist/diagnostics/slow-sql-source.d.ts +4 -0
  57. package/dist/diagnostics/slow-sql-source.js +3 -0
  58. package/dist/diagnostics/types.d.ts +189 -0
  59. package/dist/diagnostics/types.js +39 -0
  60. package/dist/engine/data-access/locks.d.ts +8 -0
  61. package/dist/engine/data-access/locks.js +146 -0
  62. package/dist/engine/data-access/processlist.d.ts +4 -0
  63. package/dist/engine/data-access/processlist.js +56 -0
  64. package/dist/engine/data-access/statements.d.ts +10 -0
  65. package/dist/engine/data-access/statements.js +203 -0
  66. package/dist/engine/data-access/storage.d.ts +6 -0
  67. package/dist/engine/data-access/storage.js +96 -0
  68. package/dist/engine/data-access.d.ts +4 -0
  69. package/dist/engine/data-access.js +4 -0
  70. package/dist/engine/diagnostics.d.ts +7 -0
  71. package/dist/engine/diagnostics.js +7 -0
  72. package/dist/engine/helper-modules/diagnostics.d.ts +57 -0
  73. package/dist/engine/helper-modules/diagnostics.js +322 -0
  74. package/dist/engine/helper-modules/parsers.d.ts +13 -0
  75. package/dist/engine/helper-modules/parsers.js +283 -0
  76. package/dist/engine/helper-modules/sql.d.ts +12 -0
  77. package/dist/engine/helper-modules/sql.js +119 -0
  78. package/dist/engine/helper-modules/types.d.ts +103 -0
  79. package/dist/engine/helper-modules/types.js +1 -0
  80. package/dist/engine/helpers.d.ts +4 -0
  81. package/dist/engine/helpers.js +4 -0
  82. package/dist/engine/runtime.d.ts +20 -0
  83. package/dist/engine/runtime.js +385 -0
  84. package/dist/engine/types.d.ts +125 -0
  85. package/dist/engine/types.js +1 -0
  86. package/dist/engine/workflows/connection-spike.d.ts +4 -0
  87. package/dist/engine/workflows/connection-spike.js +316 -0
  88. package/dist/engine/workflows/db-hotspot.d.ts +4 -0
  89. package/dist/engine/workflows/db-hotspot.js +182 -0
  90. package/dist/engine/workflows/lock-contention-helpers/entities.d.ts +9 -0
  91. package/dist/engine/workflows/lock-contention-helpers/entities.js +58 -0
  92. package/dist/engine/workflows/lock-contention-helpers/no-match.d.ts +3 -0
  93. package/dist/engine/workflows/lock-contention-helpers/no-match.js +65 -0
  94. package/dist/engine/workflows/lock-contention-helpers/report.d.ts +21 -0
  95. package/dist/engine/workflows/lock-contention-helpers/report.js +104 -0
  96. package/dist/engine/workflows/lock-contention-helpers/root-cause.d.ts +4 -0
  97. package/dist/engine/workflows/lock-contention-helpers/root-cause.js +79 -0
  98. package/dist/engine/workflows/lock-contention-helpers/signals.d.ts +22 -0
  99. package/dist/engine/workflows/lock-contention-helpers/signals.js +34 -0
  100. package/dist/engine/workflows/lock-contention-helpers.d.ts +5 -0
  101. package/dist/engine/workflows/lock-contention-helpers.js +5 -0
  102. package/dist/engine/workflows/lock-contention.d.ts +4 -0
  103. package/dist/engine/workflows/lock-contention.js +67 -0
  104. package/dist/engine/workflows/service-latency.d.ts +4 -0
  105. package/dist/engine/workflows/service-latency.js +262 -0
  106. package/dist/engine/workflows/slow-query-helpers.d.ts +41 -0
  107. package/dist/engine/workflows/slow-query-helpers.js +253 -0
  108. package/dist/engine/workflows/slow-query.d.ts +4 -0
  109. package/dist/engine/workflows/slow-query.js +156 -0
  110. package/dist/engine/workflows/storage-pressure-helpers.d.ts +12 -0
  111. package/dist/engine/workflows/storage-pressure-helpers.js +281 -0
  112. package/dist/engine/workflows/storage-pressure.d.ts +4 -0
  113. package/dist/engine/workflows/storage-pressure.js +27 -0
  114. package/dist/engine/workflows/top-slow-sql.d.ts +4 -0
  115. package/dist/engine/workflows/top-slow-sql.js +222 -0
  116. package/dist/engine.d.ts +77 -0
  117. package/dist/engine.js +240 -0
  118. package/dist/executor/adapters/mysql.d.ts +2 -0
  119. package/dist/executor/adapters/mysql.js +114 -0
  120. package/dist/executor/connection-pool.d.ts +105 -0
  121. package/dist/executor/connection-pool.js +236 -0
  122. package/dist/executor/explain.d.ts +5 -0
  123. package/dist/executor/explain.js +119 -0
  124. package/dist/executor/query-tracker.d.ts +45 -0
  125. package/dist/executor/query-tracker.js +83 -0
  126. package/dist/executor/result-normalizer.d.ts +6 -0
  127. package/dist/executor/result-normalizer.js +47 -0
  128. package/dist/executor/sql-executor.d.ts +32 -0
  129. package/dist/executor/sql-executor.js +250 -0
  130. package/dist/executor/types.d.ts +70 -0
  131. package/dist/executor/types.js +1 -0
  132. package/dist/index.d.ts +40 -0
  133. package/dist/index.js +21 -0
  134. package/dist/safety/confirmation-store.d.ts +44 -0
  135. package/dist/safety/confirmation-store.js +130 -0
  136. package/dist/safety/guardrail.d.ts +39 -0
  137. package/dist/safety/guardrail.js +99 -0
  138. package/dist/safety/parser/adapter.d.ts +10 -0
  139. package/dist/safety/parser/adapter.js +72 -0
  140. package/dist/safety/parser/ast-utils.d.ts +10 -0
  141. package/dist/safety/parser/ast-utils.js +167 -0
  142. package/dist/safety/parser/features.d.ts +12 -0
  143. package/dist/safety/parser/features.js +113 -0
  144. package/dist/safety/parser/index.d.ts +2 -0
  145. package/dist/safety/parser/index.js +1 -0
  146. package/dist/safety/parser/types.d.ts +76 -0
  147. package/dist/safety/parser/types.js +1 -0
  148. package/dist/safety/redaction.d.ts +34 -0
  149. package/dist/safety/redaction.js +186 -0
  150. package/dist/safety/sql-classifier.d.ts +19 -0
  151. package/dist/safety/sql-classifier.js +43 -0
  152. package/dist/safety/sql-validator.d.ts +19 -0
  153. package/dist/safety/sql-validator.js +143 -0
  154. package/dist/schema/adapters/mysql.d.ts +16 -0
  155. package/dist/schema/adapters/mysql.js +287 -0
  156. package/dist/schema/introspector.d.ts +70 -0
  157. package/dist/schema/introspector.js +40 -0
  158. package/dist/taurus/flashback.d.ts +36 -0
  159. package/dist/taurus/flashback.js +149 -0
  160. package/dist/taurus/recycle-bin.d.ts +14 -0
  161. package/dist/taurus/recycle-bin.js +61 -0
  162. package/dist/utils/formatter.d.ts +70 -0
  163. package/dist/utils/formatter.js +60 -0
  164. package/dist/utils/hash.d.ts +2 -0
  165. package/dist/utils/hash.js +247 -0
  166. package/dist/utils/id.d.ts +2 -0
  167. package/dist/utils/id.js +11 -0
  168. package/dist/utils/logger.d.ts +9 -0
  169. package/dist/utils/logger.js +39 -0
  170. package/package.json +46 -0
@@ -0,0 +1,104 @@
1
+ import { isIdleTransactionBlocker, } from "../../helpers.js";
2
+ export function buildLockContentionKeyFindings(input) {
3
+ const { rows, metadataLockRows, latestDeadlock, diagnosisInput, signals } = input;
4
+ const { blockerCounts, topBlocker, idleTransactionBlockers, topTable, longWaits, } = signals;
5
+ const keyFindings = [
6
+ rows.length > 0
7
+ ? `Collected ${rows.length} current InnoDB lock waits across ${blockerCounts.length} blocker sessions.`
8
+ : "No current InnoDB row-lock waits were captured.",
9
+ ];
10
+ if (topBlocker) {
11
+ keyFindings.push(`Blocking session ${topBlocker.key} accounts for ${topBlocker.count} waits in the current snapshot.`);
12
+ }
13
+ if (idleTransactionBlockers.length > 0) {
14
+ keyFindings.push(`${idleTransactionBlockers.length} waits are blocked by idle sessions with active transactions; an idle processlist state does not imply locks are released when the transaction remains uncommitted.`);
15
+ }
16
+ if (topTable) {
17
+ keyFindings.push(`Most waits are concentrated on ${topTable.key} (${topTable.count} waits).`);
18
+ }
19
+ if (longWaits.length > 0) {
20
+ keyFindings.push(`${longWaits.length} waits have been blocked for at least 60 seconds.`);
21
+ }
22
+ if (diagnosisInput.blockerSessionId) {
23
+ keyFindings.push(`Diagnosis was filtered to blocker session ${diagnosisInput.blockerSessionId}.`);
24
+ }
25
+ if (metadataLockRows.length > 0) {
26
+ keyFindings.push(`Collected ${metadataLockRows.length} current metadata-lock waits.`);
27
+ }
28
+ if (latestDeadlock) {
29
+ keyFindings.push(latestDeadlock.detectedAt
30
+ ? `Latest detected deadlock timestamp: ${latestDeadlock.detectedAt}.`
31
+ : "SHOW ENGINE INNODB STATUS returned a latest detected deadlock section.");
32
+ }
33
+ return keyFindings;
34
+ }
35
+ export function buildLockContentionRecommendedActions(input) {
36
+ const { latestDeadlock, metadataLockRows, signals } = input;
37
+ const { idleTransactionBlockers, topTable, tableLevelWaits } = signals;
38
+ const recommendedActions = [
39
+ "Inspect the blocker session in show_processlist with include_info=true before terminating it.",
40
+ "Review transaction scope and commit timing in the blocking application path to reduce lock hold time.",
41
+ ];
42
+ if (idleTransactionBlockers.length > 0) {
43
+ recommendedActions.push("For idle blocker sessions (Sleep or no active processlist state), verify whether the application left a transaction uncommitted; prefer COMMIT or ROLLBACK from the owning client before considering KILL.");
44
+ }
45
+ if (topTable) {
46
+ recommendedActions.push(`Review the access pattern and indexing on ${topTable.key} to reduce hot-row or hot-table conflicts.`);
47
+ }
48
+ if (tableLevelWaits.length > 0) {
49
+ recommendedActions.push("Check for DDL or explicit table-lock operations because TABLE-level waits are present in the snapshot.");
50
+ }
51
+ if (metadataLockRows.length > 0) {
52
+ recommendedActions.push("Review DDL, online schema change tooling, and long-running transactions because metadata-lock waits are present.");
53
+ }
54
+ if (latestDeadlock) {
55
+ recommendedActions.push("Inspect the latest deadlock section in SHOW ENGINE INNODB STATUS and correlate the involved statements before changing only timeout or retry settings.");
56
+ }
57
+ return [...new Set(recommendedActions)];
58
+ }
59
+ export function buildLockContentionEvidence(input) {
60
+ const { rows, metadataLockRows, latestDeadlock, signals } = input;
61
+ const { blockerCounts, tableCounts, topBlocker, topTable, topMetadataTable, topMetadataBlocker, } = signals;
62
+ const evidence = [
63
+ {
64
+ source: "lock_waits",
65
+ title: "Current InnoDB lock-wait snapshot",
66
+ summary: rows.length > 0
67
+ ? `${rows.length} waits observed across ${blockerCounts.length} blocker sessions and ${tableCounts.length} locked tables.`
68
+ : "No InnoDB row-lock waits were visible in the current snapshot.",
69
+ },
70
+ ];
71
+ if (topBlocker) {
72
+ const idleBlocker = rows.find((row) => row.blockingSessionId === topBlocker.key &&
73
+ isIdleTransactionBlocker(row));
74
+ evidence.push({
75
+ source: "lock_waits",
76
+ title: "Dominant blocker session",
77
+ summary: idleBlocker
78
+ ? `Session ${topBlocker.key} is blocking ${topBlocker.count} current waits while it has no active processlist state; its transaction is still ${idleBlocker.blockingTrxState}, so an uncommitted transaction can continue holding locks.`
79
+ : `Session ${topBlocker.key} is blocking ${topBlocker.count} current waits.`,
80
+ });
81
+ }
82
+ if (topTable) {
83
+ evidence.push({
84
+ source: "lock_waits",
85
+ title: "Hot locked table",
86
+ summary: `${topTable.key} appears in ${topTable.count} current waits.`,
87
+ });
88
+ }
89
+ if (metadataLockRows.length > 0) {
90
+ evidence.push({
91
+ source: "metadata_locks",
92
+ title: "Current metadata-lock snapshot",
93
+ summary: `Collected ${metadataLockRows.length} pending metadata locks${topMetadataTable ? `; hottest object=${topMetadataTable.key}` : ""}${topMetadataBlocker ? `, dominant blocker=${topMetadataBlocker.key}` : ""}.`,
94
+ });
95
+ }
96
+ if (latestDeadlock) {
97
+ evidence.push({
98
+ source: "deadlock_history",
99
+ title: "Latest detected deadlock",
100
+ summary: latestDeadlock.summary,
101
+ });
102
+ }
103
+ return evidence;
104
+ }
@@ -0,0 +1,4 @@
1
+ import type { DiagnosticRootCauseCandidate } from "../../../diagnostics/types.js";
2
+ import type { DeadlockSummary } from "../../helpers.js";
3
+ import type { LockContentionSignals } from "./signals.js";
4
+ export declare function buildLockContentionRootCauseCandidates(signals: LockContentionSignals, latestDeadlock?: DeadlockSummary): DiagnosticRootCauseCandidate[];
@@ -0,0 +1,79 @@
1
+ export function buildLockContentionRootCauseCandidates(signals, latestDeadlock) {
2
+ const candidates = [];
3
+ const { idleTransactionBlockers, topBlocker, longWaits, tableLevelWaits, topTable, topMetadataBlocker, topMetadataTable, } = signals;
4
+ if (idleTransactionBlockers.length > 0) {
5
+ candidates.push({
6
+ code: "lock_contention_idle_transaction_blocker",
7
+ title: "Idle transaction blocker is holding locks",
8
+ confidence: idleTransactionBlockers.length >= 2 ? "high" : "medium",
9
+ rationale: `${idleTransactionBlockers.length} current waits are blocked by sessions with no active processlist state while their transaction is still active; an idle session can continue holding row locks until COMMIT or ROLLBACK.`,
10
+ });
11
+ }
12
+ if (topBlocker && topBlocker.count >= 2) {
13
+ candidates.push({
14
+ code: "lock_contention_single_blocker_hotspot",
15
+ title: "A single blocker session is holding up multiple waiters",
16
+ confidence: topBlocker.count >= 3 ? "high" : "medium",
17
+ rationale: `Blocking session ${topBlocker.key} appears in ${topBlocker.count} current lock waits.`,
18
+ });
19
+ }
20
+ if (longWaits.length > 0) {
21
+ candidates.push({
22
+ code: "lock_contention_long_wait_chain",
23
+ title: "Long lock waits indicate a stuck or slow blocker transaction",
24
+ confidence: longWaits.length >= 2 ? "high" : "medium",
25
+ rationale: `${longWaits.length} current lock waits have been blocked for at least 60 seconds.`,
26
+ });
27
+ }
28
+ if (tableLevelWaits.length > 0) {
29
+ candidates.push({
30
+ code: "lock_contention_table_level_locking",
31
+ title: "Table-level locking is amplifying the wait chain",
32
+ confidence: tableLevelWaits.length >= 2 ? "medium" : "low",
33
+ rationale: "At least one current wait involves a TABLE lock, which often points to broader blocking impact than a single row conflict.",
34
+ });
35
+ }
36
+ if (topTable && topTable.count >= 2) {
37
+ candidates.push({
38
+ code: "lock_contention_hot_table",
39
+ title: "Contention is concentrated on a single table",
40
+ confidence: topTable.count >= 3 ? "high" : "medium",
41
+ rationale: `${topTable.key} appears in ${topTable.count} current lock waits.`,
42
+ });
43
+ }
44
+ if (topMetadataBlocker && topMetadataBlocker.count >= 1) {
45
+ candidates.push({
46
+ code: "lock_contention_metadata_lock_blocker",
47
+ title: "Metadata lock waits point to a blocker session",
48
+ confidence: topMetadataBlocker.count >= 2 ? "high" : "medium",
49
+ rationale: `Blocking session ${topMetadataBlocker.key} appears in ${topMetadataBlocker.count} current metadata-lock waits.`,
50
+ });
51
+ }
52
+ if (topMetadataTable) {
53
+ candidates.push({
54
+ code: "lock_contention_metadata_lock_hot_object",
55
+ title: "Metadata lock contention is concentrated on one object",
56
+ confidence: topMetadataTable.count >= 2 ? "medium" : "low",
57
+ rationale: `${topMetadataTable.key} appears in ${topMetadataTable.count} current metadata-lock waits.`,
58
+ });
59
+ }
60
+ if (latestDeadlock) {
61
+ candidates.push({
62
+ code: "lock_contention_recent_deadlock_detected",
63
+ title: "A recent deadlock was detected by InnoDB",
64
+ confidence: "medium",
65
+ rationale: latestDeadlock.detectedAt
66
+ ? `SHOW ENGINE INNODB STATUS reports a latest detected deadlock at ${latestDeadlock.detectedAt}.`
67
+ : "SHOW ENGINE INNODB STATUS reports a recent deadlock in the latest deadlock section.",
68
+ });
69
+ }
70
+ if (candidates.length === 0) {
71
+ candidates.push({
72
+ code: "lock_contention_snapshot_collected",
73
+ title: "Lock waits are present but no dominant blocker pattern was isolated",
74
+ confidence: "low",
75
+ rationale: "A live lock-wait snapshot was collected, but the current wait chain does not show one dominant blocker, table, or long-wait pattern.",
76
+ });
77
+ }
78
+ return candidates;
79
+ }
@@ -0,0 +1,22 @@
1
+ import type { DiagnosticSeverity } from "../../../diagnostics/types.js";
2
+ import { type LockWaitRow, type MetadataLockRow } from "../../helpers.js";
3
+ type CountEntry = {
4
+ key: string;
5
+ count: number;
6
+ };
7
+ export type LockContentionSignals = {
8
+ blockerCounts: CountEntry[];
9
+ tableCounts: CountEntry[];
10
+ metadataTables: CountEntry[];
11
+ metadataBlockers: CountEntry[];
12
+ longWaits: LockWaitRow[];
13
+ tableLevelWaits: LockWaitRow[];
14
+ idleTransactionBlockers: LockWaitRow[];
15
+ topBlocker?: CountEntry;
16
+ topTable?: CountEntry;
17
+ topMetadataTable?: CountEntry;
18
+ topMetadataBlocker?: CountEntry;
19
+ };
20
+ export declare function buildLockContentionSignals(rows: LockWaitRow[], metadataLockRows: MetadataLockRow[]): LockContentionSignals;
21
+ export declare function severityFromLockContentionSignals(rows: LockWaitRow[], signals: Pick<LockContentionSignals, "longWaits">): DiagnosticSeverity;
22
+ export {};
@@ -0,0 +1,34 @@
1
+ import { countBy, isIdleTransactionBlocker, } from "../../helpers.js";
2
+ export function buildLockContentionSignals(rows, metadataLockRows) {
3
+ const blockerCounts = countBy(rows, (row) => row.blockingSessionId);
4
+ const tableCounts = countBy(rows, (row) => row.lockedSchema && row.lockedTable
5
+ ? `${row.lockedSchema}.${row.lockedTable}`
6
+ : row.lockedTable);
7
+ const metadataTables = countBy(metadataLockRows, (row) => row.objectSchema && row.objectName
8
+ ? `${row.objectSchema}.${row.objectName}`
9
+ : row.objectName);
10
+ const metadataBlockers = countBy(metadataLockRows, (row) => row.blockingSessionId);
11
+ const longWaits = rows.filter((row) => (row.waitAgeSeconds ?? 0) >= 60);
12
+ const tableLevelWaits = rows.filter((row) => row.waitingLockType === "TABLE" || row.blockingLockType === "TABLE");
13
+ const idleTransactionBlockers = rows.filter(isIdleTransactionBlocker);
14
+ return {
15
+ blockerCounts,
16
+ tableCounts,
17
+ metadataTables,
18
+ metadataBlockers,
19
+ longWaits,
20
+ tableLevelWaits,
21
+ idleTransactionBlockers,
22
+ topBlocker: blockerCounts[0],
23
+ topTable: tableCounts[0],
24
+ topMetadataTable: metadataTables[0],
25
+ topMetadataBlocker: metadataBlockers[0],
26
+ };
27
+ }
28
+ export function severityFromLockContentionSignals(rows, signals) {
29
+ return rows.length >= 10 || signals.longWaits.length >= 3
30
+ ? "high"
31
+ : rows.length >= 3 || signals.longWaits.length >= 1
32
+ ? "warning"
33
+ : "info";
34
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./lock-contention-helpers/entities.js";
2
+ export * from "./lock-contention-helpers/no-match.js";
3
+ export * from "./lock-contention-helpers/report.js";
4
+ export * from "./lock-contention-helpers/root-cause.js";
5
+ export * from "./lock-contention-helpers/signals.js";
@@ -0,0 +1,5 @@
1
+ export * from "./lock-contention-helpers/entities.js";
2
+ export * from "./lock-contention-helpers/no-match.js";
3
+ export * from "./lock-contention-helpers/report.js";
4
+ export * from "./lock-contention-helpers/root-cause.js";
5
+ export * from "./lock-contention-helpers/signals.js";
@@ -0,0 +1,4 @@
1
+ import type { SessionContext } from "../../context/session-context.js";
2
+ import type { DiagnoseLockContentionInput, DiagnosticResult } from "../../diagnostics/types.js";
3
+ import type { TaurusDBEngine } from "../../engine.js";
4
+ export declare function diagnoseLockContention(engine: TaurusDBEngine, input: DiagnoseLockContentionInput, ctx: SessionContext): Promise<DiagnosticResult>;
@@ -0,0 +1,67 @@
1
+ import { clampInteger, lockEvidenceRowLimit, parseLockWaitRows, withDatasourceSummary } from "../helpers.js";
2
+ import { buildLockContentionEvidence, buildLockContentionKeyFindings, buildLockContentionRecommendedActions, buildLockContentionRootCauseCandidates, buildLockContentionSignals, buildLockContentionSuspiciousEntities, buildNoMatchingLockContentionResult, severityFromLockContentionSignals, } from "./lock-contention-helpers.js";
3
+ export async function diagnoseLockContention(engine, input, ctx) {
4
+ const [lockWaits, metadataLockRows, latestDeadlock] = await Promise.all([
5
+ engine.showLockWaits({
6
+ table: input.table,
7
+ blockerSessionId: input.blockerSessionId,
8
+ includeSql: false,
9
+ maxRows: lockEvidenceRowLimit(input.evidenceLevel),
10
+ }, ctx),
11
+ engine.findMetadataLockWaits(input, ctx),
12
+ engine.findLatestDeadlock(ctx),
13
+ ]);
14
+ const rows = parseLockWaitRows(lockWaits);
15
+ const signals = buildLockContentionSignals(rows, metadataLockRows);
16
+ if (rows.length === 0 &&
17
+ metadataLockRows.length === 0 &&
18
+ latestDeadlock === undefined) {
19
+ return buildNoMatchingLockContentionResult(input, ctx);
20
+ }
21
+ const maxCandidates = clampInteger(input.maxCandidates, 3, 1, 10);
22
+ const severity = severityFromLockContentionSignals(rows, signals);
23
+ const rootCauseCandidates = buildLockContentionRootCauseCandidates(signals, latestDeadlock);
24
+ const suspiciousEntities = buildLockContentionSuspiciousEntities({
25
+ rows,
26
+ metadataLockRows,
27
+ latestDeadlock,
28
+ signals,
29
+ });
30
+ return {
31
+ tool: "diagnose_lock_contention",
32
+ status: "ok",
33
+ severity,
34
+ summary: withDatasourceSummary(`Lock-contention diagnosis collected a live InnoDB lock-wait snapshot with ${rows.length} matching waits`, ctx.datasource),
35
+ diagnosisWindow: {
36
+ from: input.timeRange?.from,
37
+ to: input.timeRange?.to,
38
+ relative: input.timeRange?.relative,
39
+ },
40
+ rootCauseCandidates: rootCauseCandidates.slice(0, maxCandidates),
41
+ keyFindings: buildLockContentionKeyFindings({
42
+ rows,
43
+ metadataLockRows,
44
+ latestDeadlock,
45
+ diagnosisInput: input,
46
+ signals,
47
+ }),
48
+ suspiciousEntities,
49
+ evidence: buildLockContentionEvidence({
50
+ rows,
51
+ metadataLockRows,
52
+ latestDeadlock,
53
+ signals,
54
+ }),
55
+ recommendedActions: buildLockContentionRecommendedActions({
56
+ latestDeadlock,
57
+ metadataLockRows,
58
+ signals,
59
+ }),
60
+ limitations: [
61
+ "Live lock evidence remains point-in-time; waits that finish before collection will not appear.",
62
+ latestDeadlock
63
+ ? "Deadlock history currently uses the latest deadlock section only and does not yet parse a longer deadlock archive."
64
+ : "Deadlock history was not available from SHOW ENGINE INNODB STATUS in this run.",
65
+ ],
66
+ };
67
+ }
@@ -0,0 +1,4 @@
1
+ import type { SessionContext } from "../../context/session-context.js";
2
+ import { type DiagnoseServiceLatencyInput, type ServiceLatencyResult } from "../../diagnostics/types.js";
3
+ import type { TaurusDBEngine } from "../../engine.js";
4
+ export declare function diagnoseServiceLatency(engine: TaurusDBEngine, input: DiagnoseServiceLatencyInput, ctx: SessionContext): Promise<ServiceLatencyResult>;
@@ -0,0 +1,262 @@
1
+ import { buildConnectionSpikeNextToolInput, buildLockContentionNextToolInput, buildShowProcesslistNextToolInput, buildSlowQueryNextToolInput, clampInteger, confidenceWeight, dedupeNextToolInputs, metricSummaryText, metricsSourceLimitation, pickMetric, queryMetricsSafely, roundMetric, serviceCategoryPriority, withDatasourceSummary, } from "../helpers.js";
2
+ export async function diagnoseServiceLatency(engine, input, ctx) {
3
+ const maxCandidates = clampInteger(input.maxCandidates, 5, 1, 10);
4
+ const [topSlowSql, lockContention, connectionSpike, metrics] = await Promise.all([
5
+ engine.findTopSlowSql({
6
+ ...input,
7
+ topN: Math.min(maxCandidates, 5),
8
+ sortBy: input.symptom === "latency" || input.symptom === "timeout"
9
+ ? "avg_latency"
10
+ : "total_latency",
11
+ }, ctx),
12
+ input.symptom === "connection_growth"
13
+ ? Promise.resolve(undefined)
14
+ : engine.diagnoseLockContention({
15
+ ...input,
16
+ maxCandidates: Math.min(maxCandidates, 3),
17
+ }, ctx),
18
+ engine.diagnoseConnectionSpike({
19
+ ...input,
20
+ user: input.user,
21
+ clientHost: input.clientHost,
22
+ compareBaseline: false,
23
+ maxCandidates: Math.min(maxCandidates, 3),
24
+ }, ctx),
25
+ queryMetricsSafely(engine.metricsSource, [
26
+ "cpu_util",
27
+ "mem_util",
28
+ "connection_usage",
29
+ "qps",
30
+ "slow_queries",
31
+ "storage_write_delay",
32
+ "storage_read_delay",
33
+ ], input, ctx),
34
+ ]);
35
+ const cpuMetric = pickMetric(metrics, "cpu_util");
36
+ const memMetric = pickMetric(metrics, "mem_util");
37
+ const connectionUsageMetric = pickMetric(metrics, "connection_usage");
38
+ const slowQueriesMetric = pickMetric(metrics, "slow_queries");
39
+ const writeDelayMetric = pickMetric(metrics, "storage_write_delay");
40
+ const readDelayMetric = pickMetric(metrics, "storage_read_delay");
41
+ const topCandidates = [];
42
+ const evidence = [];
43
+ const recommendedNextTools = new Set();
44
+ const nextToolInputs = [];
45
+ const limitations = new Set();
46
+ const categoryScores = new Map();
47
+ const scoreCategory = (category, score) => {
48
+ categoryScores.set(category, Math.max(categoryScores.get(category) ?? 0, score));
49
+ };
50
+ if (topSlowSql.status === "ok" && topSlowSql.topSqls.length > 0) {
51
+ const leadSql = topSlowSql.topSqls[0];
52
+ const sqlConfidence = (leadSql.totalLatencyMs ?? 0) >= 1000 ||
53
+ (leadSql.avgLatencyMs ?? 0) >= 100
54
+ ? "high"
55
+ : (leadSql.totalLatencyMs ?? 0) > 0 || (leadSql.avgLatencyMs ?? 0) > 0
56
+ ? "medium"
57
+ : "low";
58
+ topCandidates.push({
59
+ type: "sql",
60
+ title: leadSql.digestText
61
+ ? `Top ranked SQL digest: ${leadSql.digestText}`
62
+ : "Top ranked SQL digest",
63
+ confidence: sqlConfidence,
64
+ sqlHash: leadSql.sqlHash,
65
+ digestText: leadSql.digestText,
66
+ sampleSql: leadSql.sampleSql,
67
+ rationale: `Ranked near the top of statement digest summaries${leadSql.avgLatencyMs !== undefined ? `; avg_latency_ms=${leadSql.avgLatencyMs}` : ""}${leadSql.totalLatencyMs !== undefined ? `, total_latency_ms=${leadSql.totalLatencyMs}` : ""}${leadSql.execCount !== undefined ? `, exec_count=${leadSql.execCount}` : ""}${leadSql.avgRowsExamined !== undefined ? `, avg_rows_examined=${leadSql.avgRowsExamined}` : ""}.`,
68
+ });
69
+ const slowQueryInput = buildSlowQueryNextToolInput(leadSql, input, "Analyze the top-ranked SQL candidate from the service-latency symptom route.");
70
+ if (slowQueryInput) {
71
+ nextToolInputs.push(slowQueryInput);
72
+ }
73
+ evidence.push(...topSlowSql.evidence.slice(0, 1));
74
+ recommendedNextTools.add("diagnose_slow_query");
75
+ if ((leadSql.avgLockTimeMs ?? 0) >= 10) {
76
+ recommendedNextTools.add("diagnose_lock_contention");
77
+ }
78
+ scoreCategory("slow_sql", input.symptom === "cpu"
79
+ ? 4
80
+ : input.symptom === "latency" || input.symptom === "timeout"
81
+ ? 3
82
+ : 2);
83
+ }
84
+ for (const limitation of topSlowSql.limitations ?? []) {
85
+ limitations.add(limitation);
86
+ }
87
+ if (lockContention) {
88
+ for (const limitation of lockContention.limitations ?? []) {
89
+ limitations.add(limitation);
90
+ }
91
+ if (lockContention.status === "ok") {
92
+ const leadBlocker = lockContention.suspiciousEntities?.sessions?.[0];
93
+ const leadTable = lockContention.suspiciousEntities?.tables?.[0];
94
+ const leadRootCause = lockContention.rootCauseCandidates[0];
95
+ if (leadBlocker) {
96
+ topCandidates.push({
97
+ type: "session",
98
+ title: leadBlocker.sessionId
99
+ ? `Blocking session ${leadBlocker.sessionId}`
100
+ : "Blocking session hotspot",
101
+ confidence: leadRootCause?.confidence ?? "medium",
102
+ sessionId: leadBlocker.sessionId,
103
+ rationale: leadBlocker.reason,
104
+ });
105
+ }
106
+ if (leadTable) {
107
+ topCandidates.push({
108
+ type: "table",
109
+ title: `Hot locked table ${leadTable.table}`,
110
+ confidence: lockContention.rootCauseCandidates.some((candidate) => candidate.code === "lock_contention_hot_table")
111
+ ? "high"
112
+ : (leadRootCause?.confidence ?? "medium"),
113
+ table: leadTable.table,
114
+ rationale: leadTable.reason,
115
+ });
116
+ }
117
+ evidence.push(...lockContention.evidence.slice(0, 2));
118
+ recommendedNextTools.add("diagnose_lock_contention");
119
+ recommendedNextTools.add("show_processlist");
120
+ nextToolInputs.push(buildLockContentionNextToolInput({
121
+ table: leadTable?.table,
122
+ blockerSessionId: leadBlocker?.sessionId,
123
+ }, input, "Inspect the lock-wait candidate identified by the service-latency symptom route."), buildShowProcesslistNextToolInput({
124
+ command: "Query",
125
+ includeIdle: false,
126
+ includeInfo: true,
127
+ }, input, "Review live running sessions around the lock-contention signal."));
128
+ const lockScoreBase = input.symptom === "timeout" ? 5 : input.symptom === "latency" ? 4 : 2;
129
+ scoreCategory("lock_contention", lockContention.rootCauseCandidates.some((candidate) => candidate.code === "lock_contention_single_blocker_hotspot")
130
+ ? lockScoreBase + 1
131
+ : lockScoreBase);
132
+ }
133
+ }
134
+ for (const limitation of connectionSpike.limitations ?? []) {
135
+ limitations.add(limitation);
136
+ }
137
+ if (connectionSpike.status === "ok") {
138
+ const focusUser = connectionSpike.suspiciousEntities?.users?.[0];
139
+ const focusSession = connectionSpike.suspiciousEntities?.sessions?.[0];
140
+ const leadRootCause = connectionSpike.rootCauseCandidates[0];
141
+ topCandidates.push({
142
+ type: "session",
143
+ title: focusUser?.user
144
+ ? `Connection growth around user ${focusUser.user}`
145
+ : focusSession?.sessionId
146
+ ? `Connection growth around session ${focusSession.sessionId}`
147
+ : "Connection growth hotspot",
148
+ confidence: leadRootCause?.confidence ?? "medium",
149
+ sessionId: focusSession?.sessionId,
150
+ rationale: focusUser?.reason ??
151
+ focusSession?.reason ??
152
+ "A live processlist snapshot suggests connection growth around a focused user or long-running sessions.",
153
+ });
154
+ evidence.push(...connectionSpike.evidence.slice(0, 2));
155
+ recommendedNextTools.add("diagnose_connection_spike");
156
+ recommendedNextTools.add("show_processlist");
157
+ nextToolInputs.push(buildConnectionSpikeNextToolInput({
158
+ user: focusUser?.user ?? input.user,
159
+ clientHost: focusUser?.clientHost ?? input.clientHost,
160
+ }, input, "Inspect the connection-growth candidate identified by the service-latency symptom route."), buildShowProcesslistNextToolInput({
161
+ user: focusUser?.user ?? input.user,
162
+ host: focusUser?.clientHost ?? input.clientHost,
163
+ includeIdle: true,
164
+ includeInfo: true,
165
+ }, input, "Review live sessions for idle buildup or long-running queries around the connection signal."));
166
+ const connectionScoreBase = input.symptom === "connection_growth"
167
+ ? 5
168
+ : input.symptom === "latency" || input.symptom === "timeout"
169
+ ? 2
170
+ : 1;
171
+ scoreCategory("connection_spike", connectionSpike.rootCauseCandidates.some((candidate) => candidate.code === "connection_spike_idle_session_accumulation")
172
+ ? connectionScoreBase + 1
173
+ : connectionScoreBase);
174
+ }
175
+ if (metrics.length > 0) {
176
+ evidence.push(...metrics.slice(0, 4).map((metric) => ({
177
+ source: "ces_metrics",
178
+ title: `CES ${metric.alias}`,
179
+ summary: metricSummaryText(metric),
180
+ })));
181
+ if ((cpuMetric?.max ?? 0) >= 80 || (memMetric?.max ?? 0) >= 90) {
182
+ topCandidates.push({
183
+ type: "session",
184
+ title: "Instance resource pressure from CES metrics",
185
+ confidence: (cpuMetric?.max ?? 0) >= 90 || (memMetric?.max ?? 0) >= 95
186
+ ? "high"
187
+ : "medium",
188
+ rationale: `Cloud Eye metrics show instance resource pressure${cpuMetric?.max !== undefined ? `; max_cpu=${roundMetric(cpuMetric.max)}` : ""}${memMetric?.max !== undefined ? `, max_mem=${roundMetric(memMetric.max)}` : ""}.`,
189
+ });
190
+ recommendedNextTools.add("diagnose_storage_pressure");
191
+ scoreCategory("resource_pressure", input.symptom === "cpu" ? 6 : 3);
192
+ }
193
+ if ((writeDelayMetric?.max ?? 0) >= 50 ||
194
+ (readDelayMetric?.max ?? 0) >= 50) {
195
+ recommendedNextTools.add("diagnose_storage_pressure");
196
+ scoreCategory("resource_pressure", 4);
197
+ }
198
+ if ((connectionUsageMetric?.max ?? 0) >= 80) {
199
+ recommendedNextTools.add("diagnose_connection_spike");
200
+ scoreCategory("connection_spike", input.symptom === "connection_growth" ? 6 : 3);
201
+ }
202
+ if ((slowQueriesMetric?.max ?? 0) > 0) {
203
+ recommendedNextTools.add("find_top_slow_sql");
204
+ recommendedNextTools.add("diagnose_slow_query");
205
+ scoreCategory("slow_sql", input.symptom === "latency" ? 4 : 2);
206
+ }
207
+ }
208
+ else {
209
+ for (const limitation of metricsSourceLimitation(engine.metricsSource)) {
210
+ limitations.add(limitation);
211
+ }
212
+ }
213
+ const scoredCategories = [...categoryScores.entries()]
214
+ .filter(([, score]) => score > 0)
215
+ .sort((left, right) => right[1] - left[1] ||
216
+ serviceCategoryPriority(right[0]) - serviceCategoryPriority(left[0]));
217
+ const fallbackCategory = input.symptom === "cpu"
218
+ ? "resource_pressure"
219
+ : input.symptom === "connection_growth"
220
+ ? "connection_spike"
221
+ : input.symptom === "timeout"
222
+ ? "lock_contention"
223
+ : "slow_sql";
224
+ const suspectedCategory = scoredCategories.length === 0
225
+ ? fallbackCategory
226
+ : scoredCategories.length > 1 &&
227
+ scoredCategories[0][1] === scoredCategories[1][1]
228
+ ? "mixed"
229
+ : scoredCategories[0][0];
230
+ if (suspectedCategory === "resource_pressure") {
231
+ recommendedNextTools.add("diagnose_storage_pressure");
232
+ if (!engine.metricsSource) {
233
+ limitations.add("Resource-pressure routing is heuristic because no CPU, IOPS, or instance-metric collector is configured yet.");
234
+ }
235
+ }
236
+ const sortedCandidates = [...topCandidates]
237
+ .sort((left, right) => confidenceWeight(right.confidence) -
238
+ confidenceWeight(left.confidence) ||
239
+ left.title.localeCompare(right.title))
240
+ .slice(0, maxCandidates);
241
+ const summary = sortedCandidates.length > 0
242
+ ? suspectedCategory === "mixed"
243
+ ? "Service-latency diagnosis found mixed SQL, lock, or connection signals"
244
+ : `Service-latency diagnosis points to ${suspectedCategory.replace(/_/g, " ")} as the dominant suspect`
245
+ : "Service-latency diagnosis did not isolate a dominant suspect from current SQL, lock, or connection evidence";
246
+ return {
247
+ tool: "diagnose_service_latency",
248
+ status: sortedCandidates.length > 0 ? "ok" : "inconclusive",
249
+ summary: withDatasourceSummary(summary, ctx.datasource),
250
+ diagnosisWindow: {
251
+ from: input.timeRange?.from,
252
+ to: input.timeRange?.to,
253
+ relative: input.timeRange?.relative,
254
+ },
255
+ suspectedCategory,
256
+ topCandidates: sortedCandidates,
257
+ evidence: evidence.slice(0, 5),
258
+ recommendedNextTools: [...recommendedNextTools],
259
+ nextToolInputs: dedupeNextToolInputs(nextToolInputs).slice(0, maxCandidates),
260
+ limitations: [...limitations].slice(0, 5),
261
+ };
262
+ }
@@ -0,0 +1,41 @@
1
+ import type { SessionContext } from "../../context/session-context.js";
2
+ import type { DiagnosticResult, DiagnosticRootCauseCandidate } from "../../diagnostics/types.js";
3
+ import type { ExternalSlowSqlSample } from "../../diagnostics/slow-sql-source.js";
4
+ import type { TaurusDBEngine } from "../../engine.js";
5
+ import type { EnhancedExplainResult } from "../types.js";
6
+ import type { ExplainResult } from "../../executor/sql-executor.js";
7
+ import { type PlanTableStats, type StatementDigestRow, type StatementWaitEventRow } from "../helpers.js";
8
+ export declare function collectPlanTableStats(engine: TaurusDBEngine, ctx: SessionContext, plan: ExplainResult["plan"]): Promise<PlanTableStats[]>;
9
+ export declare function buildSlowQueryRootCauseCandidates(input: {
10
+ riskSummary: ExplainResult["riskSummary"];
11
+ explain: EnhancedExplainResult;
12
+ digestSample?: StatementDigestRow;
13
+ runtimeLockTimeMs?: number;
14
+ waitEventRows: StatementWaitEventRow[];
15
+ }): DiagnosticRootCauseCandidate[];
16
+ export declare function buildSlowQueryKeyFindings(input: {
17
+ riskSummary: ExplainResult["riskSummary"];
18
+ resolvedPlanTables: PlanTableStats[];
19
+ digestSample?: StatementDigestRow;
20
+ externalSlowSqlSample?: ExternalSlowSqlSample;
21
+ runtimeRowsExamined?: number;
22
+ runtimeLockTimeMs?: number;
23
+ waitEventRows: StatementWaitEventRow[];
24
+ }): string[];
25
+ export declare function buildSlowQueryRecommendedActions(input: {
26
+ standardPlan: ExplainResult;
27
+ explain: EnhancedExplainResult;
28
+ riskSummary: ExplainResult["riskSummary"];
29
+ resolvedPlanTables: PlanTableStats[];
30
+ digestSample?: StatementDigestRow;
31
+ runtimeLockTimeMs?: number;
32
+ topWaitEvent?: StatementWaitEventRow;
33
+ }): string[];
34
+ export declare function buildSlowQueryEvidence(input: {
35
+ standardPlan: ExplainResult;
36
+ riskSummary: ExplainResult["riskSummary"];
37
+ resolvedPlanTables: PlanTableStats[];
38
+ digestSample?: StatementDigestRow;
39
+ externalSlowSqlSample?: ExternalSlowSqlSample;
40
+ waitEventRows: StatementWaitEventRow[];
41
+ }): DiagnosticResult["evidence"];