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
108
|
using System.Collections.Generic;
using System.Data.Common;
using System.Globalization;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.Logging;
namespace Jellyfin.Database.Providers.Sqlite;
/// <summary>
/// Injects a series of PRAGMA on each connection starts.
/// </summary>
public class PragmaConnectionInterceptor : DbConnectionInterceptor
{
private readonly ILogger _logger;
private readonly int? _cacheSize;
private readonly string _lockingMode;
private readonly int? _journalSizeLimit;
private readonly int _tempStoreMode;
private readonly int _syncMode;
private readonly IDictionary<string, string> _customPragma;
/// <summary>
/// Initializes a new instance of the <see cref="PragmaConnectionInterceptor"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="cacheSize">Cache size.</param>
/// <param name="lockingMode">Locking mode.</param>
/// <param name="journalSizeLimit">Journal Size.</param>
/// <param name="tempStoreMode">The https://sqlite.org/pragma.html#pragma_temp_store pragma.</param>
/// <param name="syncMode">The https://sqlite.org/pragma.html#pragma_synchronous pragma.</param>
/// <param name="customPragma">A list of custom provided Pragma in the list of CustomOptions starting with "#PRAGMA:".</param>
public PragmaConnectionInterceptor(ILogger logger, int? cacheSize, string lockingMode, int? journalSizeLimit, int tempStoreMode, int syncMode, IDictionary<string, string> customPragma)
{
_logger = logger;
_cacheSize = cacheSize;
_lockingMode = lockingMode;
_journalSizeLimit = journalSizeLimit;
_tempStoreMode = tempStoreMode;
_syncMode = syncMode;
_customPragma = customPragma;
InitialCommand = BuildCommandText();
_logger.LogInformation("SQLITE connection pragma command set to: \r\n {PragmaCommand}", InitialCommand);
}
private string? InitialCommand { get; set; }
/// <inheritdoc/>
public override void ConnectionOpened(DbConnection connection, ConnectionEndEventData eventData)
{
base.ConnectionOpened(connection, eventData);
using (var command = connection.CreateCommand())
{
#pragma warning disable CA2100 // Review SQL queries for security vulnerabilities
command.CommandText = InitialCommand;
#pragma warning restore CA2100 // Review SQL queries for security vulnerabilities
command.ExecuteNonQuery();
}
}
/// <inheritdoc/>
public override async Task ConnectionOpenedAsync(DbConnection connection, ConnectionEndEventData eventData, CancellationToken cancellationToken = default)
{
await base.ConnectionOpenedAsync(connection, eventData, cancellationToken).ConfigureAwait(false);
var command = connection.CreateCommand();
await using (command.ConfigureAwait(false))
{
#pragma warning disable CA2100 // Review SQL queries for security vulnerabilities
command.CommandText = InitialCommand;
#pragma warning restore CA2100 // Review SQL queries for security vulnerabilities
await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
}
}
private string BuildCommandText()
{
var sb = new StringBuilder();
if (_cacheSize.HasValue)
{
sb.AppendLine(CultureInfo.InvariantCulture, $"PRAGMA cache_size={_cacheSize.Value};");
}
if (!string.IsNullOrWhiteSpace(_lockingMode))
{
sb.AppendLine(CultureInfo.InvariantCulture, $"PRAGMA locking_mode={_lockingMode};");
}
if (_journalSizeLimit.HasValue)
{
sb.AppendLine(CultureInfo.InvariantCulture, $"PRAGMA journal_size_limit={_journalSizeLimit};");
}
sb.AppendLine(CultureInfo.InvariantCulture, $"PRAGMA synchronous={_syncMode};");
sb.AppendLine(CultureInfo.InvariantCulture, $"PRAGMA temp_store={_tempStoreMode};");
foreach (var item in _customPragma)
{
sb.AppendLine(CultureInfo.InvariantCulture, $"PRAGMA {item.Key}={item.Value};");
}
return sb.ToString();
}
}
|