-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProgram.cs
107 lines (97 loc) · 3.77 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SQLite;
using System.Diagnostics;
using System.Threading;
using Dapper;
using McMaster.Extensions.CommandLineUtils;
namespace SQLiteTest
{
public class Program
{
public static int Main(string[] args) => CommandLineApplication.Execute<Program>(args);
[Option("-c|--connection-string <CONNECTION_STRING>", Description = "Connection String. Defaults to 'Data Source=test.db'")]
public string ConnectionString { get; } = "Data Source=test.db";
[Option("-t|--threads <COUNT>", Description = "Thread Count. Defaults to 8")]
public int ThreadCount { get; } = 8;
[Option("-o|--operations <COUNT>", Description = "Operation Count. Defaults to 1,000")]
public int OperationCount { get; } = 1000;
private void OnExecute()
{
new SQLiteTester(ConnectionString, ThreadCount, OperationCount).Run();
}
}
public class SQLiteTester
{
private readonly string _connectionString;
private readonly int _operationsCount;
private readonly int _threadCount;
private int _errorCount = 0;
public SQLiteTester(string connectionString, int threadCount, int operationCount)
{
Console.WriteLine($"Initialize Database with ConnectionString: '{connectionString}' ...");
var builder = new SQLiteConnectionStringBuilder(connectionString);
_connectionString = builder.ConnectionString;
_threadCount = threadCount;
_operationsCount = operationCount;
using(var conn = CreateConnection())
using(var tx = conn.BeginTransaction())
{
conn.Execute("DROP TABLE IF EXISTS Tests");
conn.Execute("CREATE TABLE IF NOT EXISTS Tests (Id INTEGER PRIMARY KEY, Name TEXT NOT NULL)");
for (var i = 1; i <= _threadCount; i++)
{
conn.Execute("INSERT INTO Tests (Id,Name) VALUES (@Id, @Name)", new { Id = i, Name = "test" });
}
tx.Commit();
}
}
public void Run()
{
Console.WriteLine($"Runing tests with {_threadCount} threads and {_operationsCount:n0} operations-per-thread ...");
var sw = Stopwatch.StartNew();
var workers = new List<Thread>();
for (var i = 1; i <= _threadCount; i++)
{
var id = i; // HACK: prevent captured variable in loop
var worker = new Thread(() => UpdateRecord(id));
workers.Add(worker);
worker.Start();
}
foreach (var worker in workers)
{
worker.Join();
}
sw.Stop();
Console.WriteLine($"Done in {sw.ElapsedMilliseconds:n0} ms with errors: {_errorCount}");
}
private IDbConnection CreateConnection()
{
var conn = new SQLiteConnection(_connectionString);
conn.Open();
return conn;
}
private void UpdateRecord(int id)
{
using(var conn = CreateConnection())
for (var i = 0; i < _operationsCount; i++)
{
try
{
using(var tx = conn.BeginTransaction())
{
conn.Execute(
"UPDATE Tests SET Name = @Name WHERE Id = @Id", new { Name = Guid.NewGuid().ToString(), Id = id });
tx.Commit();
}
}
catch (Exception)
{
Interlocked.Increment(ref _errorCount);
}
}
}
}
}