< 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%28.132894.44%
PrepareStatement(...)100%11100%
TableExists(...)75%4.07483.33%
GetColumnNames(...)100%44100%
AddColumn(...)100%22100%
CheckDisposed()100%11100%
Dispose()100%11100%
Dispose(...)75%4.01492.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;
 6817        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;
 6827        }
 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>
 2444        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>
 139649        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>
 139655        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>
 139662        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>
 69868        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"/>
 2475        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"/>
 139682        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.
 4487            using (var connection = GetConnection())
 88            {
 4489                connection.Execute("VACUUM");
 4490            }
 4491        }
 92
 93        protected ManagedConnection GetConnection(bool readOnly = false)
 94        {
 82295            if (!readOnly)
 96            {
 16897                _writeLock.Wait();
 16898                if (_writeConnection is not null)
 99                {
 124100                    return new ManagedConnection(_writeConnection, _writeLock);
 101                }
 102
 44103                var writeConnection = new SqliteConnection($"Filename={DbFilePath};Pooling=False");
 44104                writeConnection.Open();
 105
 44106                if (CacheSize.HasValue)
 107                {
 22108                    writeConnection.Execute("PRAGMA cache_size=" + CacheSize.Value);
 109                }
 110
 44111                if (!string.IsNullOrWhiteSpace(LockingMode))
 112                {
 44113                    writeConnection.Execute("PRAGMA locking_mode=" + LockingMode);
 114                }
 115
 44116                if (!string.IsNullOrWhiteSpace(JournalMode))
 117                {
 44118                    writeConnection.Execute("PRAGMA journal_mode=" + JournalMode);
 119                }
 120
 44121                if (JournalSizeLimit.HasValue)
 122                {
 44123                    writeConnection.Execute("PRAGMA journal_size_limit=" + JournalSizeLimit.Value);
 124                }
 125
 44126                if (Synchronous.HasValue)
 127                {
 44128                    writeConnection.Execute("PRAGMA synchronous=" + (int)Synchronous.Value);
 129                }
 130
 44131                if (PageSize.HasValue)
 132                {
 0133                    writeConnection.Execute("PRAGMA page_size=" + PageSize.Value);
 134                }
 135
 44136                writeConnection.Execute("PRAGMA temp_store=" + (int)TempStore);
 137
 44138                return new ManagedConnection(_writeConnection = writeConnection, _writeLock);
 139            }
 140
 654141            var connection = new SqliteConnection($"Filename={DbFilePath};Mode=ReadOnly");
 654142            connection.Open();
 143
 654144            if (CacheSize.HasValue)
 145            {
 652146                connection.Execute("PRAGMA cache_size=" + CacheSize.Value);
 147            }
 148
 654149            if (!string.IsNullOrWhiteSpace(LockingMode))
 150            {
 654151                connection.Execute("PRAGMA locking_mode=" + LockingMode);
 152            }
 153
 654154            if (!string.IsNullOrWhiteSpace(JournalMode))
 155            {
 654156                connection.Execute("PRAGMA journal_mode=" + JournalMode);
 157            }
 158
 654159            if (JournalSizeLimit.HasValue)
 160            {
 654161                connection.Execute("PRAGMA journal_size_limit=" + JournalSizeLimit.Value);
 162            }
 163
 654164            if (Synchronous.HasValue)
 165            {
 654166                connection.Execute("PRAGMA synchronous=" + (int)Synchronous.Value);
 167            }
 168
 654169            if (PageSize.HasValue)
 170            {
 0171                connection.Execute("PRAGMA page_size=" + PageSize.Value);
 172            }
 173
 654174            connection.Execute("PRAGMA temp_store=" + (int)TempStore);
 175
 654176            return new ManagedConnection(connection, null);
 177        }
 178
 179        public SqliteCommand PrepareStatement(ManagedConnection connection, string sql)
 180        {
 828181            var command = connection.CreateCommand();
 828182            command.CommandText = sql;
 828183            return command;
 184        }
 185
 186        protected bool TableExists(ManagedConnection connection, string name)
 187        {
 44188            using var statement = PrepareStatement(connection, "select DISTINCT tbl_name from sqlite_master");
 704189            foreach (var row in statement.ExecuteQuery())
 190            {
 308191                if (string.Equals(name, row.GetString(0), StringComparison.OrdinalIgnoreCase))
 192                {
 0193                    return true;
 194                }
 195            }
 196
 44197            return false;
 44198        }
 199
 200        protected List<string> GetColumnNames(ManagedConnection connection, string table)
 201        {
 110202            var columnNames = new List<string>();
 203
 2948204            foreach (var row in connection.Query("PRAGMA table_info(" + table + ")"))
 205            {
 1364206                if (row.TryGetString(1, out var columnName))
 207                {
 1364208                    columnNames.Add(columnName);
 209                }
 210            }
 211
 110212            return columnNames;
 213        }
 214
 215        protected void AddColumn(ManagedConnection connection, string table, string columnName, string type, List<string
 216        {
 2222217            if (existingColumnNames.Contains(columnName, StringComparison.OrdinalIgnoreCase))
 218            {
 616219                return;
 220            }
 221
 1606222            connection.Execute("alter table " + table + " add column " + columnName + " " + type + " NULL");
 1606223        }
 224
 225        protected void CheckDisposed()
 226        {
 832227            ObjectDisposedException.ThrowIf(_disposed, this);
 832228        }
 229
 230        /// <inheritdoc />
 231        public void Dispose()
 232        {
 44233            Dispose(true);
 44234            GC.SuppressFinalize(this);
 44235        }
 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        {
 44243            if (_disposed)
 244            {
 0245                return;
 246            }
 247
 44248            if (dispose)
 249            {
 44250                _writeLock.Wait();
 251                try
 252                {
 44253                    _writeConnection.Dispose();
 44254                }
 255                finally
 256                {
 44257                    _writeLock.Release();
 44258                }
 259
 44260                _writeLock.Dispose();
 261            }
 262
 44263            _writeConnection = null;
 44264            _writeLock = null;
 265
 44266            _disposed = true;
 44267        }
 268    }
 269}