diff --git a/FileStorageService.www/Controllers/FilesController.cs b/FileStorageService.www/Controllers/FilesController.cs index c4f35e3..99bf3b3 100644 --- a/FileStorageService.www/Controllers/FilesController.cs +++ b/FileStorageService.www/Controllers/FilesController.cs @@ -28,7 +28,7 @@ public class FilesController( var handles = fileHandles.Select(e => new FileHandleModel { FileName = e.Name, - BlockCount = e.FileBlocks.Count, + BlockCount = e.FileBlockCount, Id = e.Id, }) .ToList(); @@ -48,7 +48,7 @@ public class FilesController( var model = new FileHandleModel { FileName = fileHandle.Name, - BlockCount = fileHandle.FileBlocks.Count, + BlockCount = fileHandle.FileBlockCount, Id = fileHandle.Id, }; diff --git a/FileStorageService.www/Data/FileHandle.cs b/FileStorageService.www/Data/FileHandle.cs index d5f3006..0533e8a 100644 --- a/FileStorageService.www/Data/FileHandle.cs +++ b/FileStorageService.www/Data/FileHandle.cs @@ -10,4 +10,6 @@ public class FileHandle public required string Name { get; set; } public ICollection FileBlocks { get; } = new List(); + + public int FileBlockCount { get; set; } = 0; } \ No newline at end of file diff --git a/FileStorageService.www/Data/Migrations/20250317201703_DenormalisingBlockCount.Designer.cs b/FileStorageService.www/Data/Migrations/20250317201703_DenormalisingBlockCount.Designer.cs new file mode 100644 index 0000000..b962fda --- /dev/null +++ b/FileStorageService.www/Data/Migrations/20250317201703_DenormalisingBlockCount.Designer.cs @@ -0,0 +1,84 @@ +// +using System; +using FileStorageService.www.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace FileStorageService.www.Data.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20250317201703_DenormalisingBlockCount")] + partial class DenormalisingBlockCount + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "9.0.0"); + + modelBuilder.Entity("FileStorageService.www.Data.FileBlock", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("BlockNumber") + .HasColumnType("INTEGER"); + + b.Property("Data") + .IsRequired() + .HasMaxLength(1024) + .HasColumnType("BLOB"); + + b.Property("FileHandleId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("FileHandleId"); + + b.ToTable("FileBlocks"); + }); + + modelBuilder.Entity("FileStorageService.www.Data.FileHandle", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("FileBlockCount") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("FileHandles"); + }); + + modelBuilder.Entity("FileStorageService.www.Data.FileBlock", b => + { + b.HasOne("FileStorageService.www.Data.FileHandle", "FileHandle") + .WithMany("FileBlocks") + .HasForeignKey("FileHandleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FileHandle"); + }); + + modelBuilder.Entity("FileStorageService.www.Data.FileHandle", b => + { + b.Navigation("FileBlocks"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/FileStorageService.www/Data/Migrations/20250317201703_DenormalisingBlockCount.cs b/FileStorageService.www/Data/Migrations/20250317201703_DenormalisingBlockCount.cs new file mode 100644 index 0000000..4350538 --- /dev/null +++ b/FileStorageService.www/Data/Migrations/20250317201703_DenormalisingBlockCount.cs @@ -0,0 +1,38 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace FileStorageService.www.Data.Migrations +{ + /// + public partial class DenormalisingBlockCount : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "FileBlockCount", + table: "FileHandles", + type: "INTEGER", + nullable: false, + defaultValue: 0); + + migrationBuilder.Sql(@" + UPDATE FileHandles + SET FileBlockCount = ( + SELECT COUNT(*) + FROM FileBlocks + WHERE FileBlocks.FileHandleId = FileHandles.Id + ); + "); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "FileBlockCount", + table: "FileHandles"); + } + } +} diff --git a/FileStorageService.www/Data/Migrations/ApplicationDbContextModelSnapshot.cs b/FileStorageService.www/Data/Migrations/ApplicationDbContextModelSnapshot.cs index b0da111..c06cac2 100644 --- a/FileStorageService.www/Data/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/FileStorageService.www/Data/Migrations/ApplicationDbContextModelSnapshot.cs @@ -47,6 +47,9 @@ namespace FileStorageService.www.Data.Migrations .ValueGeneratedOnAdd() .HasColumnType("TEXT"); + b.Property("FileBlockCount") + .HasColumnType("INTEGER"); + b.Property("Name") .IsRequired() .HasMaxLength(64) diff --git a/FileStorageService.www/Repositories/FileRepository.cs b/FileStorageService.www/Repositories/FileRepository.cs index 8c3dcc5..d8a1616 100644 --- a/FileStorageService.www/Repositories/FileRepository.cs +++ b/FileStorageService.www/Repositories/FileRepository.cs @@ -7,8 +7,8 @@ public class FileRepository(ApplicationDbContext context) { public static readonly int MAX_BLOCKS = 10_485_760; - private readonly Queue<(string, Stream)> creationQueue = new(); - private readonly Lock countLock = new(); + private readonly Queue<(string, Stream)> _creationQueue = new(); + private readonly Lock _countLock = new(); public async Task> GetAllFilesAsync() { @@ -26,9 +26,9 @@ public class FileRepository(ApplicationDbContext context) { var tcs = new TaskCompletionSource(); - lock (creationQueue) + lock (_creationQueue) { - creationQueue.Enqueue((name, reader)); + _creationQueue.Enqueue((name, reader)); } Task.Run(async () => @@ -37,9 +37,9 @@ public class FileRepository(ApplicationDbContext context) Stream stream; string name; - lock (creationQueue) + lock (_creationQueue) { - (name, stream) = creationQueue.Dequeue(); + (name, stream) = _creationQueue.Dequeue(); } var fileHandle = new FileHandle @@ -49,8 +49,9 @@ public class FileRepository(ApplicationDbContext context) var handle = await CreateFileBlocks(stream, fileHandle); var currentFileCount = handle.FileBlocks.Count(); + handle.FileBlockCount = currentFileCount; - lock (countLock) + lock (_countLock) { var count = context.FileBlocks.Count(); diff --git a/FileStorageService.www/Views/Files/Index.cshtml b/FileStorageService.www/Views/Files/Index.cshtml index 7a4b583..a5126ac 100644 --- a/FileStorageService.www/Views/Files/Index.cshtml +++ b/FileStorageService.www/Views/Files/Index.cshtml @@ -7,7 +7,7 @@

All Files

-
+
Total Storage
@@ -21,31 +21,37 @@
-@if (!Model.FileHandles.Any()) -{ -

No files available

-} -else -{ - - - - - - - - - - @foreach (var file in Model.FileHandles) +
+
+ @if (!Model.FileHandles.Any()) { -
- - - - +

No files available

+ New File... } - -
NameBlock CountLinks
@file.FileName@file.BlockCountView...
-} \ No newline at end of file + else + { + + + + + + + + + + @foreach (var file in Model.FileHandles) + { + + + + + + } + +
NameBlock CountLinks
@file.FileName@file.BlockCount + View...
+ } +
+
\ No newline at end of file diff --git a/FileStorageService.www/Views/Shared/_Layout.cshtml b/FileStorageService.www/Views/Shared/_Layout.cshtml index 2f06810..5bd3917 100644 --- a/FileStorageService.www/Views/Shared/_Layout.cshtml +++ b/FileStorageService.www/Views/Shared/_Layout.cshtml @@ -24,7 +24,7 @@ Home