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.Configuration.Json" Version="7.0.0"/>
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" 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="Piwigo.Client" Version="0.1.0.19" />
|
||||||
|
<PackageReference Include="Polly" Version="7.2.4" />
|
||||||
<PackageReference Include="Serilog" Version="3.0.1" />
|
<PackageReference Include="Serilog" Version="3.0.1" />
|
||||||
<PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" />
|
<PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Data;
|
||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using PiwigoDirectorySync.Infrastructure;
|
using PiwigoDirectorySync.Infrastructure;
|
||||||
using PiwigoDirectorySync.Persistence;
|
using PiwigoDirectorySync.Persistence;
|
||||||
|
using Polly;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace PiwigoDirectorySync.Services;
|
namespace PiwigoDirectorySync.Services;
|
||||||
@ -62,7 +64,7 @@ internal class FileIndexer : IFileIndexer
|
|||||||
|
|
||||||
var relativePath = Path.GetRelativePath(piwigoServer.RootDirectory, fullFilePath);
|
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);
|
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)
|
if (imageEntity is null)
|
||||||
{
|
{
|
||||||
imageEntity = new ImageEntity
|
imageEntity = new ImageEntity
|
||||||
{
|
{
|
||||||
AlbumId = album.Id,
|
AlbumId = albumId,
|
||||||
Album = album,
|
|
||||||
FilePath = relativePath,
|
FilePath = relativePath,
|
||||||
UploadRequired = true,
|
UploadRequired = true,
|
||||||
DeleteRequired = false
|
DeleteRequired = false
|
||||||
@ -105,38 +106,52 @@ internal class FileIndexer : IFileIndexer
|
|||||||
return imageEntity;
|
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);
|
return await Policy.Handle<DbUpdateException>()
|
||||||
var album = await db.PiwigoAlbums.FindByServerAndPathAsync(server.Id, albumPath, ct);
|
.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)
|
if (album != null)
|
||||||
{
|
{
|
||||||
return album;
|
return album.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
AlbumEntity? parentAlbum;
|
int? parentAlbumId = null;
|
||||||
if (string.Equals(new DirectoryInfo(server.RootDirectory).FullName, directory.Parent!.FullName))
|
if (!string.Equals(new DirectoryInfo(rootDirectory).FullName, directory.Parent!.FullName))
|
||||||
{
|
{
|
||||||
parentAlbum = null;
|
parentAlbumId = await GetOrAddAlbumAsync(db, serverId, rootDirectory, directory.Parent!, ct);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parentAlbum = await GetOrAddAlbumAsync(db, server, directory.Parent!, ct);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
album = new AlbumEntity
|
album = new AlbumEntity
|
||||||
{
|
{
|
||||||
ServerId = server.Id,
|
ServerId = serverId,
|
||||||
Server = server,
|
|
||||||
Name = directory.Name,
|
Name = directory.Name,
|
||||||
Path = albumPath,
|
Path = albumPath,
|
||||||
ParentId = parentAlbum?.Id,
|
ParentId = parentAlbumId
|
||||||
Parent = parentAlbum
|
|
||||||
};
|
};
|
||||||
db.PiwigoAlbums.Add(album);
|
db.PiwigoAlbums.Add(album);
|
||||||
|
|
||||||
await db.SaveChangesAsync(ct);
|
await db.SaveChangesAsync(ct);
|
||||||
|
|
||||||
return album;
|
return album.Id;
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user