Skip to content

Commit 58acc28

Browse files
Get-DbaAgRingBuffer - Fix timestamp query handling (review of #10282)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent afe35fa commit 58acc28

3 files changed

Lines changed: 111 additions & 38 deletions

File tree

docs/trackers/features/commit-bug-review-TRACKER.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ Find real bugs (logic errors, null refs, incorrect behavior) and fix them. Skip
9090
| 562e3ac31 | Expand-DbaDbLogFile - Add -TargetVlfCount parameter (#10272) | DONE | Fixed TargetVlfCount planning to account for smaller final growth steps; added unit regression test. |
9191
| 3bda32716 | Test-DbaLastBackup - Add DbccOutput property with detailed DBCC messages (#10239) | DONE | Restored Start-DbccCheck string return for legacy callers and added unit regression coverage. |
9292
| d6552592e | Update-DbaInstance - Add early validation for empty -Path parameter (#10283) | DONE | Fixed whitespace-only Path validation gap and added regression coverage. |
93-
| c82ae190c | Get-DbaAgRingBuffer - Add command for HADR ring buffer diagnostics (#10282) | PENDING | |
93+
| c82ae190c | Get-DbaAgRingBuffer - Add command for HADR ring buffer diagnostics (#10282) | DONE | Fixed timestamp DataTable expansion and routed query failures through Stop-Function; added unit regression tests. |
9494
| 552b77af4 | Invoke-DbaDbDataMasking - Fix StaticValue empty string fallback and FilterQuery in Actions (#10281) | PENDING | |
9595
| 99a4a9067 | Update-ServiceStatus - Fix WinRM error on machines without WinRM configured (#10274) | PENDING | |
9696
| 1f70b62bd | Add Remove-DbaAgentJobSchedule cmdlet (#10273) | PENDING | |

public/Get-DbaAgRingBuffer.ps1

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -114,46 +114,50 @@ function Get-DbaAgRingBuffer {
114114
Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $instance -Continue
115115
}
116116

117-
$currentTimestamp = ($server.Query("SELECT cpu_ticks / CONVERT(FLOAT, (cpu_ticks / ms_ticks)) AS TimeStamp FROM sys.dm_os_sys_info"))[0]
118-
Write-Message -Level Verbose -Message "Using current timestamp of $currentTimestamp"
117+
try {
118+
[long]$currentTimestamp = ($server.Query("SELECT cpu_ticks / CONVERT(FLOAT, (cpu_ticks / ms_ticks)) AS TimeStamp FROM sys.dm_os_sys_info")).TimeStamp
119+
Write-Message -Level Verbose -Message "Using current timestamp of $currentTimestamp"
119120

120-
if ($RingBufferType) {
121-
$typeList = ($RingBufferType | ForEach-Object { "N'$_'" }) -join ", "
122-
} else {
123-
$typeList = "N'RING_BUFFER_HADRDBMGR_API', N'RING_BUFFER_HADRDBMGR_STATE', N'RING_BUFFER_HADRDBMGR_COMMIT', N'RING_BUFFER_HADR_TRANSPORT_STATE'"
124-
}
121+
if ($RingBufferType) {
122+
$typeList = ($RingBufferType | ForEach-Object { "N'$_'" }) -join ", "
123+
} else {
124+
$typeList = "N'RING_BUFFER_HADRDBMGR_API', N'RING_BUFFER_HADRDBMGR_STATE', N'RING_BUFFER_HADRDBMGR_COMMIT', N'RING_BUFFER_HADR_TRANSPORT_STATE'"
125+
}
125126

126-
$sql = "WITH HadrRingBuffer AS
127-
(
127+
$sql = "WITH HadrRingBuffer AS
128+
(
129+
SELECT
130+
ring_buffer_type,
131+
timestamp,
132+
CONVERT(XML, record) AS record
133+
FROM sys.dm_os_ring_buffers
134+
WHERE ring_buffer_type IN ($typeList)
135+
)
128136
SELECT
137+
SERVERPROPERTY('ServerName') AS ServerName,
129138
ring_buffer_type,
130-
timestamp,
131-
CONVERT(XML, record) AS record
132-
FROM sys.dm_os_ring_buffers
133-
WHERE ring_buffer_type IN ($typeList)
134-
)
135-
SELECT
136-
SERVERPROPERTY('ServerName') AS ServerName,
137-
ring_buffer_type,
138-
record.value('(./Record/@id)[1]', 'int') AS record_id,
139-
DATEADD(ms, -1 * ($currentTimestamp - [timestamp]), GETDATE()) AS EventTime,
140-
record
141-
FROM HadrRingBuffer
142-
WHERE DATEADD(ms, -1 * ($currentTimestamp - [timestamp]), GETDATE()) > DATEADD(MINUTE, -$CollectionMinutes, GETDATE())
143-
ORDER BY EventTime DESC;"
144-
145-
Write-Message -Level Verbose -Message "Executing SQL Statement: $sql"
146-
foreach ($row in $server.Query($sql)) {
147-
[PSCustomObject]@{
148-
ComputerName = $server.ComputerName
149-
InstanceName = $server.ServiceName
150-
SqlInstance = $server.DomainInstanceName
151-
RingBufferType = $row.ring_buffer_type
152-
RecordId = $row.record_id
153-
EventTime = $row.EventTime
154-
Record = $row.record
139+
record.value('(./Record/@id)[1]', 'int') AS record_id,
140+
DATEADD(ms, -1 * ($currentTimestamp - [timestamp]), GETDATE()) AS EventTime,
141+
record
142+
FROM HadrRingBuffer
143+
WHERE DATEADD(ms, -1 * ($currentTimestamp - [timestamp]), GETDATE()) > DATEADD(MINUTE, -$CollectionMinutes, GETDATE())
144+
ORDER BY EventTime DESC;"
145+
146+
Write-Message -Level Verbose -Message "Executing SQL Statement: $sql"
147+
foreach ($row in $server.Query($sql)) {
148+
[PSCustomObject]@{
149+
ComputerName = $server.ComputerName
150+
InstanceName = $server.ServiceName
151+
SqlInstance = $server.DomainInstanceName
152+
RingBufferType = $row.ring_buffer_type
153+
RecordId = $row.record_id
154+
EventTime = $row.EventTime
155+
Record = $row.record
156+
}
155157
}
158+
} catch {
159+
Stop-Function -Message "Failed to query HADR ring buffer data." -Category InvalidOperation -ErrorRecord $_ -Target $instance -Continue
156160
}
157161
}
158162
}
159-
}
163+
}

tests/Get-DbaAgRingBuffer.Tests.ps1

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#Requires -Module @{ ModuleName="Pester"; ModuleVersion="5.0" }
22
param(
3-
$ModuleName = "dbatools",
3+
$ModuleName = "dbatools",
44
$CommandName = "Get-DbaAgRingBuffer",
55
$PSDefaultParameterValues = $TestConfig.Defaults
66
)
@@ -20,6 +20,75 @@ Describe $CommandName -Tag UnitTests {
2020
Compare-Object -ReferenceObject $expectedParameters -DifferenceObject $hasParameters | Should -BeNullOrEmpty
2121
}
2222
}
23+
24+
InModuleScope dbatools {
25+
Context "Query handling" {
26+
BeforeAll {
27+
$script:lastQuery = $null
28+
$script:throwRingBufferQuery = $false
29+
30+
$script:mockTimestampTable = New-Object System.Data.DataTable
31+
$null = $script:mockTimestampTable.Columns.Add("TimeStamp", [double])
32+
$timestampRow = $script:mockTimestampTable.NewRow()
33+
$timestampRow.TimeStamp = 123456
34+
$script:mockTimestampTable.Rows.Add($timestampRow)
35+
36+
$script:mockServer = [PSCustomObject]@{
37+
ComputerName = "sql1"
38+
ServiceName = "MSSQLSERVER"
39+
DomainInstanceName = "sql1"
40+
}
41+
42+
$script:mockServer | Add-Member -Force -MemberType ScriptMethod -Name Query -Value {
43+
param($Sql)
44+
45+
if ($Sql -like "*sys.dm_os_sys_info*") {
46+
$script:mockTimestampTable
47+
} elseif ($script:throwRingBufferQuery) {
48+
throw "ring buffer query failed"
49+
} else {
50+
$script:lastQuery = $Sql
51+
@()
52+
}
53+
}
54+
}
55+
56+
BeforeEach {
57+
$script:lastQuery = $null
58+
$script:throwRingBufferQuery = $false
59+
}
60+
61+
It "uses the scalar timestamp value when building the HADR ring buffer query" {
62+
Mock Connect-DbaInstance {
63+
$script:mockServer
64+
}
65+
66+
$null = Get-DbaAgRingBuffer -SqlInstance "sql1"
67+
68+
$script:lastQuery | Should -Match "DATEADD\(ms, -1 \* \(123456 - \[timestamp\]\), GETDATE\(\)\)"
69+
$script:lastQuery | Should -Not -Match "System\.Data\.DataRow"
70+
}
71+
72+
It "routes HADR ring buffer query failures through Stop-Function" {
73+
Mock Connect-DbaInstance {
74+
$script:mockServer
75+
}
76+
Mock Stop-Function {
77+
param(
78+
$Message,
79+
$Target,
80+
$ErrorRecord
81+
)
82+
83+
throw "$Message | inner: $($ErrorRecord.Exception.Message) | target: $Target"
84+
}
85+
86+
$script:throwRingBufferQuery = $true
87+
88+
{ Get-DbaAgRingBuffer -SqlInstance "sql1" } | Should -Throw "*Failed to query HADR ring buffer data.*ring buffer query failed*target: sql1*"
89+
}
90+
}
91+
}
2392
}
2493

2594
Describe $CommandName -Tag IntegrationTests {
@@ -44,4 +113,4 @@ Describe $CommandName -Tag IntegrationTests {
44113
}
45114
}
46115
}
47-
}
116+
}

0 commit comments

Comments
 (0)