Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions Lite/Controls/ServerTab.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@
}

var tz = ServerTimeHelper.GetTimezoneLabel(ServerTimeHelper.CurrentDisplayMode);
ConnectionStatusText.Text = $"{_server.ServerNameDisplay} - Last refresh: {DateTime.Now:HH:mm:ss} ({tz})";

Check warning on line 804 in Lite/Controls/ServerTab.xaml.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

Check warning on line 804 in Lite/Controls/ServerTab.xaml.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.
}
catch (Exception ex)
{
Expand Down Expand Up @@ -5243,6 +5243,37 @@
_refreshTimer.Stop();
}

public void DisposeChartHelpers()
{
_waitStatsHover?.Dispose();
_perfmonHover?.Dispose();
_overviewCpuHover?.Dispose();
_overviewMemoryHover?.Dispose();
_overviewFileIoHover?.Dispose();
_overviewWaitStatsHover?.Dispose();
_cpuHover?.Dispose();
_memoryHover?.Dispose();
_tempDbHover?.Dispose();
_tempDbFileIoHover?.Dispose();
_fileIoReadHover?.Dispose();
_fileIoWriteHover?.Dispose();
_fileIoReadThroughputHover?.Dispose();
_fileIoWriteThroughputHover?.Dispose();
_collectorDurationHover?.Dispose();
_queryDurationTrendHover?.Dispose();
_procDurationTrendHover?.Dispose();
_queryStoreDurationTrendHover?.Dispose();
_executionCountTrendHover?.Dispose();
_lockWaitTrendHover?.Dispose();
_blockingTrendHover?.Dispose();
_deadlockTrendHover?.Dispose();
_memoryClerksHover?.Dispose();
_memoryGrantSizingHover?.Dispose();
_memoryGrantActivityHover?.Dispose();
_currentWaitsDurationHover?.Dispose();
_currentWaitsBlockedHover?.Dispose();
}

/* ========== Column Filtering ========== */

private void InitializeFilterManagers()
Expand Down
8 changes: 8 additions & 0 deletions Lite/Helpers/ChartHoverHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ public ChartHoverHelper(ScottPlot.WPF.WpfPlot chart, string unit)

public string Unit { get => _unit; set => _unit = value; }

public void Dispose()
{
_chart.MouseMove -= OnMouseMove;
_chart.MouseLeave -= OnMouseLeave;
_popup.IsOpen = false;
_scatters.Clear();
}

public void Clear() => _scatters.Clear();

public void Add(ScottPlot.Plottables.Scatter scatter, string label) =>
Expand Down
31 changes: 23 additions & 8 deletions Lite/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public partial class MainWindow : Window
private CancellationTokenSource? _backgroundCts;
private SystemTrayService? _trayService;
private readonly Dictionary<string, TabItem> _openServerTabs = new();
private readonly Dictionary<string, (Action<int, int, DateTime?> AlertCounts, Action<int> ApplyTimeRange, Func<Task> ManualRefresh)> _tabEventHandlers = new();
private readonly Dictionary<string, bool> _previousConnectionStates = new();
private readonly Dictionary<string, bool> _previousCollectorErrorStates = new();
private readonly Dictionary<string, DateTime> _lastCpuAlert = new();
Expand Down Expand Up @@ -530,15 +531,13 @@ private async void ConnectToServer(ServerConnection server)
Content = serverTab
};

/* Subscribe to alert counts for badge updates */
/* Subscribe to events — store handlers so we can unsubscribe on tab close */
var serverId = server.Id;
serverTab.AlertCountsChanged += (blockingCount, deadlockCount, latestEventTime) =>
Action<int, int, DateTime?> alertHandler = (blockingCount, deadlockCount, latestEventTime) =>
{
Dispatcher.Invoke(() => UpdateTabBadge(tabHeader, serverId, blockingCount, deadlockCount, latestEventTime));
};

/* Subscribe to "Apply to All" time range propagation */
serverTab.ApplyTimeRangeRequested += (selectedIndex) =>
Action<int> timeRangeHandler = (selectedIndex) =>
{
Dispatcher.Invoke(() =>
{
Expand All @@ -551,9 +550,7 @@ private async void ConnectToServer(ServerConnection server)
}
});
};

/* Re-collect on-load data (config, trace flags) when refresh button is clicked */
serverTab.ManualRefreshRequested += async () =>
Func<Task> refreshHandler = async () =>
{
if (_collectorService != null)
{
Expand All @@ -572,6 +569,11 @@ private async void ConnectToServer(ServerConnection server)
}
};

serverTab.AlertCountsChanged += alertHandler;
serverTab.ApplyTimeRangeRequested += timeRangeHandler;
serverTab.ManualRefreshRequested += refreshHandler;
_tabEventHandlers[server.Id] = (alertHandler, timeRangeHandler, refreshHandler);

_openServerTabs[server.Id] = tabItem;
ServerTabControl.Items.Add(tabItem);
ServerTabControl.SelectedItem = tabItem;
Expand Down Expand Up @@ -793,7 +795,20 @@ private void CloseServerTab(string serverId)
{
if (tab.Content is ServerTab serverTab)
{
/* Unsubscribe event handlers to prevent memory leaks */
if (_tabEventHandlers.TryGetValue(serverId, out var handlers))
{
serverTab.AlertCountsChanged -= handlers.AlertCounts;
serverTab.ApplyTimeRangeRequested -= handlers.ApplyTimeRange;
serverTab.ManualRefreshRequested -= handlers.ManualRefresh;
_tabEventHandlers.Remove(serverId);
}

serverTab.StopRefresh();
serverTab.DisposeChartHelpers();

/* Clear delta cache for this server to free memory */
_collectorService?.DeltaCalculator?.ClearServer(serverTab.ServerId);
}

ServerTabControl.Items.Remove(tab);
Expand Down
9 changes: 9 additions & 0 deletions Lite/Services/DeltaCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ public async Task SeedFromDatabaseAsync(DuckDbInitializer duckDb)
}
}

/// <summary>
/// Removes all cached entries for a server (e.g., when the server tab is closed).
/// Next collection will re-seed from database if needed.
/// </summary>
public void ClearServer(int serverId)
{
_cache.TryRemove(serverId, out _);
}

/// <summary>
/// Calculates the delta between the current value and the previous cached value.
/// First-ever sighting (no baseline): returns currentValue so single-execution queries appear.
Expand Down
1 change: 1 addition & 0 deletions Lite/Services/RemoteCollectorService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public partial class RemoteCollectorService
private readonly ScheduleManager _scheduleManager;
private readonly ILogger<RemoteCollectorService>? _logger;
private readonly DeltaCalculator _deltaCalculator;
public DeltaCalculator DeltaCalculator => _deltaCalculator;
private static long s_idCounter = DateTime.UtcNow.Ticks;

/// <summary>
Expand Down
Loading