Skip to content

Commit eaf5da1

Browse files
sakrutclaude
andcommitted
fix: make Windows SQLite file lock retry more aggressive
Increased retry attempts and improved cleanup for Windows file locking: Changes: - Increased max attempts from 10 to 20 - Increased initial delay from 50ms to 100ms - Capped max delay at 2 seconds - Added SqliteConnection.ClearAllPools() before and during retries - Added second GC.Collect() to clean up finalizer queue - ErrorPathTests: Also delete WAL/SHM files Windows + SQLite WAL mode can hold locks for several seconds after disposal. These changes give more time for Windows to release locks. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent f621a55 commit eaf5da1

2 files changed

Lines changed: 22 additions & 7 deletions

File tree

AiCodeGraph.Tests/ErrorPathTests.cs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ private static void DeleteFileWithRetry(string path)
1717
return;
1818

1919
// On Windows, SQLite may keep files locked briefly after connection disposal
20+
Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools();
21+
2022
var attempts = 0;
21-
var maxAttempts = 10;
22-
var delay = 50; // ms
23+
var maxAttempts = 20; // Increased for Windows
24+
var delay = 100; // Start with 100ms
2325

2426
while (attempts < maxAttempts)
2527
{
@@ -29,16 +31,25 @@ private static void DeleteFileWithRetry(string path)
2931
{
3032
GC.Collect();
3133
GC.WaitForPendingFinalizers();
34+
GC.Collect(); // Second GC to clean up finalizer queue
35+
Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools();
3236
Thread.Sleep(delay);
3337
}
3438

3539
File.Delete(path);
40+
41+
// Also try to delete WAL and SHM files if they exist
42+
var walPath = path + "-wal";
43+
var shmPath = path + "-shm";
44+
if (File.Exists(walPath)) File.Delete(walPath);
45+
if (File.Exists(shmPath)) File.Delete(shmPath);
46+
3647
return; // Success
3748
}
3849
catch (IOException) when (attempts < maxAttempts - 1)
3950
{
4051
attempts++;
41-
delay *= 2; // Exponential backoff
52+
delay = Math.Min(delay * 2, 2000); // Cap at 2 seconds
4253
}
4354
}
4455

AiCodeGraph.Tests/TempDirectoryFixture.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ public virtual void Dispose()
2424
return;
2525

2626
// On Windows, SQLite WAL mode keeps files locked briefly after disposal
27-
// Retry deletion with delays to allow locks to be released
27+
// Clear connection pools and retry deletion with delays to allow locks to be released
28+
Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools();
29+
2830
var attempts = 0;
29-
var maxAttempts = 10;
30-
var delay = 50; // ms
31+
var maxAttempts = 20; // Increased for Windows
32+
var delay = 100; // Start with 100ms
3133

3234
while (attempts < maxAttempts)
3335
{
@@ -38,6 +40,8 @@ public virtual void Dispose()
3840
{
3941
GC.Collect();
4042
GC.WaitForPendingFinalizers();
43+
GC.Collect(); // Second GC to clean up finalizer queue
44+
Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools();
4145
Thread.Sleep(delay);
4246
}
4347

@@ -47,7 +51,7 @@ public virtual void Dispose()
4751
catch (IOException) when (attempts < maxAttempts - 1)
4852
{
4953
attempts++;
50-
delay *= 2; // Exponential backoff
54+
delay = Math.Min(delay * 2, 2000); // Cap at 2 seconds
5155
}
5256
}
5357

0 commit comments

Comments
 (0)