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.LogsEntries;
using Moonlight.App.Database.Entities.Notification;
using Moonlight.App.Database.Interceptors;
using Moonlight.App.Models.Misc;
using Moonlight.App.Services;
@ -65,6 +66,9 @@ public class DataContext : DbContext
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;
public bool DebugMode { get; private set; } = false;
public bool SqlDebugMode { get; private set; } = false;
public ConfigService(StorageService storageService)
{
@ -28,6 +29,14 @@ public class ConfigService : IConfiguration
if (DebugMode)
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()

View file

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

View file

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

View file

@ -17,12 +17,15 @@
"applicationUrl": "http://moonlight.testy:5118;https://localhost:7118;http://localhost:5118",
"dotnetRunMessages": true
},
"IIS Express": {
"commandName": "IISExpress",
"Sql Debug": {
"commandName": "Project",
"launchBrowser": true,
"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": {
"commandName": "Docker",

View file

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