Skip to content

Commit f975abd

Browse files
committed
Fix DocumentationObjectPoolProvider usage
1 parent e3d6c13 commit f975abd

File tree

5 files changed

+120
-87
lines changed

5 files changed

+120
-87
lines changed

src/Elastic.Markdown/DocumentationGenerator.cs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -347,15 +347,13 @@ public async Task<string> RenderLlmMarkdown(MarkdownFile markdown, Cancel ctx)
347347
{
348348
await DocumentationSet.Tree.Resolve(ctx);
349349
var document = await markdown.ParseFullAsync(ctx);
350-
var stringBuilder = DocumentationObjectPoolProvider.StringBuilderPool.Get();
351-
await using var stringWriter = DocumentationObjectPoolProvider.StringWriterPool.Get();
352-
stringWriter.SetStringBuilder(stringBuilder);
353-
var renderer = new LlmMarkdownRenderer(stringWriter)
354-
{
355-
BuildContext = DocumentationSet.Context
356-
};
350+
var subscription = DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Get();
351+
subscription.SetBuildContext(DocumentationSet.Context);
352+
var renderer = subscription.LlmMarkdownRenderer;
357353
_ = renderer.Render(document);
358-
return stringBuilder.ToString().Trim();
354+
var result = subscription.RentedStringBuilder!.ToString().Trim();
355+
DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Return(subscription);
356+
return result;
359357
}
360358

361359
public async Task<RenderResult> RenderLayout(MarkdownFile markdown, Cancel ctx)

src/Elastic.Markdown/Exporters/LlmMarkdownExporter.cs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,13 @@ await fileContext.SourceFile.SourceFile.FileSystem.File.WriteAllTextAsync(
6161

6262
public static string ConvertToLlmMarkdown(MarkdownDocument document, MarkdownExportFileContext context)
6363
{
64-
var stringBuilder = DocumentationObjectPoolProvider.StringBuilderPool.Get();
65-
using var stringWriter = DocumentationObjectPoolProvider.StringWriterPool.Get();
66-
stringWriter.SetStringBuilder(stringBuilder);
67-
68-
var renderer = new LlmMarkdownRenderer(stringWriter)
69-
{
70-
BuildContext = context.BuildContext
71-
};
64+
var subscription = DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Get();
65+
subscription.SetBuildContext(context.BuildContext!);
66+
var renderer = subscription.LlmMarkdownRenderer;
7267
_ = renderer.Render(document);
73-
return stringBuilder.ToString();
68+
var result = subscription.RentedStringBuilder!.ToString();
69+
DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Return(subscription);
70+
return result;
7471
}
7572

7673
private static IFileInfo GetLlmOutputFile(MarkdownExportFileContext fileContext)

src/Elastic.Markdown/Helpers/DocumentationObjectPoolProvider.cs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
// See the LICENSE file in the project root for more information
44

55
using System.Text;
6+
using Elastic.Documentation.Configuration;
67
using Elastic.Documentation.Extensions;
78
using Elastic.Markdown.Myst;
9+
using Elastic.Markdown.Myst.Renderers.LlmMarkdown;
810
using Markdig.Renderers;
911
using Microsoft.Extensions.ObjectPool;
1012

@@ -17,6 +19,7 @@ internal static class DocumentationObjectPoolProvider
1719
public static readonly ObjectPool<StringBuilder> StringBuilderPool = PoolProvider.CreateStringBuilderPool(256, 4 * 1024);
1820
public static readonly ObjectPool<ReusableStringWriter> StringWriterPool = PoolProvider.Create(new ReusableStringWriterPooledObjectPolicy());
1921
public static readonly ObjectPool<HtmlRenderSubscription> HtmlRendererPool = PoolProvider.Create(new HtmlRendererPooledObjectPolicy());
22+
public static readonly ObjectPool<LlmMarkdownRenderSubscription> LlmMarkdownRendererPool = PoolProvider.Create(new LlmMarkdownRendererPooledObjectPolicy());
2023

2124

2225
private sealed class ReusableStringWriterPooledObjectPolicy : IPooledObjectPolicy<ReusableStringWriter>
@@ -36,6 +39,14 @@ public sealed class HtmlRenderSubscription
3639
public StringBuilder? RentedStringBuilder { get; internal set; }
3740
}
3841

42+
public sealed class LlmMarkdownRenderSubscription
43+
{
44+
public required LlmMarkdownRenderer LlmMarkdownRenderer { get; init; }
45+
public StringBuilder? RentedStringBuilder { get; internal set; }
46+
47+
public void SetBuildContext(BuildContext buildContext) => LlmMarkdownRenderer.BuildContext = buildContext;
48+
}
49+
3950
private sealed class HtmlRendererPooledObjectPolicy : IPooledObjectPolicy<HtmlRenderSubscription>
4051
{
4152
public HtmlRenderSubscription Create()
@@ -51,7 +62,6 @@ public HtmlRenderSubscription Create()
5162

5263
public bool Return(HtmlRenderSubscription subscription)
5364
{
54-
//subscription.RentedStringBuilder = null;
5565
//return string builder
5666
if (subscription.RentedStringBuilder is not null)
5767
StringBuilderPool.Return(subscription.RentedStringBuilder);
@@ -71,4 +81,42 @@ public bool Return(HtmlRenderSubscription subscription)
7181
}
7282
}
7383

84+
private sealed class LlmMarkdownRendererPooledObjectPolicy : IPooledObjectPolicy<LlmMarkdownRenderSubscription>
85+
{
86+
public LlmMarkdownRenderSubscription Create()
87+
{
88+
var stringBuilder = StringBuilderPool.Get();
89+
using var stringWriter = StringWriterPool.Get();
90+
stringWriter.SetStringBuilder(stringBuilder);
91+
var renderer = new LlmMarkdownRenderer(stringWriter)
92+
{
93+
BuildContext = null
94+
};
95+
return new LlmMarkdownRenderSubscription { LlmMarkdownRenderer = renderer, RentedStringBuilder = stringBuilder };
96+
}
97+
98+
public bool Return(LlmMarkdownRenderSubscription subscription)
99+
{
100+
//return string builder
101+
if (subscription.RentedStringBuilder is not null)
102+
StringBuilderPool.Return(subscription.RentedStringBuilder);
103+
104+
subscription.RentedStringBuilder = null;
105+
106+
var renderer = subscription.LlmMarkdownRenderer;
107+
108+
//reset string writer
109+
((ReusableStringWriter)renderer.Writer).Reset();
110+
111+
// reseed string writer with string builder
112+
var stringBuilder = StringBuilderPool.Get();
113+
subscription.RentedStringBuilder = stringBuilder;
114+
((ReusableStringWriter)renderer.Writer).SetStringBuilder(stringBuilder);
115+
116+
// Reset BuildContext to null for reuse
117+
renderer.BuildContext = null!;
118+
119+
return true;
120+
}
121+
}
74122
}

src/Elastic.Markdown/Myst/Renderers/LlmMarkdown/LlmBlockRenderers.cs

Lines changed: 58 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,21 @@ namespace Elastic.Markdown.Myst.Renderers.LlmMarkdown;
2222

2323
public static class LlmRenderingHelpers
2424
{
25-
public static ReusableStringWriter CreateTempWriter()
26-
{
27-
var stringBuilder = DocumentationObjectPoolProvider.StringBuilderPool.Get();
28-
var sw = DocumentationObjectPoolProvider.StringWriterPool.Get();
29-
sw.SetStringBuilder(stringBuilder);
30-
return sw;
31-
}
25+
// public static ReusableStringWriter CreateTempWriter()
26+
// {
27+
// var stringBuilder = DocumentationObjectPoolProvider.StringBuilderPool.Get();
28+
// var sw = DocumentationObjectPoolProvider.StringWriterPool.Get();
29+
// sw.SetStringBuilder(stringBuilder);
30+
// return sw;
31+
// }
3232

3333
public static void RenderBlockWithIndentation(LlmMarkdownRenderer renderer, MarkdownObject block, string indentation = " ")
3434
{
35-
using var sw = CreateTempWriter();
36-
var tempRenderer = new LlmMarkdownRenderer(sw)
37-
{
38-
BuildContext = renderer.BuildContext
39-
};
35+
var subscription = DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Get();
36+
subscription.SetBuildContext(renderer.BuildContext!);
37+
var tempRenderer = subscription.LlmMarkdownRenderer;
4038
_ = tempRenderer.Render(block);
41-
var content = sw.ToString();
39+
var content = subscription.RentedStringBuilder!.ToString();
4240
if (string.IsNullOrEmpty(content))
4341
return;
4442
var lines = content.Split(['\n', '\r'], StringSplitOptions.RemoveEmptyEntries);
@@ -47,6 +45,7 @@ public static void RenderBlockWithIndentation(LlmMarkdownRenderer renderer, Mark
4745
renderer.Write(indentation);
4846
renderer.WriteLine(line);
4947
}
48+
DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Return(subscription);
5049
}
5150

5251
/// <summary>
@@ -56,7 +55,7 @@ public static void RenderBlockWithIndentation(LlmMarkdownRenderer renderer, Mark
5655
{
5756
if (
5857
string.IsNullOrEmpty(url)
59-
|| renderer.BuildContext.CanonicalBaseUrl == null
58+
|| renderer.BuildContext!.CanonicalBaseUrl == null
6059
|| Uri.IsWellFormedUriString(url, UriKind.Absolute)
6160
|| !Uri.IsWellFormedUriString(url, UriKind.Relative))
6261
return url;
@@ -201,13 +200,11 @@ private static string GetContinuationIndent(string baseIndent, bool isOrdered) =
201200

202201
private static void RenderBlockWithIndentation(LlmMarkdownRenderer renderer, Block block, string baseIndent, bool isOrdered)
203202
{
204-
using var sw = LlmRenderingHelpers.CreateTempWriter();
205-
var tempRenderer = new LlmMarkdownRenderer(sw)
206-
{
207-
BuildContext = renderer.BuildContext
208-
};
203+
var subscription = DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Get();
204+
subscription.SetBuildContext(renderer.BuildContext!);
205+
var tempRenderer = subscription.LlmMarkdownRenderer;
209206
_ = tempRenderer.Render(block);
210-
var blockOutput = sw.ToString();
207+
var blockOutput = subscription.RentedStringBuilder!.ToString();
211208

212209
var continuationIndent = GetContinuationIndent(baseIndent, isOrdered);
213210
var lines = blockOutput.Split('\n');
@@ -225,6 +222,7 @@ private static void RenderBlockWithIndentation(LlmMarkdownRenderer renderer, Blo
225222
else if (i < lines.Length - 1)
226223
renderer.WriteLine();
227224
}
225+
DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Return(subscription);
228226
}
229227

230228
/// <summary>
@@ -301,20 +299,19 @@ protected override void Write(LlmMarkdownRenderer renderer, Table table)
301299
renderer.Writer.Write(" ");
302300

303301
// Capture cell content
304-
using var sw = LlmRenderingHelpers.CreateTempWriter();
305-
var tempRenderer = new LlmMarkdownRenderer(sw)
306-
{
307-
BuildContext = renderer.BuildContext
308-
};
302+
var subscription = DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Get();
303+
subscription.SetBuildContext(renderer.BuildContext!);
304+
var tempRenderer = subscription.LlmMarkdownRenderer;
309305
// Render cell content to temporary writer
310306
foreach (var inline in cell.Descendants().OfType<Inline>())
311307
tempRenderer.Write(inline);
312308

313309
// Write padded content
314-
var content = sw.ToString();
310+
var content = subscription.RentedStringBuilder!.ToString();
315311
renderer.Writer.Write(content.PadRight(columnWidths[cellIndex]));
316312
renderer.Writer.Write(" |");
317313
cellIndex++;
314+
DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Return(subscription);
318315
}
319316

320317
renderer.WriteLine();
@@ -340,20 +337,19 @@ protected override void Write(LlmMarkdownRenderer renderer, Table table)
340337
renderer.Writer.Write(" ");
341338

342339
// Capture cell content
343-
using var sw = LlmRenderingHelpers.CreateTempWriter();
344-
var tempRenderer = new LlmMarkdownRenderer(sw)
345-
{
346-
BuildContext = renderer.BuildContext
347-
};
340+
var subscription = DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Get();
341+
subscription.SetBuildContext(renderer.BuildContext!);
342+
var tempRenderer = subscription.LlmMarkdownRenderer;
348343
// Render cell content to temporary writer
349344
foreach (var inline in cell.Descendants().OfType<Inline>())
350345
tempRenderer.Write(inline);
351346

352347
// Write padded content
353-
var content = sw.ToString();
348+
var content = subscription.RentedStringBuilder!.ToString();
354349
renderer.Writer.Write(content.PadRight(columnWidths[cellIndex]));
355350
renderer.Writer.Write(" |");
356351
cellIndex++;
352+
DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Return(subscription);
357353
}
358354

359355
renderer.WriteLine();
@@ -380,21 +376,20 @@ private static int[] CalculateColumnWidths(LlmMarkdownRenderer renderer, Table t
380376
foreach (var cell in row.Cast<TableCell>())
381377
{
382378
// Capture cell content
383-
using var sw = LlmRenderingHelpers.CreateTempWriter();
384-
var tempRenderer = new LlmMarkdownRenderer(sw)
385-
{
386-
BuildContext = renderer.BuildContext
387-
};
379+
var subscription = DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Get();
380+
subscription.SetBuildContext(renderer.BuildContext!);
381+
var tempRenderer = subscription.LlmMarkdownRenderer;
388382
// Render cell content to temporary writer
389383
foreach (var inline in cell.Descendants().OfType<Inline>())
390384
{
391385
tempRenderer.Write(inline);
392386
}
393387

394388
// Update width if this cell is wider
395-
var content = sw.ToString();
389+
var content = subscription.RentedStringBuilder!.ToString();
396390
widths[cellIndex] = Math.Max(widths[cellIndex], content.Length);
397391
cellIndex++;
392+
DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Return(subscription);
398393
}
399394
}
400395

@@ -464,7 +459,7 @@ private void WriteIncludeBlock(LlmMarkdownRenderer renderer, IncludeBlock block)
464459
{
465460
if (!block.Found || block.IncludePath is null)
466461
{
467-
renderer.BuildContext.Collector.EmitError(block.IncludePath ?? string.Empty, "File not found or invalid path");
462+
renderer.BuildContext!.Collector.EmitError(block.IncludePath ?? string.Empty, "File not found or invalid path");
468463
return;
469464
}
470465

@@ -474,7 +469,7 @@ private void WriteIncludeBlock(LlmMarkdownRenderer renderer, IncludeBlock block)
474469
var snippet = block.Build.ReadFileSystem.FileInfo.New(block.IncludePath);
475470
if (!snippet.Exists)
476471
{
477-
renderer.BuildContext.Collector.EmitError(block.IncludePath ?? string.Empty, "File not found or invalid path");
472+
renderer.BuildContext!.Collector.EmitError(block.IncludePath ?? string.Empty, "File not found or invalid path");
478473
return;
479474
}
480475

@@ -503,7 +498,7 @@ private void WriteIncludeBlock(LlmMarkdownRenderer renderer, IncludeBlock block)
503498
}
504499
catch (Exception ex)
505500
{
506-
renderer.BuildContext.Collector.EmitError(block.IncludePath ?? string.Empty, "Failed to parse included content", ex);
501+
renderer.BuildContext!.Collector.EmitError(block.IncludePath ?? string.Empty, "Failed to parse included content", ex);
507502
}
508503
}
509504

@@ -513,32 +508,25 @@ private void WriteIncludeBlock(LlmMarkdownRenderer renderer, IncludeBlock block)
513508
private static void WriteChildrenWithIndentation(LlmMarkdownRenderer renderer, Block container, string indent)
514509
{
515510
// Capture output and manually add indentation
516-
using var sw = LlmRenderingHelpers.CreateTempWriter();
517-
518-
var originalWriter = renderer.Writer;
519-
renderer.Writer = sw;
520-
try
511+
var subscription = DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Get();
512+
subscription.SetBuildContext(renderer.BuildContext!);
513+
var tempRenderer = subscription.LlmMarkdownRenderer;
514+
switch (container)
521515
{
522-
switch (container)
523-
{
524-
case ContainerBlock containerBlock:
525-
renderer.WriteChildren(containerBlock);
526-
break;
527-
case LeafBlock leafBlock:
528-
renderer.WriteLeafInline(leafBlock);
529-
break;
530-
}
531-
var content = sw.ToString();
532-
if (string.IsNullOrEmpty(content))
533-
return;
534-
var reader = new StringReader(content);
535-
while (reader.ReadLine() is { } line)
536-
originalWriter.WriteLine(string.IsNullOrWhiteSpace(line) ? string.Empty : indent + line);
537-
}
538-
finally
539-
{
540-
renderer.Writer = originalWriter;
516+
case ContainerBlock containerBlock:
517+
tempRenderer.WriteChildren(containerBlock);
518+
break;
519+
case LeafBlock leafBlock:
520+
tempRenderer.WriteLeafInline(leafBlock);
521+
break;
541522
}
523+
var content = subscription.RentedStringBuilder!.ToString();
524+
if (string.IsNullOrEmpty(content))
525+
return;
526+
var reader = new StringReader(content);
527+
while (reader.ReadLine() is { } line)
528+
renderer.WriteLine(string.IsNullOrWhiteSpace(line) ? string.Empty : indent + line);
529+
DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Return(subscription);
542530
}
543531
}
544532

@@ -565,10 +553,12 @@ protected override void Write(LlmMarkdownRenderer renderer, DefinitionItem obj)
565553

566554
private static string GetPlainTextFromLeafBlock(LlmMarkdownRenderer renderer, LeafBlock leafBlock)
567555
{
568-
using var sw = LlmRenderingHelpers.CreateTempWriter();
569-
var tempRenderer = new LlmMarkdownRenderer(sw) { BuildContext = renderer.BuildContext };
556+
var subscription = DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Get();
557+
subscription.SetBuildContext(renderer.BuildContext!);
558+
var tempRenderer = subscription.LlmMarkdownRenderer;
570559
tempRenderer.WriteLeafInline(leafBlock);
571-
var markdownText = sw.ToString();
560+
var markdownText = subscription.RentedStringBuilder!.ToString();
561+
DocumentationObjectPoolProvider.LlmMarkdownRendererPool.Return(subscription);
572562
return markdownText.StripMarkdown();
573563
}
574564
}

src/Elastic.Markdown/Myst/Renderers/LlmMarkdown/LlmMarkdownRenderer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace Elastic.Markdown.Myst.Renderers.LlmMarkdown;
1313
/// </summary>
1414
public class LlmMarkdownRenderer : TextRendererBase
1515
{
16-
public required BuildContext BuildContext { get; init; }
16+
public required BuildContext? BuildContext { get; set; }
1717
private bool _isAtLineStart = true;
1818

1919
/// <summary>

0 commit comments

Comments
 (0)