< Summary - Jellyfin

Information
Class: Emby.Server.Implementations.Data.BaseSqliteRepository
Assembly: Emby.Server.Implementations
File(s): /srv/git/jellyfin/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
Line coverage
95%
Covered lines: 81
Uncovered lines: 4
Coverable lines: 85
Total lines: 269
Line coverage: 95.2%
Branch coverage
90%
Covered branches: 38
Total branches: 42
Branch coverage: 90.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_CacheSize()100%11100%
get_LockingMode()100%11100%
get_JournalMode()100%11100%
get_JournalSizeLimit()100%11100%
get_PageSize()100%11100%
get_TempStore()100%11100%
get_Synchronous()100%11100%
Initialize()100%11100%
GetConnection(...)92.85%282894.44%
PrepareStatement(...)100%11100%
TableExists(...)75%4483.33%
GetColumnNames(...)100%44100%
AddColumn(...)100%22100%
CheckDisposed()100%11100%
Dispose()100%11100%
Dispose(...)75%4492.3%

File(s)

/srv/git/jellyfin/Emby.Server.Implementations/Data/BaseSqliteRepository.cs

#LineLine coverage
 1#nullable disable
 2
 3#pragma warning disable CS1591
 4
 5using System;
 6using System.Collections.Generic;
 7using System.Threading;
 8using Jellyfin.Extensions;
 9using Microsoft.Data.Sqlite;
 10using Microsoft.Extensions.Logging;
 11
 12namespace Emby.Server.Implementations.Data
 13{
 14    public abstract class BaseSqliteRepository : IDisposable
 15    {
 16        private bool _disposed = false;
 6617        private SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1);
 18        private SqliteConnection _writeConnection;
 19
 20        /// <summary>
 21        /// Initializes a new instance of the <see cref="BaseSqliteRepository"/> class.
 22        /// </summary>
 23        /// <param name="logger">The logger.</param>
 24        protected BaseSqliteRepository(ILogger<BaseSqliteRepository> logger)
 25        {
 26            Logger = logger;
 6627        }
 28
 29        /// <summary>
 30        /// Gets or sets the path to the DB file.
 31        /// </summary>
 32        protected string DbFilePath { get; set; }
 33
 34        /// <summary>
 35        /// Gets the logger.
 36        /// </summary>
 37        /// <value>The logger.</value>
 38        protected ILogger<BaseSqliteRepository> Logger { get; }
 39
 40        /// <summary>
 41        /// Gets the cache size.
 42        /// </summary>
 43        /// <value>The cache size or null.</value>
 2344        protected virtual int? CacheSize => null;
 45
 46        /// <summary>
 47        /// Gets the locking mode. <see href="https://www.sqlite.org/pragma.html#pragma_locking_mode" />.
 48        /// </summary>
 132849        protected virtual string LockingMode => "NORMAL";
 50
 51        /// <summary>
 52        /// Gets the journal mode. <see href="https://www.sqlite.org/pragma.html#pragma_journal_mode" />.
 53        /// </summary>
 54        /// <value>The journal mode.</value>
 132855        protected virtual string JournalMode => "WAL";
 56
 57        /// <summary>
 58        /// Gets the journal size limit. <see href="https://www.sqlite.org/pragma.html#pragma_journal_size_limit" />.
 59        /// The default (-1) is overridden to prevent unconstrained WAL size, as reported by users.
 60        /// </summary>
 61        /// <value>The journal size limit.</value>
 132862        protected virtual int? JournalSizeLimit => 134_217_728; // 128MiB
 63
 64        /// <summary>
 65        /// Gets the page size.
 66        /// </summary>
 67        /// <value>The page size or null.</value>
 66468        protected virtual int? PageSize => null;
 69
 70        /// <summary>
 71        /// Gets the temp store mode.
 72        /// </summary>
 73        /// <value>The temp store mode.</value>
 74        /// <see cref="TempStoreMode"/>
 2375        protected virtual TempStoreMode TempStore => TempStoreMode.Memory;
 76
 77        /// <summary>
 78        /// Gets the synchronous mode.
 79        /// </summary>
 80        /// <value>The synchronous mode or null.</value>
 81        /// <see cref="SynchronousMode"/>
 132882        protected virtual SynchronousMode? Synchronous => SynchronousMode.Normal;
 83
 84        public virtual void Initialize()
 85        {
 86            // Configuration and pragmas can affect VACUUM so it needs to be last.
 4287            using (var connection = GetConnection())
 88            {
 4289                connection.Execute("VACUUM");
 4290            }
 4291        }
 92
 93        protected ManagedConnection GetConnection(bool readOnly = false)
 94        {
 78295            if (!readOnly)
 96            {
 16097                _writeLock.Wait();
 16098                if (_writeConnection is not null)
 99                {
 118100                    return new ManagedConnection(_writeConnection, _writeLock);
 101                }
 102
 42103                var writeConnection = new SqliteConnection($"Filename={DbFilePath};Pooling=False");
 42104                writeConnection.Open();
 105
 42106                if (CacheSize.HasValue)
 107                {
 21108                    writeConnection.Execute("PRAGMA cache_size=" + CacheSize.Value);
 109                }
 110
 42111                if (!string.IsNullOrWhiteSpace(LockingMode))
 112                {
 42113                    writeConnection.Execute("PRAGMA locking_mode=" + LockingMode);
 114                }
 115
 42116                if (!string.IsNullOrWhiteSpace(JournalMode))
 117                {
 42118                    writeConnection.Execute("PRAGMA journal_mode=" + JournalMode);
 119                }
 120
 42121                if (JournalSizeLimit.HasValue)
 122                {
 42123                    writeConnection.Execute("PRAGMA journal_size_limit=" + JournalSizeLimit.Value);
 124                }
 125
 42126                if (Synchronous.HasValue)
 127                {
 42128                    writeConnection.Execute("PRAGMA synchronous=" + (int)Synchronous.Value);
 129                }
 130
 42131                if (PageSize.HasValue)
 132                {
 0133                    writeConnection.Execute("PRAGMA page_size=" + PageSize.Value);
 134                }
 135
 42136                writeConnection.Execute("PRAGMA temp_store=" + (int)TempStore);
 137
 42138                return new ManagedConnection(_writeConnection = writeConnection, _writeLock);
 139            }
 140
 622141            var connection = new SqliteConnection($"Filename={DbFilePath};Mode=ReadOnly");
 622142            connection.Open();
 143
 622144            if (CacheSize.HasValue)
 145            {
 620146                connection.Execute("PRAGMA cache_size=" + CacheSize.Value);
 147            }
 148
 622149            if (!string.IsNullOrWhiteSpace(LockingMode))
 150            {
 622151                connection.Execute("PRAGMA locking_mode=" + LockingMode);
 152            }
 153
 622154            if (!string.IsNullOrWhiteSpace(JournalMode))
 155            {
 622156                connection.Execute("PRAGMA journal_mode=" + JournalMode);
 157            }
 158
 622159            if (JournalSizeLimit.HasValue)
 160            {
 622161                connection.Execute("PRAGMA journal_size_limit=" + JournalSizeLimit.Value);
 162            }
 163
 622164            if (Synchronous.HasValue)
 165            {
 622166                connection.Execute("PRAGMA synchronous=" + (int)Synchronous.Value);
 167            }
 168
 622169            if (PageSize.HasValue)
 170            {
 0171                connection.Execute("PRAGMA page_size=" + PageSize.Value);
 172            }
 173
 622174            connection.Execute("PRAGMA temp_store=" + (int)TempStore);
 175
 622176            return new ManagedConnection(connection, null);
 177        }
 178
 179        public SqliteCommand PrepareStatement(ManagedConnection connection, string sql)
 180        {
 788181            var command = connection.CreateCommand();
 788182            command.CommandText = sql;
 788183            return command;
 184        }
 185
 186        protected bool TableExists(ManagedConnection connection, string name)
 187        {
 42188            using var statement = PrepareStatement(connection, "select DISTINCT tbl_name from sqlite_master");
 672189            foreach (var row in statement.ExecuteQuery())
 190            {
 294191                if (string.Equals(name, row.GetString(0), StringComparison.OrdinalIgnoreCase))
 192                {
 0193                    return true;
 194                }
 195            }
 196
 42197            return false;
 42198        }
 199
 200        protected List<string> GetColumnNames(ManagedConnection connection, string table)
 201        {
 105202            var columnNames = new List<string>();
 203
 2814204            foreach (var row in connection.Query("PRAGMA table_info(" + table + ")"))
 205            {
 1302206                if (row.TryGetString(1, out var columnName))
 207                {
 1302208                    columnNames.Add(columnName);
 209                }
 210            }
 211
 105212            return columnNames;
 213        }
 214
 215        protected void AddColumn(ManagedConnection connection, string table, string columnName, string type, List<string
 216        {
 2121217            if (existingColumnNames.Contains(columnName, StringComparison.OrdinalIgnoreCase))
 218            {
 588219                return;
 220            }
 221
 1533222            connection.Execute("alter table " + table + " add column " + columnName + " " + type + " NULL");
 1533223        }
 224
 225        protected void CheckDisposed()
 226        {
 791227            ObjectDisposedException.ThrowIf(_disposed, this);
 791228        }
 229
 230        /// <inheritdoc />
 231        public void Dispose()
 232        {
 42233            Dispose(true);
 42234            GC.SuppressFinalize(this);
 42235        }
 236
 237        /// <summary>
 238        /// Releases unmanaged and - optionally - managed resources.
 239        /// </summary>
 240        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release o
 241        protected virtual void Dispose(bool dispose)
 242        {
 42243            if (_disposed)
 244            {
 0245                return;
 246            }
 247
 42248            if (dispose)
 249            {
 42250                _writeLock.Wait();
 251                try
 252                {
 42253                    _writeConnection.Dispose();
 42254                }
 255                finally
 256                {
 42257                    _writeLock.Release();
 42258                }
 259
 42260                _writeLock.Dispose();
 261            }
 262
 42263            _writeConnection = null;
 42264            _writeLock = null;
 265
 42266            _disposed = true;
 42267        }
 268    }
 269}