#498 fixes
This commit is contained in:
parent
6c369e7477
commit
a1b7c2fa12
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using RMuseum.DbContext;
|
||||||
using RMuseum.Models.Ganjoor;
|
using RMuseum.Models.Ganjoor;
|
||||||
using RSecurityBackend.Models.Generic;
|
using RSecurityBackend.Models.Generic;
|
||||||
using System;
|
using System;
|
||||||
@ -8,7 +9,6 @@ using System.Threading.Tasks;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using RMuseum.Models.Ganjoor.ViewModels;
|
using RMuseum.Models.Ganjoor.ViewModels;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using RMuseum.DbContext;
|
|
||||||
|
|
||||||
namespace RMuseum.Services.Implementation
|
namespace RMuseum.Services.Implementation
|
||||||
{
|
{
|
||||||
|
|||||||
@ -60,6 +60,13 @@ namespace RMuseum.Services.Implementation
|
|||||||
await jobProgressServiceEF.UpdateJob(job.Id, 1, "Writing shared lookup tables");
|
await jobProgressServiceEF.UpdateJob(job.Id, 1, "Writing shared lookup tables");
|
||||||
await ExportSharedLookupTables(context, repoRoot);
|
await ExportSharedLookupTables(context, repoRoot);
|
||||||
|
|
||||||
|
// loaded once for the whole run instead of once per poem (was the
|
||||||
|
// single biggest cost in this job: ~3 round-trips per poem, tens of
|
||||||
|
// thousands of poems, on every run regardless of what changed) — see
|
||||||
|
// ExportPoetContent for how sections/verses are batched per-poet.
|
||||||
|
var metresById = (await context.GanjoorMetres.AsNoTracking().ToListAsync())
|
||||||
|
.ToDictionary(m => m.Id);
|
||||||
|
|
||||||
var poets = await context.GanjoorPoets.AsNoTracking()
|
var poets = await context.GanjoorPoets.AsNoTracking()
|
||||||
.Include(p => p.BirthLocation)
|
.Include(p => p.BirthLocation)
|
||||||
.Include(p => p.DeathLocation)
|
.Include(p => p.DeathLocation)
|
||||||
@ -92,7 +99,7 @@ namespace RMuseum.Services.Implementation
|
|||||||
await ExportPoetToJson(context, repoRoot, poet, catPoet);
|
await ExportPoetToJson(context, repoRoot, poet, catPoet);
|
||||||
poetIdIndex[poet.Id] = catPoet.FullUrl;
|
poetIdIndex[poet.Id] = catPoet.FullUrl;
|
||||||
|
|
||||||
int poemCount = await ExportCatTreeToJson(context, repoRoot, catPoet, catIdIndex, poemIdIndex);
|
int poemCount = await ExportPoetContent(context, repoRoot, poet, catPoet, metresById, catIdIndex, poemIdIndex);
|
||||||
manifest.PoemsCount += poemCount;
|
manifest.PoemsCount += poemCount;
|
||||||
|
|
||||||
manifest.Poets.Add(new PublicExportManifestPoetEntryDto
|
manifest.Poets.Add(new PublicExportManifestPoetEntryDto
|
||||||
@ -202,6 +209,35 @@ namespace RMuseum.Services.Implementation
|
|||||||
await DeterministicJsonWriter.WriteIfChangedAsync(path, dto);
|
await DeterministicJsonWriter.WriteIfChangedAsync(path, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Batch-loads this poet's entire sections/verses in two queries (instead of the
|
||||||
|
/// two-per-poem queries the old per-poem approach ran), then walks the poet's category
|
||||||
|
/// tree writing everything from memory. This is the fix for the export consistently
|
||||||
|
/// taking about as long on every run regardless of how much content changed — the
|
||||||
|
/// "skip unchanged files" logic in DeterministicJsonWriter only ever saved disk writes,
|
||||||
|
/// never the DB round-trips, which were the actual dominant cost (roughly 3 sequential
|
||||||
|
/// queries per poem — tens of thousands of round-trips for the full corpus, every run).
|
||||||
|
/// </summary>
|
||||||
|
private async Task<int> ExportPoetContent(RMuseumDbContext context, string repoRoot, GanjoorPoet poet, GanjoorCat catPoet,
|
||||||
|
Dictionary<int, GanjoorMetre> metresById, Dictionary<int, string> catIdIndex, Dictionary<int, string> poemIdIndex)
|
||||||
|
{
|
||||||
|
var sectionsByPoem = (await context.GanjoorPoemSections.AsNoTracking()
|
||||||
|
.Where(s => s.Poem.Cat.PoetId == poet.Id)
|
||||||
|
.OrderBy(s => s.Index)
|
||||||
|
.ToListAsync())
|
||||||
|
.GroupBy(s => s.PoemId)
|
||||||
|
.ToDictionary(g => g.Key, g => g.ToList());
|
||||||
|
|
||||||
|
var versesByPoem = (await context.GanjoorVerses.AsNoTracking()
|
||||||
|
.Where(v => v.Poem.Cat.PoetId == poet.Id)
|
||||||
|
.OrderBy(v => v.VOrder)
|
||||||
|
.ToListAsync())
|
||||||
|
.GroupBy(v => v.PoemId)
|
||||||
|
.ToDictionary(g => g.Key, g => g.ToList());
|
||||||
|
|
||||||
|
return await ExportCatTreeToJson(context, repoRoot, catPoet, metresById, sectionsByPoem, versesByPoem, catIdIndex, poemIdIndex);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// recursively writes _cat.json for <paramref name="cat"/> and every poem directly
|
/// recursively writes _cat.json for <paramref name="cat"/> and every poem directly
|
||||||
/// under it, then recurses into child categories. Returns the number of poems written
|
/// under it, then recurses into child categories. Returns the number of poems written
|
||||||
@ -212,6 +248,8 @@ namespace RMuseum.Services.Implementation
|
|||||||
/// either; every category/poem under a published poet is exported.
|
/// either; every category/poem under a published poet is exported.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task<int> ExportCatTreeToJson(RMuseumDbContext context, string repoRoot, GanjoorCat cat,
|
private async Task<int> ExportCatTreeToJson(RMuseumDbContext context, string repoRoot, GanjoorCat cat,
|
||||||
|
Dictionary<int, GanjoorMetre> metresById,
|
||||||
|
Dictionary<int, List<GanjoorPoemSection>> sectionsByPoem, Dictionary<int, List<GanjoorVerse>> versesByPoem,
|
||||||
Dictionary<int, string> catIdIndex, Dictionary<int, string> poemIdIndex)
|
Dictionary<int, string> catIdIndex, Dictionary<int, string> poemIdIndex)
|
||||||
{
|
{
|
||||||
var childCats = await context.GanjoorCategories.AsNoTracking()
|
var childCats = await context.GanjoorCategories.AsNoTracking()
|
||||||
@ -247,34 +285,29 @@ namespace RMuseum.Services.Implementation
|
|||||||
|
|
||||||
foreach (var poem in poems)
|
foreach (var poem in poems)
|
||||||
{
|
{
|
||||||
await ExportPoemToJson(context, repoRoot, poem);
|
sectionsByPoem.TryGetValue(poem.Id, out var sections);
|
||||||
|
versesByPoem.TryGetValue(poem.Id, out var verses);
|
||||||
|
GanjoorMetre metre = poem.GanjoorMetreId != null && metresById.TryGetValue(poem.GanjoorMetreId.Value, out var m) ? m : null;
|
||||||
|
|
||||||
|
await ExportPoemToJson(repoRoot, poem, metre, sections ?? new List<GanjoorPoemSection>(), verses ?? new List<GanjoorVerse>());
|
||||||
poemIdIndex[poem.Id] = poem.FullUrl;
|
poemIdIndex[poem.Id] = poem.FullUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var childCat in childCats)
|
foreach (var childCat in childCats)
|
||||||
{
|
{
|
||||||
poemCount += await ExportCatTreeToJson(context, repoRoot, childCat, catIdIndex, poemIdIndex);
|
poemCount += await ExportCatTreeToJson(context, repoRoot, childCat, metresById, sectionsByPoem, versesByPoem, catIdIndex, poemIdIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return poemCount;
|
return poemCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ExportPoemToJson(RMuseumDbContext context, string repoRoot, GanjoorPoem poem)
|
/// <summary>
|
||||||
|
/// Pure in-memory write — no DB access. Sections/verses/metre are pre-loaded by the caller
|
||||||
|
/// (see <see cref="ExportPoetContent"/>) instead of queried per poem.
|
||||||
|
/// </summary>
|
||||||
|
private async Task ExportPoemToJson(string repoRoot, GanjoorPoem poem, GanjoorMetre metre,
|
||||||
|
List<GanjoorPoemSection> sections, List<GanjoorVerse> verses)
|
||||||
{
|
{
|
||||||
var metre = poem.GanjoorMetreId == null
|
|
||||||
? null
|
|
||||||
: await context.GanjoorMetres.AsNoTracking().Where(m => m.Id == poem.GanjoorMetreId).SingleOrDefaultAsync();
|
|
||||||
|
|
||||||
var sections = await context.GanjoorPoemSections.AsNoTracking()
|
|
||||||
.Where(s => s.PoemId == poem.Id)
|
|
||||||
.OrderBy(s => s.Index)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
var verses = await context.GanjoorVerses.AsNoTracking()
|
|
||||||
.Where(v => v.PoemId == poem.Id)
|
|
||||||
.OrderBy(v => v.VOrder)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
var dto = new PoemPublicDto
|
var dto = new PoemPublicDto
|
||||||
{
|
{
|
||||||
Id = poem.Id,
|
Id = poem.Id,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user