Fix database debugging tools

This commit is contained in:
Stephan
2018-05-30 16:40:25 +02:00
parent 632e401d33
commit 825f785a2b
4 changed files with 65 additions and 62 deletions

View File

@@ -3,9 +3,11 @@ using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlServerCe;
using System.Linq;
using System.Reflection;
using System.Text;
using Umbraco.Core.Persistence.FaultHandling;
namespace Umbraco.Core.Persistence
{
@@ -29,11 +31,7 @@ namespace Umbraco.Core.Persistence
{
lock (Commands)
{
var tuple = Commands.FirstOrDefault(x =>
{
IDbCommand c;
return x.Item2.TryGetTarget(out c) && c == command;
});
var tuple = Commands.FirstOrDefault(x => x.Item2.TryGetTarget(out var c) && c == command);
return tuple == null ? "?" : tuple.Item1;
}
}
@@ -42,28 +40,30 @@ namespace Umbraco.Core.Persistence
{
con = con.UnwrapUmbraco();
var ceCon = con as System.Data.SqlServerCe.SqlCeConnection;
if (ceCon != null) return null; // "NotSupported: SqlCE";
if (con is SqlCeConnection) return null; // "NotSupported: SqlCE";
var dbCon = con as DbConnection;
return dbCon == null
? "NotSupported: " + con.GetType()
: GetReferencedObjects(dbCon);
return con is DbConnection dbCon
? GetReferencedObjects(dbCon)
: "NotSupported: " + con.GetType();
}
public static string GetReferencedObjects(DbConnection con)
{
var t = con.GetType();
if (con.UnwrapUmbraco() is DbConnection ucon && !(ucon is SqlCeConnection))
con = ucon;
else
return "NotSupported: " + con.GetType();
var t = con.GetType();
var field = t.GetField("_innerConnection", BindingFlags.Instance | BindingFlags.NonPublic);
if (field == null) throw new Exception("panic: _innerConnection (" + t + ").");
var innerConnection = field.GetValue(con);
var tin = innerConnection.GetType();
var tin = innerConnection.GetType();
var fi = con is System.Data.SqlClient.SqlConnection
? tin.BaseType.BaseType.GetField("_referenceCollection", BindingFlags.Instance | BindingFlags.NonPublic)
: tin.BaseType.GetField("_referenceCollection", BindingFlags.Instance | BindingFlags.NonPublic);
? tin.BaseType?.BaseType?.GetField("_referenceCollection", BindingFlags.Instance | BindingFlags.NonPublic)
: tin.BaseType?.GetField("_referenceCollection", BindingFlags.Instance | BindingFlags.NonPublic);
if (fi == null)
//return "";
throw new Exception("panic: referenceCollection.");
@@ -73,7 +73,7 @@ namespace Umbraco.Core.Persistence
//return "";
throw new Exception("panic: innerCollection.");
field = rc.GetType().BaseType.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic);
field = rc.GetType().BaseType?.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic);
if (field == null) throw new Exception("panic: items.");
var items = field.GetValue(rc);
var prop = items.GetType().GetProperty("Length", BindingFlags.Instance | BindingFlags.Public);
@@ -116,21 +116,26 @@ namespace Umbraco.Core.Persistence
i, inUse, objTarget.GetType(), objTarget.GetHashCode());
DbCommand cmd = null;
if (objTarget is DbDataReader)
switch (objTarget)
{
//var rdr = objTarget as DbDataReader;
try
{
cmd = objTarget.GetType().GetProperty("Command", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(objTarget, null) as DbCommand;
}
catch (Exception e)
{
result.AppendFormat("\t\tObjTarget: DbDataReader, Exception: {0}" + Environment.NewLine, e);
}
}
else if (objTarget is DbCommand)
{
cmd = objTarget as DbCommand;
case DbDataReader _:
//var rdr = objTarget as DbDataReader;
try
{
var commandProp = objTarget.GetType().GetProperty("Command", BindingFlags.Instance | BindingFlags.NonPublic);
if (commandProp == null)
throw new Exception($"panic: failed to get Command property of {objTarget.GetType().FullName}.");
cmd = commandProp.GetValue(objTarget, null) as DbCommand;
}
catch (Exception e)
{
result.AppendFormat("\t\tObjTarget: DbDataReader, Exception: {0}" + Environment.NewLine, e);
}
break;
case DbCommand command:
cmd = command;
break;
}
if (cmd == null)
{
@@ -152,7 +157,9 @@ namespace Umbraco.Core.Persistence
if (pi.PropertyType != typeof (DbConnection) || pi.Name != "Connection") continue;
var con1 = pi.GetValue(cmd, null) as DbConnection;
var con0 = pi.GetValue(cmd, null);
if (!(con0 is DbConnection con1))
throw new Exception($"panic: expected DbConnection, got {con0?.GetType().FullName ?? "null"}.");
result.AppendFormat("\t\t\tConnection type=\"{0}\" state=\"{1}\" hashCode=\"{2}\"" + Environment.NewLine,
con1.GetType(), con1.State, con1.GetHashCode());

View File

@@ -5,6 +5,7 @@ using System.Data.SqlClient;
using System.Data.SqlServerCe;
using System.Linq;
using MySql.Data.MySqlClient;
using StackExchange.Profiling.Data;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.FaultHandling;
@@ -78,18 +79,13 @@ namespace Umbraco.Core.Persistence
/// OnConnectionOpened); this unwraps and returns the original database connection.</remarks>
internal static IDbConnection UnwrapUmbraco(this IDbConnection connection)
{
IDbConnection unwrapped;
var c = connection;
var unwrapped = connection;
IDbConnection c;
do
{
unwrapped = c;
var profiled = unwrapped as StackExchange.Profiling.Data.ProfiledDbConnection;
if (profiled != null) unwrapped = profiled.InnerConnection;
var retrying = unwrapped as RetryDbConnection;
if (retrying != null) unwrapped = retrying.Inner;
c = unwrapped;
if (unwrapped is ProfiledDbConnection profiled) unwrapped = profiled.InnerConnection;
if (unwrapped is RetryDbConnection retrying) unwrapped = retrying.Inner;
} while (c != unwrapped);
@@ -100,22 +96,23 @@ namespace Umbraco.Core.Persistence
{
try
{
if (connection is SqlConnection)
switch (connection)
{
var builder = new SqlConnectionStringBuilder(connection.ConnectionString);
return $"DataSource: {builder.DataSource}, InitialCatalog: {builder.InitialCatalog}";
}
if (connection is SqlCeConnection)
{
var builder = new SqlCeConnectionStringBuilder(connection.ConnectionString);
return $"DataSource: {builder.DataSource}";
}
if (connection is MySqlConnection)
{
var builder = new MySqlConnectionStringBuilder(connection.ConnectionString);
return $"Server: {builder.Server}, Database: {builder.Database}";
case SqlConnection _:
{
var builder = new SqlConnectionStringBuilder(connection.ConnectionString);
return $"DataSource: {builder.DataSource}, InitialCatalog: {builder.InitialCatalog}";
}
case SqlCeConnection _:
{
var builder = new SqlCeConnectionStringBuilder(connection.ConnectionString);
return $"DataSource: {builder.DataSource}";
}
case MySqlConnection _:
{
var builder = new MySqlConnectionStringBuilder(connection.ConnectionString);
return $"Server: {builder.Server}, Database: {builder.Database}";
}
}
}
catch (Exception ex)

View File

@@ -177,8 +177,7 @@ namespace Umbraco.Core.Persistence.FaultHandling
set
{
if (value == null) throw new ArgumentNullException(nameof(value));
var connection = value as RetryDbConnection;
if (connection == null) throw new ArgumentException("Value is not a FaultHandlingDbConnection instance.");
if (!(value is RetryDbConnection connection)) throw new ArgumentException("Value is not a FaultHandlingDbConnection instance.");
if (_connection != null && _connection != connection) throw new Exception("Value is another FaultHandlingDbConnection instance.");
_connection = connection;
_inner.Connection = connection.Inner;

View File

@@ -149,7 +149,7 @@ namespace Umbraco.Core.Persistence
#if DEBUG_DATABASES
// determines the database connection SPID for debugging
if (DatabaseType == DBType.MySql)
if (DatabaseType.IsMySql())
{
using (var command = connection.CreateCommand())
{
@@ -157,7 +157,7 @@ namespace Umbraco.Core.Persistence
_spid = Convert.ToInt32(command.ExecuteScalar());
}
}
else if (DatabaseType == DBType.SqlServer)
else if (DatabaseType.IsSqlServer())
{
using (var command = connection.CreateCommand())
{
@@ -183,7 +183,7 @@ namespace Umbraco.Core.Persistence
}
#if DEBUG_DATABASES
public override void OnConnectionClosing(IDbConnection conn)
protected override void OnConnectionClosing(DbConnection conn)
{
_spid = -1;
base.OnConnectionClosing(conn);
@@ -212,7 +212,7 @@ namespace Umbraco.Core.Persistence
#if DEBUG_DATABASES
// detects whether the command is already in use (eg still has an open reader...)
DatabaseDebugHelper.SetCommand(cmd, InstanceId + " [T" + Thread.CurrentThread.ManagedThreadId + "]");
DatabaseDebugHelper.SetCommand(cmd, InstanceId + " [T" + System.Threading.Thread.CurrentThread.ManagedThreadId + "]");
var refsobj = DatabaseDebugHelper.GetReferencedObjects(cmd.Connection);
if (refsobj != null) _logger.Debug<UmbracoDatabase>("Oops!" + Environment.NewLine + refsobj);
#endif