Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 25 additions & 11 deletions Lite.Tests/DuckDbSentinelConnectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -645,33 +645,47 @@ defeats that compression the same way real Query Store plan XML would. */

Assert.NotNull(beforeBytes);

// DuckDB's "64MB" memory_limit unit is decimal (64 * 1000 * 1000 bytes), not binary (MiB).
const double trimTargetBytes = 64.0 * 1000.0 * 1000.0;

var originalThreshold = DuckDbInitializer.TrimThresholdBytes;
DuckDbInitializer.TrimThresholdBytes = 1;
double? afterBytes = null;
try
{
initializer.RunMemoryTrimCycle();
/* #4262: RunMemoryTrimCycle's own contract is "never wait" — it takes s_dbLock's write lock
with TryEnterWriteLock(0) and silently skips this cycle if another writer holds it (any
concurrent test process-wide, since s_dbLock is static across every DuckDbInitializer
instance, not just this one), same as a real caller mid-archival. A skipped cycle reports
beforeBytes == afterBytes with no error — exactly the "trim released nothing" failure this
test chased intermittently on CI (one Windows run: 105906176 -> 105906176). That is lock
contention from an unrelated parallel test, not a broken trim, so the test retries the
cycle itself rather than looser-than-the-contract on a single skipped attempt. */
for (var attempt = 0; attempt < 20; attempt++)
{
initializer.RunMemoryTrimCycle();

using var measure = initializer.CreateConnection();
await measure.OpenAsync();
afterBytes = initializer.ReadSentinelMemoryUsageBytes(measure);

if (afterBytes.HasValue && afterBytes.Value <= trimTargetBytes)
break;

await Task.Delay(50);
}
}
finally
{
DuckDbInitializer.TrimThresholdBytes = originalThreshold;
}

double? afterBytes;
using (var measure = initializer.CreateConnection())
{
await measure.OpenAsync();
afterBytes = initializer.ReadSentinelMemoryUsageBytes(measure);
}

Assert.NotNull(afterBytes);

initializer.Dispose();

Console.WriteLine($"#4262 round 1 trim measurement (duckdb_memory): before={beforeBytes / (1024.0 * 1024.0):F1} MB, after={afterBytes / (1024.0 * 1024.0):F1} MB");

// DuckDB's "64MB" memory_limit unit is decimal (64 * 1000 * 1000 bytes), not binary (MiB).
const double trimTargetBytes = 64.0 * 1000.0 * 1000.0;

Assert.True(beforeBytes > trimTargetBytes,
$"Expected the wide read to fill DuckDB's buffer past the trim target before trimming, or this test proves nothing: before={beforeBytes}, target={trimTargetBytes}");
Assert.True(afterBytes <= trimTargetBytes,
Expand Down
Loading