fixes concurrency issues on get or add album
All checks were successful
PiwigoDirectorySync/pipeline/head This commit looks good

This commit is contained in:
Philipp Häfelfinger 2023-09-12 00:17:21 +02:00
parent f111df487d
commit 3b8dad1af2
2 changed files with 37 additions and 21 deletions

View File

@ -25,6 +25,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0"/>
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="7.0.0" />
<PackageReference Include="Piwigo.Client" Version="0.1.0.19" />
<PackageReference Include="Polly" Version="7.2.4" />
<PackageReference Include="Serilog" Version="3.0.1" />
<PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />

View File

@ -1,9 +1,11 @@
using System.Collections.Concurrent;
using System.Data;
using System.Threading.Channels;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using PiwigoDirectorySync.Infrastructure;
using PiwigoDirectorySync.Persistence;
using Polly;
using Serilog;
namespace PiwigoDirectorySync.Services;
@ -62,7 +64,7 @@ internal class FileIndexer : IFileIndexer
var relativePath = Path.GetRelativePath(piwigoServer.RootDirectory, fullFilePath);
var album = await GetOrAddAlbumAsync(db, piwigoServer, fileInfo.Directory!, ct);
var album = await GetOrAddAlbumAsync(piwigoServerId, fileInfo.Directory!, ct);
var image = await GetOrAddImageAsync(db, album, relativePath, ct);
@ -86,15 +88,14 @@ internal class FileIndexer : IFileIndexer
}
}
private static async Task<ImageEntity> GetOrAddImageAsync(PersistenceContext db, AlbumEntity album, string relativePath, CancellationToken ct)
private static async Task<ImageEntity> GetOrAddImageAsync(PersistenceContext db, int albumId, string relativePath, CancellationToken ct)
{
var imageEntity = await db.PiwigoImages.Where(i => i.AlbumId == album.Id && i.FilePath == relativePath).FirstOrDefaultAsync(ct);
var imageEntity = await db.PiwigoImages.Where(i => i.AlbumId == albumId && i.FilePath == relativePath).FirstOrDefaultAsync(ct);
if (imageEntity is null)
{
imageEntity = new ImageEntity
{
AlbumId = album.Id,
Album = album,
AlbumId = albumId,
FilePath = relativePath,
UploadRequired = true,
DeleteRequired = false
@ -105,38 +106,52 @@ internal class FileIndexer : IFileIndexer
return imageEntity;
}
private static async Task<AlbumEntity> GetOrAddAlbumAsync(PersistenceContext db, ServerEntity server, DirectoryInfo directory, CancellationToken ct)
private async Task<int> GetOrAddAlbumAsync(int serverId, DirectoryInfo directory, CancellationToken ct)
{
var albumPath = Path.GetRelativePath(server.RootDirectory, directory.FullName);
var album = await db.PiwigoAlbums.FindByServerAndPathAsync(server.Id, albumPath, ct);
return await Policy.Handle<DbUpdateException>()
.RetryAsync(3, (ex, _) => { _logger.Warning(ex, "Could not create album for directory {AlbumDirectory}, retrying", directory); })
.ExecuteAsync(async () =>
{
await using var scope = _serviceProvider.CreateAsyncScope();
await using var db = scope.ServiceProvider.GetRequiredService<PersistenceContext>();
await using var tx = await db.Database.BeginTransactionAsync(IsolationLevel.Serializable, ct);
var piwigoServer = await db.PiwigoServers.GetByIdAsync(serverId, ct);
_logger.Information("Get or crate album for directory {AlbumDirectory}", directory);
var albumId = await GetOrAddAlbumAsync(db, serverId, piwigoServer.RootDirectory, directory, ct);
await tx.CommitAsync(ct);
return albumId;
});
}
private static async Task<int> GetOrAddAlbumAsync(PersistenceContext db, int serverId, string rootDirectory, DirectoryInfo directory, CancellationToken ct)
{
var albumPath = Path.GetRelativePath(rootDirectory, directory.FullName);
var album = await db.PiwigoAlbums.FindByServerAndPathAsync(serverId, albumPath, ct);
if (album != null)
{
return album;
return album.Id;
}
AlbumEntity? parentAlbum;
if (string.Equals(new DirectoryInfo(server.RootDirectory).FullName, directory.Parent!.FullName))
int? parentAlbumId = null;
if (!string.Equals(new DirectoryInfo(rootDirectory).FullName, directory.Parent!.FullName))
{
parentAlbum = null;
}
else
{
parentAlbum = await GetOrAddAlbumAsync(db, server, directory.Parent!, ct);
parentAlbumId = await GetOrAddAlbumAsync(db, serverId, rootDirectory, directory.Parent!, ct);
}
album = new AlbumEntity
{
ServerId = server.Id,
Server = server,
ServerId = serverId,
Name = directory.Name,
Path = albumPath,
ParentId = parentAlbum?.Id,
Parent = parentAlbum
ParentId = parentAlbumId
};
db.PiwigoAlbums.Add(album);
await db.SaveChangesAsync(ct);
return album;
return album.Id;
}
}