|
@@ -0,0 +1,121 @@
|
|
|
+using Dapper;
|
|
|
+using EVCB_OCPP.Domain;
|
|
|
+using EVCB_OCPP.WSServer.Helper;
|
|
|
+using Microsoft.Data.SqlClient;
|
|
|
+using Microsoft.Extensions.Logging;
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.ComponentModel.DataAnnotations.Schema;
|
|
|
+using System.Linq;
|
|
|
+using System.Text;
|
|
|
+using System.Threading.Tasks;
|
|
|
+
|
|
|
+namespace EVCB_OCPP.WSServer.Service
|
|
|
+{
|
|
|
+ public class BlockingTreePrintService
|
|
|
+ {
|
|
|
+ public BlockingTreePrintService(ILogger<BlockingTreePrintService> logger,
|
|
|
+ SqlConnectionFactory<MainDBContext> connectionFactory)
|
|
|
+ {
|
|
|
+ this.logger = logger;
|
|
|
+ this.connectionFactory = connectionFactory;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task PrintDbBlockingTree()
|
|
|
+ {
|
|
|
+ using var connection = await connectionFactory.CreateAsync();
|
|
|
+ var tree = await connection.QueryAsync<TreeStruct>(Command);
|
|
|
+
|
|
|
+ logger.LogCritical("Printing BlockingTree");
|
|
|
+ foreach (var data in tree)
|
|
|
+ {
|
|
|
+ logger.LogCritical($"{data.BlockingTree} {data.Type} {data.LoginName} {data.SourceDatabase} {data.SQLText} {data.CursorSQLText} {data.Database} {data.Schema} {data.Table} {data.WaitResource} {data.Command} {data.Application} {data.HostName} {data.LastBatchTime} ");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private const string Command = """
|
|
|
+ /* SQL Blocking Tree w/Cursor info
|
|
|
+ Thanks SQL Server Expert JOHNNYBNO
|
|
|
+ */
|
|
|
+ IF OBJECT_ID('tempdb..#Blocks') IS NOT NULL
|
|
|
+ DROP TABLE #Blocks
|
|
|
+ SELECT spid
|
|
|
+ ,blocked
|
|
|
+ ,REPLACE (REPLACE (st.TEXT, CHAR(10), ' '), CHAR (13), ' ' ) AS batch
|
|
|
+ INTO #Blocks
|
|
|
+ FROM sys.sysprocesses spr
|
|
|
+ CROSS APPLY sys.dm_exec_sql_text(spr.SQL_HANDLE) st;
|
|
|
+
|
|
|
+ WITH BlockingTree (spid, blocking_spid, [level], batch)
|
|
|
+ AS
|
|
|
+ (
|
|
|
+ SELECT blc.spid
|
|
|
+ ,blc.blocked
|
|
|
+ ,CAST (REPLICATE ('0', 4-LEN (CAST (blc.spid AS VARCHAR))) + CAST (blc.spid AS VARCHAR) AS VARCHAR (1000)) AS [level]
|
|
|
+ ,blc.batch
|
|
|
+ FROM #Blocks blc
|
|
|
+ WHERE (blc.blocked = 0 OR blc.blocked = SPID) AND
|
|
|
+ EXISTS (SELECT * FROM #Blocks blc2 WHERE blc2.BLOCKED = blc.SPID AND blc2.BLOCKED <> blc2.SPID)
|
|
|
+ UNION ALL
|
|
|
+ SELECT blc.spid
|
|
|
+ ,blc.blocked
|
|
|
+ ,CAST(bt.[level] + RIGHT (CAST ((1000 + blc.SPID) AS VARCHAR (100)), 4) AS VARCHAR (1000)) AS [level]
|
|
|
+ ,blc.batch
|
|
|
+ FROM #Blocks AS blc
|
|
|
+ INNER JOIN BlockingTree bt
|
|
|
+ ON blc.blocked = bt.SPID
|
|
|
+ WHERE blc.blocked > 0 AND
|
|
|
+ blc.blocked <> blc.SPID
|
|
|
+ )
|
|
|
+ SELECT N'' + ISNULL(REPLICATE (N'| ', LEN (LEVEL)/4 - 2),'')
|
|
|
+ + CASE WHEN (LEN(LEVEL)/4 - 1) = 0 THEN '' ELSE '|------ ' END
|
|
|
+ + CAST (bt.SPID AS NVARCHAR (10)) AS BlockingTree
|
|
|
+ ,spr.lastwaittype AS [Type]
|
|
|
+ ,spr.loginame AS [LoginName]
|
|
|
+ ,DB_NAME(spr.dbid) AS [SourceDatabase]
|
|
|
+ ,st.text AS [SQLText]
|
|
|
+ ,CASE WHEN cur.sql_handle IS NULL THEN '' ELSE (SELECT [TEXT] FROM sys.dm_exec_sql_text (cur.sql_handle)) END AS [CursorSQLText]
|
|
|
+ ,DB_NAME(sli.rsc_dbid) AS [Database]
|
|
|
+ ,OBJECT_SCHEMA_NAME(sli.rsc_objid,sli.rsc_dbid) AS [Schema]
|
|
|
+ ,OBJECT_NAME(sli.rsc_objid, sli.rsc_dbid) AS [Table]
|
|
|
+ ,spr.waitresource AS [WaitResource]
|
|
|
+ ,spr.cmd AS [Command]
|
|
|
+ ,spr.program_name AS [Application]
|
|
|
+ ,spr.hostname AS [HostName]
|
|
|
+ ,spr.last_batch AS [Last Batch Time]
|
|
|
+ FROM BlockingTree bt
|
|
|
+ LEFT OUTER JOIN sys.sysprocesses spr
|
|
|
+ ON spr.spid = bt.spid
|
|
|
+ CROSS APPLY sys.dm_exec_sql_text(spr.SQL_HANDLE) st
|
|
|
+ LEFT JOIN sys.dm_exec_cursors(0) cur
|
|
|
+ ON cur.session_id = spr.spid AND
|
|
|
+ cur.fetch_status != 0
|
|
|
+ JOIN sys.syslockinfo sli
|
|
|
+ ON sli.req_spid = spr.spid AND
|
|
|
+ sli.rsc_type = 5 AND
|
|
|
+ OBJECT_NAME(sli.rsc_objid, sli.rsc_dbid) IS NOT NULL
|
|
|
+ ORDER BY LEVEL ASC
|
|
|
+ """;
|
|
|
+ private readonly ILogger<BlockingTreePrintService> logger;
|
|
|
+ private readonly SqlConnectionFactory<MainDBContext> connectionFactory;
|
|
|
+ }
|
|
|
+
|
|
|
+ public class TreeStruct
|
|
|
+ {
|
|
|
+ public string BlockingTree { get; set; }
|
|
|
+ public string Type { get; set; }
|
|
|
+ public string LoginName { get; set; }
|
|
|
+ public string SourceDatabase { get; set; }
|
|
|
+ public string SQLText { get; set; }
|
|
|
+ public string CursorSQLText { get; set; }
|
|
|
+ public string Database { get; set; }
|
|
|
+ public string Schema { get; set; }
|
|
|
+ public string Table { get; set; }
|
|
|
+ public string WaitResource { get; set; }
|
|
|
+ public string Command { get; set; }
|
|
|
+ public string Application { get; set; }
|
|
|
+ public string HostName { get; set; }
|
|
|
+ public string LastBatchTime { get; set; }
|
|
|
+
|
|
|
+ }
|
|
|
+}
|