Merge pull request #76 from Moonlight-Panel/SqlLoggingAndOptimisations

Optimized allocation search. Added sql command log interception
This commit is contained in:
Marcel Baumgartner 2023-04-16 02:46:38 +02:00 committed by GitHub
commit 7921e9a525
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 103 additions and 29 deletions

View file

@ -2,6 +2,7 @@
using Moonlight.App.Database.Entities; using Moonlight.App.Database.Entities;
using Moonlight.App.Database.Entities.LogsEntries; using Moonlight.App.Database.Entities.LogsEntries;
using Moonlight.App.Database.Entities.Notification; using Moonlight.App.Database.Entities.Notification;
using Moonlight.App.Database.Interceptors;
using Moonlight.App.Models.Misc; using Moonlight.App.Models.Misc;
using Moonlight.App.Services; using Moonlight.App.Services;
@ -65,6 +66,9 @@ public class DataContext : DbContext
builder.EnableRetryOnFailure(5); builder.EnableRetryOnFailure(5);
} }
); );
if(ConfigService.SqlDebugMode)
optionsBuilder.AddInterceptors(new SqlLoggingInterceptor());
} }
} }
} }

View file

@ -0,0 +1,40 @@
using System.Data.Common;
using Logging.Net;
using Microsoft.EntityFrameworkCore.Diagnostics;
namespace Moonlight.App.Database.Interceptors;
public class SqlLoggingInterceptor : DbCommandInterceptor
{
public override InterceptionResult<DbDataReader> ReaderExecuting(
DbCommand command,
CommandEventData eventData,
InterceptionResult<DbDataReader> result)
{
LogSql(command.CommandText);
return base.ReaderExecuting(command, eventData, result);
}
public override InterceptionResult<object> ScalarExecuting(
DbCommand command,
CommandEventData eventData,
InterceptionResult<object> result)
{
LogSql(command.CommandText);
return base.ScalarExecuting(command, eventData, result);
}
public override InterceptionResult<int> NonQueryExecuting(
DbCommand command,
CommandEventData eventData,
InterceptionResult<int> result)
{
LogSql(command.CommandText);
return base.NonQueryExecuting(command, eventData, result);
}
private void LogSql(string sql)
{
Logger.Info($"[SQL DEBUG] {sql.Replace("\n", "")}");
}
}

View file

@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore;
using Moonlight.App.Database;
using Moonlight.App.Database.Entities;
namespace Moonlight.App.Repositories;
public class NodeAllocationRepository : IDisposable
{
// This repository is ONLY for the server creation service, so allocations can be found
// using raw sql. DO NOT use this in any other component
private readonly DataContext DataContext;
public NodeAllocationRepository(DataContext dataContext)
{
DataContext = dataContext;
}
public DbSet<NodeAllocation> Get()
{
return DataContext.NodeAllocations;
}
public void Dispose()
{
DataContext.Dispose();
}
}

View file

@ -12,6 +12,7 @@ public class ConfigService : IConfiguration
private IConfiguration Configuration; private IConfiguration Configuration;
public bool DebugMode { get; private set; } = false; public bool DebugMode { get; private set; } = false;
public bool SqlDebugMode { get; private set; } = false;
public ConfigService(StorageService storageService) public ConfigService(StorageService storageService)
{ {
@ -28,6 +29,14 @@ public class ConfigService : IConfiguration
if (DebugMode) if (DebugMode)
Logger.Debug("Debug mode enabled"); Logger.Debug("Debug mode enabled");
var sqlDebugVar = Environment.GetEnvironmentVariable("ML_SQL_DEBUG");
if (sqlDebugVar != null)
SqlDebugMode = bool.Parse(sqlDebugVar);
if (SqlDebugMode)
Logger.Debug("Sql debug mode enabled");
} }
public void Reload() public void Reload()

View file

@ -21,6 +21,7 @@ public class ServerService
private readonly UserRepository UserRepository; private readonly UserRepository UserRepository;
private readonly ImageRepository ImageRepository; private readonly ImageRepository ImageRepository;
private readonly NodeRepository NodeRepository; private readonly NodeRepository NodeRepository;
private readonly NodeAllocationRepository NodeAllocationRepository;
private readonly WingsApiHelper WingsApiHelper; private readonly WingsApiHelper WingsApiHelper;
private readonly MessageService MessageService; private readonly MessageService MessageService;
private readonly UserService UserService; private readonly UserService UserService;
@ -44,7 +45,8 @@ public class ServerService
SecurityLogService securityLogService, SecurityLogService securityLogService,
AuditLogService auditLogService, AuditLogService auditLogService,
ErrorLogService errorLogService, ErrorLogService errorLogService,
NodeService nodeService) NodeService nodeService,
NodeAllocationRepository nodeAllocationRepository)
{ {
ServerRepository = serverRepository; ServerRepository = serverRepository;
WingsApiHelper = wingsApiHelper; WingsApiHelper = wingsApiHelper;
@ -59,6 +61,7 @@ public class ServerService
AuditLogService = auditLogService; AuditLogService = auditLogService;
ErrorLogService = errorLogService; ErrorLogService = errorLogService;
NodeService = nodeService; NodeService = nodeService;
NodeAllocationRepository = nodeAllocationRepository;
} }
private Server EnsureNodeData(Server s) private Server EnsureNodeData(Server s)
@ -268,32 +271,19 @@ public class ServerService
.Include(x => x.DockerImages) .Include(x => x.DockerImages)
.First(x => x.Id == i.Id); .First(x => x.Id == i.Id);
Node node; Node node = n ?? NodeRepository.Get().First();
if (n == null)
{
node = NodeRepository
.Get()
.Include(x => x.Allocations)
.First(); //TODO: Add smart deploy maybe
}
else
{
node = NodeRepository
.Get()
.Include(x => x.Allocations)
.First(x => x.Id == n.Id);
}
NodeAllocation[] freeAllocations; NodeAllocation[] freeAllocations;
try try
{ {
freeAllocations = node.Allocations // We have sadly no choice to use entity framework to do what the sql call does, there
.Where(a => !ServerRepository.Get() // are only slower ways, so we will use a raw sql call as a exception
.SelectMany(s => s.Allocations)
.Any(b => b.Id == a.Id)) freeAllocations = NodeAllocationRepository
.Take(allocations).ToArray(); .Get()
.FromSqlRaw($"SELECT * FROM `NodeAllocations` WHERE ServerId IS NULL AND NodeId={node.Id} LIMIT {allocations}")
.ToArray();
} }
catch (Exception) catch (Exception)
{ {

View file

@ -89,7 +89,7 @@ public class SubscriptionService
} }
} }
public async Task<SubscriptionLimit> GetLimit(string identifier) public async Task<SubscriptionLimit> GetLimit(string identifier) // Cache, optimize sql code
{ {
var subscription = await GetCurrent(); var subscription = await GetCurrent();
var defaultLimits = await GetDefaultLimits(); var defaultLimits = await GetDefaultLimits();

View file

@ -71,9 +71,8 @@ namespace Moonlight
builder.Services.AddScoped<WebsiteRepository>(); builder.Services.AddScoped<WebsiteRepository>();
builder.Services.AddScoped<LoadingMessageRepository>(); builder.Services.AddScoped<LoadingMessageRepository>();
builder.Services.AddScoped<NewsEntryRepository>(); builder.Services.AddScoped<NewsEntryRepository>();
builder.Services.AddScoped<NodeAllocationRepository>();
builder.Services.AddScoped<StatisticsRepository>(); builder.Services.AddScoped<StatisticsRepository>();
builder.Services.AddScoped<AuditLogEntryRepository>(); builder.Services.AddScoped<AuditLogEntryRepository>();
builder.Services.AddScoped<ErrorLogEntryRepository>(); builder.Services.AddScoped<ErrorLogEntryRepository>();
builder.Services.AddScoped<SecurityLogEntryRepository>(); builder.Services.AddScoped<SecurityLogEntryRepository>();

View file

@ -17,12 +17,15 @@
"applicationUrl": "http://moonlight.testy:5118;https://localhost:7118;http://localhost:5118", "applicationUrl": "http://moonlight.testy:5118;https://localhost:7118;http://localhost:5118",
"dotnetRunMessages": true "dotnetRunMessages": true
}, },
"IIS Express": { "Sql Debug": {
"commandName": "IISExpress", "commandName": "Project",
"launchBrowser": true, "launchBrowser": true,
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development",
} "ML_SQL_DEBUG": "true"
},
"applicationUrl": "http://moonlight.testy:5118;https://localhost:7118;http://localhost:5118",
"dotnetRunMessages": true
}, },
"Docker": { "Docker": {
"commandName": "Docker", "commandName": "Docker",

View file

@ -103,6 +103,7 @@
.Include(x => x.Node) .Include(x => x.Node)
.Include(x => x.Image) .Include(x => x.Image)
.Where(x => x.Owner.Id == User.Id) .Where(x => x.Owner.Id == User.Id)
.OrderBy(x => x.Name)
.ToArray(); .ToArray();
foreach (var server in AllServers) foreach (var server in AllServers)