SqliteProviderInfoRepository.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. using MediaBrowser.Common.Configuration;
  2. using MediaBrowser.Controller.Providers;
  3. using MediaBrowser.Model.Logging;
  4. using System;
  5. using System.Data;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. namespace MediaBrowser.Server.Implementations.Persistence
  12. {
  13. public class SqliteProviderInfoRepository : BaseSqliteRepository, IProviderRepository
  14. {
  15. private IDbConnection _connection;
  16. private IDbCommand _saveStatusCommand;
  17. private readonly IApplicationPaths _appPaths;
  18. public SqliteProviderInfoRepository(ILogManager logManager, IApplicationPaths appPaths) : base(logManager)
  19. {
  20. _appPaths = appPaths;
  21. }
  22. /// <summary>
  23. /// Gets the name of the repository
  24. /// </summary>
  25. /// <value>The name.</value>
  26. public string Name
  27. {
  28. get
  29. {
  30. return "SQLite";
  31. }
  32. }
  33. /// <summary>
  34. /// Opens the connection to the database
  35. /// </summary>
  36. /// <returns>Task.</returns>
  37. public async Task Initialize()
  38. {
  39. var dbFile = Path.Combine(_appPaths.DataPath, "refreshinfo.db");
  40. _connection = await SqliteExtensions.ConnectToDb(dbFile, Logger).ConfigureAwait(false);
  41. string[] queries = {
  42. "create table if not exists MetadataStatus (ItemId GUID PRIMARY KEY, ItemName TEXT, ItemType TEXT, SeriesName TEXT, DateLastMetadataRefresh datetime, DateLastImagesRefresh datetime, LastErrorMessage TEXT, ItemDateModified DateTimeNull)",
  43. "create index if not exists idx_MetadataStatus on MetadataStatus(ItemId)",
  44. //pragmas
  45. "pragma temp_store = memory",
  46. "pragma shrink_memory"
  47. };
  48. _connection.RunQueries(queries, Logger);
  49. AddItemDateModifiedCommand();
  50. PrepareStatements();
  51. }
  52. private static readonly string[] StatusColumns =
  53. {
  54. "ItemId",
  55. "ItemName",
  56. "ItemType",
  57. "SeriesName",
  58. "DateLastMetadataRefresh",
  59. "DateLastImagesRefresh",
  60. "LastErrorMessage",
  61. "ItemDateModified"
  62. };
  63. private void AddItemDateModifiedCommand()
  64. {
  65. using (var cmd = _connection.CreateCommand())
  66. {
  67. cmd.CommandText = "PRAGMA table_info(MetadataStatus)";
  68. using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
  69. {
  70. while (reader.Read())
  71. {
  72. if (!reader.IsDBNull(1))
  73. {
  74. var name = reader.GetString(1);
  75. if (string.Equals(name, "ItemDateModified", StringComparison.OrdinalIgnoreCase))
  76. {
  77. return;
  78. }
  79. }
  80. }
  81. }
  82. }
  83. var builder = new StringBuilder();
  84. builder.AppendLine("alter table MetadataStatus");
  85. builder.AppendLine("add column ItemDateModified DateTime NULL");
  86. _connection.RunQueries(new[] { builder.ToString() }, Logger);
  87. }
  88. /// <summary>
  89. /// Prepares the statements.
  90. /// </summary>
  91. private void PrepareStatements()
  92. {
  93. _saveStatusCommand = _connection.CreateCommand();
  94. _saveStatusCommand.CommandText = string.Format("replace into MetadataStatus ({0}) values ({1})",
  95. string.Join(",", StatusColumns),
  96. string.Join(",", StatusColumns.Select(i => "@" + i).ToArray()));
  97. foreach (var col in StatusColumns)
  98. {
  99. _saveStatusCommand.Parameters.Add(_saveStatusCommand, "@" + col);
  100. }
  101. }
  102. public MetadataStatus GetMetadataStatus(Guid itemId)
  103. {
  104. if (itemId == Guid.Empty)
  105. {
  106. throw new ArgumentNullException("itemId");
  107. }
  108. using (var cmd = _connection.CreateCommand())
  109. {
  110. var cmdText = "select " + string.Join(",", StatusColumns) + " from MetadataStatus where";
  111. cmdText += " ItemId=@ItemId";
  112. cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = itemId;
  113. cmd.CommandText = cmdText;
  114. using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
  115. {
  116. while (reader.Read())
  117. {
  118. return GetStatus(reader);
  119. }
  120. return null;
  121. }
  122. }
  123. }
  124. private MetadataStatus GetStatus(IDataReader reader)
  125. {
  126. var result = new MetadataStatus
  127. {
  128. ItemId = reader.GetGuid(0)
  129. };
  130. if (!reader.IsDBNull(1))
  131. {
  132. result.ItemName = reader.GetString(1);
  133. }
  134. if (!reader.IsDBNull(2))
  135. {
  136. result.ItemName = reader.GetString(2);
  137. }
  138. if (!reader.IsDBNull(3))
  139. {
  140. result.SeriesName = reader.GetString(3);
  141. }
  142. if (!reader.IsDBNull(4))
  143. {
  144. result.DateLastMetadataRefresh = reader.GetDateTime(4).ToUniversalTime();
  145. }
  146. if (!reader.IsDBNull(5))
  147. {
  148. result.DateLastImagesRefresh = reader.GetDateTime(5).ToUniversalTime();
  149. }
  150. if (!reader.IsDBNull(6))
  151. {
  152. result.LastErrorMessage = reader.GetString(6);
  153. }
  154. if (!reader.IsDBNull(7))
  155. {
  156. result.ItemDateModified = reader.GetDateTime(7).ToUniversalTime();
  157. }
  158. return result;
  159. }
  160. public async Task SaveMetadataStatus(MetadataStatus status, CancellationToken cancellationToken)
  161. {
  162. if (status == null)
  163. {
  164. throw new ArgumentNullException("status");
  165. }
  166. cancellationToken.ThrowIfCancellationRequested();
  167. await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false);
  168. IDbTransaction transaction = null;
  169. try
  170. {
  171. transaction = _connection.BeginTransaction();
  172. _saveStatusCommand.GetParameter(0).Value = status.ItemId;
  173. _saveStatusCommand.GetParameter(1).Value = status.ItemName;
  174. _saveStatusCommand.GetParameter(2).Value = status.ItemType;
  175. _saveStatusCommand.GetParameter(3).Value = status.SeriesName;
  176. _saveStatusCommand.GetParameter(4).Value = status.DateLastMetadataRefresh;
  177. _saveStatusCommand.GetParameter(5).Value = status.DateLastImagesRefresh;
  178. _saveStatusCommand.GetParameter(6).Value = status.LastErrorMessage;
  179. _saveStatusCommand.GetParameter(7).Value = status.ItemDateModified;
  180. _saveStatusCommand.Transaction = transaction;
  181. _saveStatusCommand.ExecuteNonQuery();
  182. transaction.Commit();
  183. }
  184. catch (OperationCanceledException)
  185. {
  186. if (transaction != null)
  187. {
  188. transaction.Rollback();
  189. }
  190. throw;
  191. }
  192. catch (Exception e)
  193. {
  194. Logger.ErrorException("Failed to save provider info:", e);
  195. if (transaction != null)
  196. {
  197. transaction.Rollback();
  198. }
  199. throw;
  200. }
  201. finally
  202. {
  203. if (transaction != null)
  204. {
  205. transaction.Dispose();
  206. }
  207. WriteLock.Release();
  208. }
  209. }
  210. protected override void CloseConnection()
  211. {
  212. if (_connection != null)
  213. {
  214. if (_connection.IsOpen())
  215. {
  216. _connection.Close();
  217. }
  218. _connection.Dispose();
  219. _connection = null;
  220. }
  221. }
  222. }
  223. }