Browse Source

Add temp fallback for locked database file

pull/109/head
Ionite 1 year ago
parent
commit
64041a43ec
No known key found for this signature in database
  1. 91
      StabilityMatrix.Core/Database/LiteDbContext.cs

91
StabilityMatrix.Core/Database/LiteDbContext.cs

@ -1,4 +1,6 @@
using LiteDB.Async; using LiteDB;
using LiteDB.Async;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Extensions;
using StabilityMatrix.Core.Models.Api; using StabilityMatrix.Core.Models.Api;
@ -10,27 +12,12 @@ namespace StabilityMatrix.Core.Database;
public class LiteDbContext : ILiteDbContext public class LiteDbContext : ILiteDbContext
{ {
private readonly ILogger<LiteDbContext> logger;
private readonly ISettingsManager settingsManager; private readonly ISettingsManager settingsManager;
private readonly DebugOptions debugOptions; private readonly DebugOptions debugOptions;
private LiteDatabaseAsync? database; private LiteDatabaseAsync? database;
public LiteDatabaseAsync Database public LiteDatabaseAsync Database => database ??= CreateDatabase();
{
get
{
if (database != null) return database;
var connectionString = debugOptions.TempDatabase ? ":temp:"
: $"Filename={Path.Combine(settingsManager.LibraryDir, "StabilityMatrix.db")};Mode=Shared";
database = new LiteDatabaseAsync(connectionString);
// Register reference fields
LiteDBExtensions.Register<CivitModel, CivitModelVersion>(m => m.ModelVersions, "CivitModelVersions");
LiteDBExtensions.Register<CivitModelQueryCacheEntry, CivitModel>(e => e.Items, "CivitModels");
return database;
}
}
// Notification events // Notification events
public event EventHandler? CivitModelsChanged; public event EventHandler? CivitModelsChanged;
@ -41,12 +28,50 @@ public class LiteDbContext : ILiteDbContext
public ILiteCollectionAsync<CivitModelQueryCacheEntry> CivitModelQueryCache => Database.GetCollection<CivitModelQueryCacheEntry>("CivitModelQueryCache"); public ILiteCollectionAsync<CivitModelQueryCacheEntry> CivitModelQueryCache => Database.GetCollection<CivitModelQueryCacheEntry>("CivitModelQueryCache");
public ILiteCollectionAsync<GithubCacheEntry> GithubCache => Database.GetCollection<GithubCacheEntry>("GithubCache"); public ILiteCollectionAsync<GithubCacheEntry> GithubCache => Database.GetCollection<GithubCacheEntry>("GithubCache");
public LiteDbContext(ISettingsManager settingsManager, IOptions<DebugOptions> debugOptions) public LiteDbContext(
ILogger<LiteDbContext> logger,
ISettingsManager settingsManager,
IOptions<DebugOptions> debugOptions)
{ {
this.logger = logger;
this.settingsManager = settingsManager; this.settingsManager = settingsManager;
this.debugOptions = debugOptions.Value; this.debugOptions = debugOptions.Value;
} }
private LiteDatabaseAsync CreateDatabase()
{
LiteDatabaseAsync? db = null;
if (debugOptions.TempDatabase)
{
db = new LiteDatabaseAsync(":temp:");
}
// Attempt to create connection, might be in use
try
{
var dbPath = Path.Combine(settingsManager.LibraryDir, "StabilityMatrix.db");
db = new LiteDatabaseAsync(new ConnectionString()
{
Filename = dbPath,
Connection = ConnectionType.Shared,
});
}
catch (IOException e)
{
logger.LogWarning("Database in use or not accessible ({Message}), using temporary database", e.Message);
}
// Fallback to temporary database
db ??= new LiteDatabaseAsync(":temp:");
// Register reference fields
LiteDBExtensions.Register<CivitModel, CivitModelVersion>(m => m.ModelVersions, "CivitModelVersions");
LiteDBExtensions.Register<CivitModelQueryCacheEntry, CivitModel>(e => e.Items, "CivitModels");
return db;
}
public async Task<(CivitModel?, CivitModelVersion?)> FindCivitModelFromFileHashAsync(string hashBlake3) public async Task<(CivitModel?, CivitModelVersion?)> FindCivitModelFromFileHashAsync(string hashBlake3)
{ {
var version = await CivitModelVersions.Query() var version = await CivitModelVersions.Query()
@ -54,22 +79,26 @@ public class LiteDbContext : ILiteDbContext
.Select(f => f.Hashes) .Select(f => f.Hashes)
.Select(hashes => hashes.BLAKE3) .Select(hashes => hashes.BLAKE3)
.Any(hash => hash == hashBlake3)) .Any(hash => hash == hashBlake3))
.FirstOrDefaultAsync(); .FirstOrDefaultAsync()
.ConfigureAwait(false);
if (version is null) return (null, null); if (version is null) return (null, null);
var model = await CivitModels.Query() var model = await CivitModels.Query()
.Include(m => m.ModelVersions) .Include(m => m.ModelVersions)
.Where(m => m.ModelVersions! .Where(m => m.ModelVersions!
.Select(v => v.Id) .Select(v => v.Id)
.Any(id => id == version.Id)) .Any(id => id == version.Id))
.FirstOrDefaultAsync(); .FirstOrDefaultAsync().ConfigureAwait(false);
return (model, version); return (model, version);
} }
public async Task<bool> UpsertCivitModelAsync(CivitModel civitModel) public async Task<bool> UpsertCivitModelAsync(CivitModel civitModel)
{ {
// Insert model versions first then model // Insert model versions first then model
var versionsUpdated = await CivitModelVersions.UpsertAsync(civitModel.ModelVersions); var versionsUpdated = await CivitModelVersions.UpsertAsync(civitModel.ModelVersions).ConfigureAwait(false);
var updated = await CivitModels.UpsertAsync(civitModel); var updated = await CivitModels.UpsertAsync(civitModel).ConfigureAwait(false);
// Notify listeners on any change // Notify listeners on any change
var anyUpdated = versionsUpdated > 0 || updated; var anyUpdated = versionsUpdated > 0 || updated;
if (anyUpdated) if (anyUpdated)
@ -84,8 +113,8 @@ public class LiteDbContext : ILiteDbContext
var civitModelsArray = civitModels.ToArray(); var civitModelsArray = civitModels.ToArray();
// Get all model versions then insert models // Get all model versions then insert models
var versions = civitModelsArray.SelectMany(model => model.ModelVersions ?? new()); var versions = civitModelsArray.SelectMany(model => model.ModelVersions ?? new());
var versionsUpdated = await CivitModelVersions.UpsertAsync(versions); var versionsUpdated = await CivitModelVersions.UpsertAsync(versions).ConfigureAwait(false);
var updated = await CivitModels.UpsertAsync(civitModelsArray); var updated = await CivitModels.UpsertAsync(civitModelsArray).ConfigureAwait(false);
// Notify listeners on any change // Notify listeners on any change
var anyUpdated = versionsUpdated > 0 || updated > 0; var anyUpdated = versionsUpdated > 0 || updated > 0;
if (updated > 0 || versionsUpdated > 0) if (updated > 0 || versionsUpdated > 0)
@ -98,7 +127,7 @@ public class LiteDbContext : ILiteDbContext
// Add to cache // Add to cache
public async Task<bool> UpsertCivitModelQueryCacheEntryAsync(CivitModelQueryCacheEntry entry) public async Task<bool> UpsertCivitModelQueryCacheEntryAsync(CivitModelQueryCacheEntry entry)
{ {
var changed = await CivitModelQueryCache.UpsertAsync(entry); var changed = await CivitModelQueryCache.UpsertAsync(entry).ConfigureAwait(false);
if (changed) if (changed)
{ {
CivitModelsChanged?.Invoke(this, EventArgs.Empty); CivitModelsChanged?.Invoke(this, EventArgs.Empty);
@ -107,8 +136,14 @@ public class LiteDbContext : ILiteDbContext
return changed; return changed;
} }
public Task<GithubCacheEntry?> GetGithubCacheEntry(string cacheKey) => public async Task<GithubCacheEntry?> GetGithubCacheEntry(string cacheKey)
GithubCache.FindByIdAsync(cacheKey); {
if (await GithubCache.FindByIdAsync(cacheKey).ConfigureAwait(false) is { } result)
{
return result;
}
return null;
}
public Task<bool> UpsertGithubCacheEntry(GithubCacheEntry cacheEntry) => public Task<bool> UpsertGithubCacheEntry(GithubCacheEntry cacheEntry) =>
GithubCache.UpsertAsync(cacheEntry); GithubCache.UpsertAsync(cacheEntry);

Loading…
Cancel
Save