persist provider results

This commit is contained in:
Luke Pulverenti
2014-01-29 00:17:58 -05:00
parent d864ed87f5
commit 81d5e9f808
20 changed files with 477 additions and 206 deletions

View File

@@ -56,21 +56,6 @@ namespace MediaBrowser.Server.Implementations.IO
_tempIgnoredPaths[path] = path;
}
/// <summary>
/// Removes the temp ignore.
/// </summary>
/// <param name="path">The path.</param>
private async void RemoveTempIgnore(string path)
{
// This is an arbitraty amount of time, but delay it because file system writes often trigger events after RemoveTempIgnore has been called.
// Seeing long delays in some situations, especially over the network.
// Seeing delays up to 40 seconds, but not going to ignore changes for that long.
await Task.Delay(1500).ConfigureAwait(false);
string val;
_tempIgnoredPaths.TryRemove(path, out val);
}
public void ReportFileSystemChangeBeginning(string path)
{
if (string.IsNullOrEmpty(path))
@@ -81,14 +66,20 @@ namespace MediaBrowser.Server.Implementations.IO
TemporarilyIgnore(path);
}
public void ReportFileSystemChangeComplete(string path, bool refreshPath)
public async void ReportFileSystemChangeComplete(string path, bool refreshPath)
{
if (string.IsNullOrEmpty(path))
{
throw new ArgumentNullException("path");
}
RemoveTempIgnore(path);
// This is an arbitraty amount of time, but delay it because file system writes often trigger events after RemoveTempIgnore has been called.
// Seeing long delays in some situations, especially over the network.
// Seeing delays up to 40 seconds, but not going to ignore changes for that long.
await Task.Delay(1500).ConfigureAwait(false);
string val;
_tempIgnoredPaths.TryRemove(path, out val);
if (refreshPath)
{

View File

@@ -58,7 +58,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
private SqliteChapterRepository _chapterRepository;
private SqliteMediaStreamsRepository _mediaStreamsRepository;
private SqliteProviderInfoRepository _providerInfoRepository;
private IDbCommand _deleteChildrenCommand;
private IDbCommand _saveChildrenCommand;
@@ -99,10 +98,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
var mediaStreamsDbFile = Path.Combine(_appPaths.DataPath, "mediainfo.db");
var mediaStreamsConnection = SqliteExtensions.ConnectToDb(mediaStreamsDbFile, _logger).Result;
_mediaStreamsRepository = new SqliteMediaStreamsRepository(mediaStreamsConnection, logManager);
var providerInfosDbFile = Path.Combine(_appPaths.DataPath, "providerinfo.db");
var providerInfoConnection = SqliteExtensions.ConnectToDb(providerInfosDbFile, _logger).Result;
_providerInfoRepository = new SqliteProviderInfoRepository(providerInfoConnection, logManager);
}
/// <summary>
@@ -134,7 +129,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
PrepareStatements();
_mediaStreamsRepository.Initialize();
_providerInfoRepository.Initialize();
_chapterRepository.Initialize();
_shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
@@ -436,12 +430,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
_mediaStreamsRepository.Dispose();
_mediaStreamsRepository = null;
}
if (_providerInfoRepository != null)
{
_providerInfoRepository.Dispose();
_providerInfoRepository = null;
}
}
}
catch (Exception ex)
@@ -556,15 +544,5 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
return _mediaStreamsRepository.SaveMediaStreams(id, streams, cancellationToken);
}
public IEnumerable<BaseProviderInfo> GetProviderHistory(Guid itemId)
{
return _providerInfoRepository.GetBaseProviderInfos(itemId);
}
public Task SaveProviderHistory(Guid id, IEnumerable<BaseProviderInfo> history, CancellationToken cancellationToken)
{
return _providerInfoRepository.SaveProviderInfos(id, history, cancellationToken);
}
}
}

View File

@@ -1,4 +1,6 @@
using MediaBrowser.Controller.Providers;
using System.IO;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
@@ -9,7 +11,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.Persistence
{
class SqliteProviderInfoRepository
public class SqliteProviderInfoRepository : IProviderRepository
{
private IDbConnection _connection;
@@ -17,32 +19,47 @@ namespace MediaBrowser.Server.Implementations.Persistence
private IDbCommand _deleteInfosCommand;
private IDbCommand _saveInfoCommand;
private IDbCommand _saveStatusCommand;
private readonly IApplicationPaths _appPaths;
public SqliteProviderInfoRepository(IDbConnection connection, ILogManager logManager)
public SqliteProviderInfoRepository(IApplicationPaths appPaths, ILogManager logManager)
{
_connection = connection;
_appPaths = appPaths;
_logger = logManager.GetLogger(GetType().Name);
}
private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
/// <summary>
/// Gets the name of the repository
/// </summary>
/// <value>The name.</value>
public string Name
{
get
{
return "SQLite";
}
}
/// <summary>
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
public void Initialize()
public async Task Initialize()
{
var createTableCommand
= "create table if not exists providerinfos ";
var dbFile = Path.Combine(_appPaths.DataPath, "providerinfo.db");
createTableCommand += "(ItemId GUID, ProviderId GUID, ProviderVersion TEXT, FileStamp GUID, LastRefreshStatus TEXT, LastRefreshed datetime, PRIMARY KEY (ItemId, ProviderId))";
_connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
string[] queries = {
createTableCommand,
"create table if not exists providerinfos (ItemId GUID, ProviderId GUID, ProviderVersion TEXT, FileStamp GUID, LastRefreshStatus TEXT, LastRefreshed datetime, PRIMARY KEY (ItemId, ProviderId))",
"create index if not exists idx_providerinfos on providerinfos(ItemId, ProviderId)",
"create table if not exists MetadataStatus (ItemId GUID PRIMARY KEY, DateLastMetadataRefresh datetime, DateLastImagesRefresh datetime, LastStatus TEXT, LastErrorMessage TEXT, MetadataProvidersRefreshed TEXT, ImageProvidersRefreshed TEXT)",
"create index if not exists idx_MetadataStatus on MetadataStatus(ItemId)",
//pragmas
"pragma temp_store = memory",
@@ -56,7 +73,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
_shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
}
private static readonly string[] SaveColumns =
private static readonly string[] SaveHistoryColumns =
{
"ItemId",
"ProviderId",
@@ -66,7 +83,18 @@ namespace MediaBrowser.Server.Implementations.Persistence
"LastRefreshed"
};
private readonly string[] _selectColumns = SaveColumns.Skip(1).ToArray();
private readonly string[] _historySelectColumns = SaveHistoryColumns.Skip(1).ToArray();
private static readonly string[] StatusColumns =
{
"ItemId",
"DateLastMetadataRefresh",
"DateLastImagesRefresh",
"LastStatus",
"LastErrorMessage",
"MetadataProvidersRefreshed",
"ImageProvidersRefreshed"
};
/// <summary>
/// The _write lock
@@ -85,16 +113,27 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveInfoCommand = _connection.CreateCommand();
_saveInfoCommand.CommandText = string.Format("replace into providerinfos ({0}) values ({1})",
string.Join(",", SaveColumns),
string.Join(",", SaveColumns.Select(i => "@" + i).ToArray()));
string.Join(",", SaveHistoryColumns),
string.Join(",", SaveHistoryColumns.Select(i => "@" + i).ToArray()));
foreach (var col in SaveColumns)
foreach (var col in SaveHistoryColumns)
{
_saveInfoCommand.Parameters.Add(_saveInfoCommand, "@" + col);
}
_saveStatusCommand = _connection.CreateCommand();
_saveStatusCommand.CommandText = string.Format("replace into MetadataStatus ({0}) values ({1})",
string.Join(",", StatusColumns),
string.Join(",", StatusColumns.Select(i => "@" + i).ToArray()));
foreach (var col in StatusColumns)
{
_saveStatusCommand.Parameters.Add(_saveStatusCommand, "@" + col);
}
}
public IEnumerable<BaseProviderInfo> GetBaseProviderInfos(Guid itemId)
public IEnumerable<BaseProviderInfo> GetProviderHistory(Guid itemId)
{
if (itemId == Guid.Empty)
{
@@ -103,7 +142,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
using (var cmd = _connection.CreateCommand())
{
var cmdText = "select " + string.Join(",", _selectColumns) + " from providerinfos where";
var cmdText = "select " + string.Join(",", _historySelectColumns) + " from providerinfos where";
cmdText += " ItemId=@ItemId";
cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = itemId;
@@ -121,10 +160,10 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
/// <summary>
/// Gets the chapter.
/// Gets the base provider information.
/// </summary>
/// <param name="reader">The reader.</param>
/// <returns>ChapterInfo.</returns>
/// <returns>BaseProviderInfo.</returns>
private BaseProviderInfo GetBaseProviderInfo(IDataReader reader)
{
var item = new BaseProviderInfo
@@ -144,7 +183,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
return item;
}
public async Task SaveProviderInfos(Guid id, IEnumerable<BaseProviderInfo> infos, CancellationToken cancellationToken)
public async Task SaveProviderHistory(Guid id, IEnumerable<BaseProviderInfo> infos, CancellationToken cancellationToken)
{
if (id == Guid.Empty)
{
@@ -166,7 +205,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
transaction = _connection.BeginTransaction();
// First delete chapters
_deleteInfosCommand.GetParameter(0).Value = id;
_deleteInfosCommand.Transaction = transaction;
@@ -221,6 +259,136 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
public MetadataStatus GetMetadataStatus(Guid itemId)
{
if (itemId == Guid.Empty)
{
throw new ArgumentNullException("itemId");
}
using (var cmd = _connection.CreateCommand())
{
var cmdText = "select " + string.Join(",", StatusColumns) + " from MetadataStatus where";
cmdText += " ItemId=@ItemId";
cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = itemId;
cmd.CommandText = cmdText;
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
{
while (reader.Read())
{
return GetStatus(reader);
}
return null;
}
}
}
private MetadataStatus GetStatus(IDataReader reader)
{
var result = new MetadataStatus
{
ItemId = reader.GetGuid(0)
};
if (!reader.IsDBNull(1))
{
result.DateLastMetadataRefresh = reader.GetDateTime(1).ToUniversalTime();
}
if (!reader.IsDBNull(2))
{
result.DateLastImagesRefresh = reader.GetDateTime(2).ToUniversalTime();
}
if (!reader.IsDBNull(3))
{
result.LastStatus = (ProviderRefreshStatus)Enum.Parse(typeof(ProviderRefreshStatus), reader.GetString(3), true);
}
if (!reader.IsDBNull(4))
{
result.LastErrorMessage = reader.GetString(4);
}
if (!reader.IsDBNull(5))
{
result.MetadataProvidersRefreshed = reader.GetString(5).Split('|').Where(i => !string.IsNullOrEmpty(i)).Select(i => new Guid(i)).ToList();
}
if (!reader.IsDBNull(6))
{
result.ImageProvidersRefreshed = reader.GetString(6).Split('|').Where(i => !string.IsNullOrEmpty(i)).Select(i => new Guid(i)).ToList();
}
return result;
}
public async Task SaveMetadataStatus(MetadataStatus status, CancellationToken cancellationToken)
{
if (status == null)
{
throw new ArgumentNullException("status");
}
cancellationToken.ThrowIfCancellationRequested();
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
IDbTransaction transaction = null;
try
{
transaction = _connection.BeginTransaction();
_saveStatusCommand.GetParameter(0).Value = status.ItemId;
_saveStatusCommand.GetParameter(1).Value = status.DateLastMetadataRefresh;
_saveStatusCommand.GetParameter(2).Value = status.DateLastImagesRefresh;
_saveStatusCommand.GetParameter(3).Value = status.LastStatus.ToString();
_saveStatusCommand.GetParameter(4).Value = status.LastErrorMessage;
_saveStatusCommand.GetParameter(5).Value = string.Join("|", status.MetadataProvidersRefreshed.ToArray());
_saveStatusCommand.GetParameter(6).Value = string.Join("|", status.ImageProvidersRefreshed.ToArray());
_saveStatusCommand.Transaction = transaction;
_saveStatusCommand.ExecuteNonQuery();
transaction.Commit();
}
catch (OperationCanceledException)
{
if (transaction != null)
{
transaction.Rollback();
}
throw;
}
catch (Exception e)
{
_logger.ErrorException("Failed to save provider info:", e);
if (transaction != null)
{
transaction.Rollback();
}
throw;
}
finally
{
if (transaction != null)
{
transaction.Dispose();
}
_writeLock.Release();
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>