fixes concurrency issues on get or add album
All checks were successful
PiwigoDirectorySync/pipeline/head This commit looks good
All checks were successful
PiwigoDirectorySync/pipeline/head This commit looks good
This commit is contained in:
parent
f111df487d
commit
3b8dad1af2
@ -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" />
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user