Skip to content

Commit 3a50975

Browse files
committed
feat: implement virtual content management for large files in TabInfo
1 parent 868195f commit 3a50975

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

TabInfo.cs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.ComponentModel;
3+
using System.IO;
34
using System.Text.Json.Serialization;
45
using System.Text.RegularExpressions;
56
using System.Windows;
@@ -133,6 +134,13 @@ public bool HasNewContent
133134
// Validation state
134135
public bool IsRegexValid { get; private set; }
135136

137+
// Virtual content management for large files
138+
private readonly string? _tempFilePath;
139+
private long _totalContentLength;
140+
private const long MAX_MEMORY_CONTENT = 25_000_000; // 25MB in memory
141+
private const long KEEP_RECENT_CONTENT = 5_000_000; // Keep last 5MB in memory
142+
private bool _isUsingDiskStorage = false;
143+
136144
/// <summary>
137145
/// Creates a new TabInfo with references to all controls
138146
/// </summary>
@@ -163,6 +171,11 @@ public TabInfo(
163171
AfterLinesCurrent = 0;
164172
IsAutoCreated = isAutoCreated;
165173

174+
// Initialize virtual content management
175+
_tempFilePath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), $"X4LogWatcher_Tab_{Guid.NewGuid():N}.tmp");
176+
_totalContentLength = 0;
177+
_isUsingDiskStorage = false;
178+
166179
// Wire up events
167180
RegexTextBox.TextChanged += RegexTextBox_TextChanged;
168181

@@ -308,6 +321,9 @@ public void AppendContent(string text)
308321

309322
ContentTextBox.AppendText(text);
310323
ContentTextBox.ScrollToEnd();
324+
325+
// Check if we need to optimize memory after adding content
326+
OptimizeMemoryIfNeeded();
311327
}
312328

313329
/// <summary>
@@ -339,6 +355,102 @@ private void UpdateNewContentIndicator()
339355
UpdateTabHeader();
340356
}
341357

358+
/// <summary>
359+
/// Get estimated memory usage of this tab's content
360+
/// </summary>
361+
/// <returns>Estimated memory usage in bytes</returns>
362+
public long GetEstimatedMemoryUsage()
363+
{
364+
if (_disposed)
365+
return 0;
366+
367+
try
368+
{
369+
// Estimate memory usage: string content + UI overhead
370+
var textLength = ContentTextBox?.Text?.Length ?? 0;
371+
return textLength * 2; // Unicode characters are 2 bytes each
372+
}
373+
catch
374+
{
375+
return 0;
376+
}
377+
}
378+
379+
/// <summary>
380+
/// Optimize memory usage by moving old content to disk if needed
381+
/// </summary>
382+
public void OptimizeMemoryIfNeeded()
383+
{
384+
if (_disposed || ContentTextBox == null)
385+
return;
386+
387+
try
388+
{
389+
var currentLength = ContentTextBox.Text.Length;
390+
391+
if (currentLength > MAX_MEMORY_CONTENT)
392+
{
393+
// Keep only the most recent content in memory
394+
var text = ContentTextBox.Text;
395+
var keepFromIndex = Math.Max(0, currentLength - (int)KEEP_RECENT_CONTENT);
396+
397+
// Find a good line boundary to cut at
398+
var cutIndex = text.LastIndexOf('\n', keepFromIndex);
399+
if (cutIndex < 0)
400+
cutIndex = keepFromIndex;
401+
402+
var oldContent = text.Substring(0, cutIndex);
403+
var recentContent = text.Substring(cutIndex);
404+
405+
// Save old content to disk if we have a temp file path
406+
if (!string.IsNullOrEmpty(_tempFilePath))
407+
{
408+
File.AppendAllText(_tempFilePath, oldContent);
409+
_isUsingDiskStorage = true;
410+
}
411+
412+
// Keep only recent content in memory
413+
ContentTextBox.Text = recentContent;
414+
_totalContentLength += oldContent.Length;
415+
416+
System.Diagnostics.Debug.WriteLine(
417+
$"Tab '{TabName}' optimized: moved {oldContent.Length} chars to disk, kept {recentContent.Length} in memory"
418+
);
419+
}
420+
}
421+
catch (Exception ex)
422+
{
423+
System.Diagnostics.Debug.WriteLine($"Error optimizing memory for tab '{TabName}': {ex.Message}");
424+
}
425+
}
426+
427+
/// <summary>
428+
/// Get the full content including disk-stored content (expensive operation)
429+
/// </summary>
430+
public string GetFullContent()
431+
{
432+
if (_disposed)
433+
return string.Empty;
434+
435+
try
436+
{
437+
var memoryContent = ContentTextBox?.Text ?? string.Empty;
438+
439+
if (_isUsingDiskStorage && !string.IsNullOrEmpty(_tempFilePath) && File.Exists(_tempFilePath))
440+
{
441+
var diskContent = File.ReadAllText(_tempFilePath);
442+
return diskContent + memoryContent;
443+
}
444+
445+
return memoryContent;
446+
}
447+
catch (Exception ex)
448+
{
449+
System.Diagnostics.Debug.WriteLine($"Error reading full content for tab '{TabName}': {ex.Message}");
450+
return ContentTextBox?.Text ?? string.Empty;
451+
}
452+
}
453+
342454
#region IDisposable Implementation
343455

344456
/// <summary>
@@ -389,6 +501,22 @@ protected virtual void Dispose(bool disposing)
389501
{
390502
ContentTextBox.Clear();
391503
}
504+
505+
// Clean up temporary file if it exists
506+
if (_isUsingDiskStorage && !string.IsNullOrEmpty(_tempFilePath))
507+
{
508+
try
509+
{
510+
if (File.Exists(_tempFilePath))
511+
{
512+
File.Delete(_tempFilePath);
513+
}
514+
}
515+
catch (Exception deleteEx)
516+
{
517+
System.Diagnostics.Debug.WriteLine($"Error deleting temp file {_tempFilePath}: {deleteEx.Message}");
518+
}
519+
}
392520
}
393521
catch (Exception ex)
394522
{

0 commit comments

Comments
 (0)