Optimize PostgreSQL dead tuple handling for media scans

Introduce bulk operation extensions and transaction helpers for efficient, batched EF Core operations. Refactor MediaStreamInfo schema by splitting audio/video details into dedicated tables, reducing table bloat and improving update performance. Add migration for data movement and schema changes. Update EF Core models and context for new structure. Enhance PostgreSQL provider configuration and add comprehensive documentation and monitoring guides. Includes minor middleware and code cleanups.
This commit is contained in:
2026-04-30 15:52:37 -04:00
parent 6d5282208b
commit 57d6342524
20 changed files with 1995 additions and 339 deletions
@@ -68,6 +68,8 @@ public class MediaStreamRepository : IMediaStreamRepository
{
await using var context = _dbProvider.CreateDbContext();
var streams = await TranslateQuery(context.MediaStreamInfos.AsNoTracking(), filter)
.Include(e => e.AudioDetails)
.Include(e => e.VideoDetails)
.ToArrayAsync(cancellationToken)
.ConfigureAwait(false);
@@ -131,46 +133,54 @@ public class MediaStreamRepository : IMediaStreamRepository
dto.Language = language;
dto.ChannelLayout = entity.ChannelLayout;
dto.Profile = entity.Profile;
dto.AspectRatio = entity.AspectRatio;
dto.Path = RestorePath(entity.Path);
dto.IsInterlaced = entity.IsInterlaced.GetValueOrDefault();
dto.BitRate = entity.BitRate;
dto.Channels = entity.Channels;
dto.SampleRate = entity.SampleRate;
dto.IsDefault = entity.IsDefault;
dto.IsForced = entity.IsForced;
dto.IsExternal = entity.IsExternal;
dto.Height = entity.Height;
dto.Width = entity.Width;
dto.AverageFrameRate = entity.AverageFrameRate;
dto.RealFrameRate = entity.RealFrameRate;
dto.Level = entity.Level;
dto.PixelFormat = entity.PixelFormat;
dto.BitDepth = entity.BitDepth;
dto.IsAnamorphic = entity.IsAnamorphic;
dto.RefFrames = entity.RefFrames;
dto.CodecTag = entity.CodecTag;
dto.Comment = entity.Comment;
dto.NalLengthSize = entity.NalLengthSize;
dto.Title = entity.Title;
dto.TimeBase = entity.TimeBase;
dto.CodecTimeBase = entity.CodecTimeBase;
dto.ColorPrimaries = entity.ColorPrimaries;
dto.ColorSpace = entity.ColorSpace;
dto.ColorTransfer = entity.ColorTransfer;
dto.DvVersionMajor = entity.DvVersionMajor;
dto.DvVersionMinor = entity.DvVersionMinor;
dto.DvProfile = entity.DvProfile;
dto.DvLevel = entity.DvLevel;
dto.RpuPresentFlag = entity.RpuPresentFlag;
dto.ElPresentFlag = entity.ElPresentFlag;
dto.BlPresentFlag = entity.BlPresentFlag;
dto.DvBlSignalCompatibilityId = entity.DvBlSignalCompatibilityId;
dto.IsHearingImpaired = entity.IsHearingImpaired.GetValueOrDefault();
dto.Rotation = entity.Rotation;
dto.Hdr10PlusPresentFlag = entity.Hdr10PlusPresentFlag;
if (entity.AudioDetails is { } audio)
{
dto.ChannelLayout = audio.ChannelLayout;
dto.Channels = audio.Channels;
dto.SampleRate = audio.SampleRate;
dto.IsHearingImpaired = audio.IsHearingImpaired.GetValueOrDefault();
}
if (entity.VideoDetails is { } video)
{
dto.AspectRatio = video.AspectRatio;
dto.IsInterlaced = video.IsInterlaced.GetValueOrDefault();
dto.Height = video.Height;
dto.Width = video.Width;
dto.AverageFrameRate = video.AverageFrameRate;
dto.RealFrameRate = video.RealFrameRate;
dto.PixelFormat = video.PixelFormat;
dto.BitDepth = video.BitDepth;
dto.IsAnamorphic = video.IsAnamorphic;
dto.RefFrames = video.RefFrames;
dto.NalLengthSize = video.NalLengthSize;
dto.ColorPrimaries = video.ColorPrimaries;
dto.ColorSpace = video.ColorSpace;
dto.ColorTransfer = video.ColorTransfer;
dto.DvVersionMajor = video.DvVersionMajor;
dto.DvVersionMinor = video.DvVersionMinor;
dto.DvProfile = video.DvProfile;
dto.DvLevel = video.DvLevel;
dto.RpuPresentFlag = video.RpuPresentFlag;
dto.ElPresentFlag = video.ElPresentFlag;
dto.BlPresentFlag = video.BlPresentFlag;
dto.DvBlSignalCompatibilityId = video.DvBlSignalCompatibilityId;
dto.Rotation = video.Rotation;
dto.Hdr10PlusPresentFlag = video.Hdr10PlusPresentFlag;
}
if (dto.Type is MediaStreamType.Audio or MediaStreamType.Subtitle)
{
@@ -206,47 +216,65 @@ public class MediaStreamRepository : IMediaStreamRepository
Codec = dto.Codec,
Language = dto.Language,
ChannelLayout = dto.ChannelLayout,
Profile = dto.Profile,
AspectRatio = dto.AspectRatio,
Path = GetPathToSave(dto.Path) ?? dto.Path,
IsInterlaced = dto.IsInterlaced,
BitRate = dto.BitRate,
Channels = dto.Channels,
SampleRate = dto.SampleRate,
IsDefault = dto.IsDefault,
IsForced = dto.IsForced,
IsExternal = dto.IsExternal,
Height = dto.Height,
Width = dto.Width,
AverageFrameRate = dto.AverageFrameRate,
RealFrameRate = dto.RealFrameRate,
Level = dto.Level.HasValue ? (float)dto.Level : null,
PixelFormat = dto.PixelFormat,
BitDepth = dto.BitDepth,
IsAnamorphic = dto.IsAnamorphic,
RefFrames = dto.RefFrames,
CodecTag = dto.CodecTag,
Comment = dto.Comment,
NalLengthSize = dto.NalLengthSize,
Title = dto.Title,
TimeBase = dto.TimeBase,
CodecTimeBase = dto.CodecTimeBase,
ColorPrimaries = dto.ColorPrimaries,
ColorSpace = dto.ColorSpace,
ColorTransfer = dto.ColorTransfer,
DvVersionMajor = dto.DvVersionMajor,
DvVersionMinor = dto.DvVersionMinor,
DvProfile = dto.DvProfile,
DvLevel = dto.DvLevel,
RpuPresentFlag = dto.RpuPresentFlag,
ElPresentFlag = dto.ElPresentFlag,
BlPresentFlag = dto.BlPresentFlag,
DvBlSignalCompatibilityId = dto.DvBlSignalCompatibilityId,
IsHearingImpaired = dto.IsHearingImpaired,
Rotation = dto.Rotation,
Hdr10PlusPresentFlag = dto.Hdr10PlusPresentFlag,
};
if (dto.Type == MediaStreamType.Audio)
{
entity.AudioDetails = new AudioStreamDetails
{
ItemId = itemId,
StreamIndex = dto.Index,
ChannelLayout = dto.ChannelLayout,
Channels = dto.Channels,
SampleRate = dto.SampleRate,
IsHearingImpaired = dto.IsHearingImpaired,
};
}
else if (dto.Type == MediaStreamType.Video)
{
entity.VideoDetails = new VideoStreamDetails
{
ItemId = itemId,
StreamIndex = dto.Index,
AspectRatio = dto.AspectRatio,
IsInterlaced = dto.IsInterlaced,
Height = dto.Height,
Width = dto.Width,
AverageFrameRate = dto.AverageFrameRate,
RealFrameRate = dto.RealFrameRate,
PixelFormat = dto.PixelFormat,
BitDepth = dto.BitDepth,
IsAnamorphic = dto.IsAnamorphic,
RefFrames = dto.RefFrames,
NalLengthSize = dto.NalLengthSize,
ColorPrimaries = dto.ColorPrimaries,
ColorSpace = dto.ColorSpace,
ColorTransfer = dto.ColorTransfer,
DvVersionMajor = dto.DvVersionMajor,
DvVersionMinor = dto.DvVersionMinor,
DvProfile = dto.DvProfile,
DvLevel = dto.DvLevel,
RpuPresentFlag = dto.RpuPresentFlag,
ElPresentFlag = dto.ElPresentFlag,
BlPresentFlag = dto.BlPresentFlag,
DvBlSignalCompatibilityId = dto.DvBlSignalCompatibilityId,
Rotation = dto.Rotation,
Hdr10PlusPresentFlag = dto.Hdr10PlusPresentFlag,
};
}
return entity;
}
}