Skip to content

Commit 6157b3c

Browse files
committed
Increase delay to prevent busy. Prevent using config when no config option is used. Update config option to match doc.
1 parent 1428e5c commit 6157b3c

File tree

5 files changed

+102
-9
lines changed

5 files changed

+102
-9
lines changed

SQLite.Net.Tests/SQLite.Net2.Tests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
<IsPackable>false</IsPackable>
77

88
<LangVersion>latest</LangVersion>
9+
10+
<Nullable>enable</Nullable>
911
</PropertyGroup>
1012

1113
<ItemGroup>

SQLite.Net.Tests/TransactionTest.cs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Threading.Tasks;
45
using NUnit.Framework;
56

67

@@ -51,7 +52,7 @@ public class TransactionTestException : Exception
5152
public class TestDb : SQLiteConnection
5253
{
5354
public TestDb(String path)
54-
: base(path)
55+
: base(path, busyTimeout: TimeSpan.FromSeconds(10))
5556
{
5657
CreateTable<TestObj>();
5758
}
@@ -170,5 +171,55 @@ public void SuccesfulSavepointTransaction()
170171
dbb.InsertOrReplaceAll(testObjects);
171172
});
172173
}
174+
175+
[Test]
176+
public async Task LockedTransaction()
177+
{
178+
var newObjects = Enumerable.Range(1, 1000000).Select(i => new TestObj()).ToList();
179+
180+
Exception? lastException = null;
181+
var hasFinished = false;
182+
183+
184+
var t1 = Task.Run(() =>
185+
{
186+
try
187+
{
188+
db.InsertAll(newObjects);
189+
}
190+
catch (Exception e)
191+
{
192+
lastException = e;
193+
}
194+
195+
hasFinished = true;
196+
});
197+
198+
199+
var t2 = Task.Run(() =>
200+
{
201+
try
202+
{
203+
for (var i = 0; i < 10000; i++)
204+
{
205+
_ = db.Table<TestObj>().ToList();
206+
if(hasFinished)
207+
break;
208+
}
209+
210+
var obj = db.Table<TestObj>().FirstOrDefault(o => o.Id == 8);
211+
Assert.IsNotNull(obj);
212+
obj.Toto = 12;
213+
db.Update(obj);
214+
}
215+
catch (Exception e)
216+
{
217+
lastException = e;
218+
}
219+
});
220+
221+
await Task.WhenAll(t1, t2);
222+
Assert.IsNull(lastException, lastException?.Message);
223+
}
173224
}
174225
}

nuget/pack.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ if ($IsMacOS) {
77
$msbuild = join-path $msbuild 'MSBuild\Current\Bin\MSBuild.exe'
88
}
99
$version="2.1.0"
10-
$versionSuffix="-preA"
10+
$versionSuffix="-preB"
1111

1212
#####################
1313
#Build release config

src/SQLite.Net/Interop/SQLiteOpenFlags.cs

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,57 @@
2424

2525
namespace SQLite.Net2
2626
{
27+
/// <summary>
28+
/// https://www.sqlite.org/c3ref/open.html
29+
/// </summary>
2730
[Flags]
2831
public enum SQLiteOpenFlags
2932
{
3033
ReadOnly = 1,
3134
ReadWrite = 2,
3235
Create = 4,
36+
37+
/// <summary>
38+
/// The filename can be interpreted as a URI
39+
/// See https://www.sqlite.org/c3ref/open.html
40+
/// </summary>
41+
OpenUri = 0x40,
42+
/// <summary>
43+
/// The database will be opened as an in-memory database. The database is named by the "filename" argument for the purposes of cache-sharing, if shared cache mode is enabled, but the "filename" is otherwise ignored.
44+
/// </summary>
45+
OpenMemory = 0x80,
46+
47+
/// <summary>
48+
/// The new database connection will use the "multi-thread" threading mode.
49+
/// This means that separate threads are allowed to use SQLite at the same time, as long as each thread is using a different database connection.
50+
/// </summary>
3351
NoMutex = 0x8000,
52+
/// <summary>
53+
/// The new database connection will use the "serialized" threading mode.
54+
/// This means the multiple threads can safely attempt to use the same database connection at the same time.
55+
/// (Mutexes will block any actual concurrency, but in this mode there is no harm in trying.)
56+
/// </summary>
3457
FullMutex = 0x10000,
58+
3559
SharedCache = 0x20000,
3660
PrivateCache = 0x40000,
37-
ProtectionComplete = 0x00100000,
38-
ProtectionCompleteUnlessOpen = 0x00200000,
39-
ProtectionCompleteUntilFirstUserAuthentication = 0x00300000,
40-
ProtectionNone = 0x00400000
61+
62+
/// <summary>
63+
/// The database filename is not allowed to be a symbolic link
64+
/// </summary>
65+
NoFollow = 0x100000,
66+
/// <summary>
67+
/// The database connection comes up in "extended result code mode". In other words, the database behaves has if sqlite3_extended_result_codes(db,1) where called on the database connection as soon as the connection is created. In addition to setting the extended result code mode, this flag also causes sqlite3_open_v2() to return an extended result code
68+
/// </summary>
69+
ExResCode = 0x02000000,
70+
71+
[Obsolete]
72+
ProtectionComplete = 0x100000,
73+
[Obsolete]
74+
ProtectionCompleteUnlessOpen = 0x200000,
75+
[Obsolete]
76+
ProtectionCompleteUntilFirstUserAuthentication = 0x300000,
77+
[Obsolete]
78+
ProtectionNone = 0x400000
4179
}
4280
}

src/SQLite.Net/SQLiteConnection.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ public virtual SQLiteConnection Clone()
114114
/// <param name="busyTimeout">
115115
/// Sets a busy handler to sleep the specified amount of time when a table is locked.
116116
/// The handler will sleep multiple times until a total time of busyTimeout has accumulated.
117-
/// Default to 1s
117+
/// Default to 10s
118118
/// </param>
119119
public SQLiteConnection(string databasePath, SQLiteOpenFlags openFlags = SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create, bool storeDateTimeAsTicks = true, IBlobSerializer? serializer = null, IDictionary<string, TableMapping>? tableMappings = null,
120120
IDictionary<Type, string>? extraTypeMappings = null, IContractResolver? resolver = null, string? encryptionKey = null, ConfigOption configOption = ConfigOption.Serialized, TimeSpan? busyTimeout = null)
@@ -130,7 +130,9 @@ public SQLiteConnection(string databasePath, SQLiteOpenFlags openFlags = SQLiteO
130130
if (configOption > ConfigOption.SingleThread && sqlite.Threadsafe() == 0)
131131
throw new ArgumentException("SQlite is not compiled with multithread and config option is set to multithread", nameof(configOption));
132132

133-
sqlite.Config(configOption);
133+
if(configOption > ConfigOption.Unknown)
134+
sqlite.Config(configOption);
135+
134136
sqlite.Initialize();
135137
}
136138

@@ -154,7 +156,7 @@ public SQLiteConnection(string databasePath, SQLiteOpenFlags openFlags = SQLiteO
154156
throw new Exception("Invalid cipher key");
155157
}
156158

157-
BusyTimeout = busyTimeout ?? TimeSpan.FromSeconds(1);
159+
BusyTimeout = busyTimeout ?? TimeSpan.FromSeconds(10);
158160
Serializer = serializer;
159161
StoreDateTimeAsTicks = storeDateTimeAsTicks;
160162
ExtraTypeMappings = extraTypeMappings ?? new Dictionary<Type, string>();

0 commit comments

Comments
 (0)