Permalink
Browse files

DataProviderPluginFacade - refactoring and removing excessive locking…

… that limits website performance when using XmlDataProvider
  • Loading branch information...
napernik committed Nov 13, 2017
1 parent 6f26ee6 commit 4afc17e949dadfe49efd6d46c5ed6e7eb32cdad1
Showing with 41 additions and 84 deletions.
  1. +41 −84 Composite/Data/Foundation/PluginFacades/DataProviderPluginFacade.cs
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
@@ -19,8 +19,6 @@ namespace Composite.Data.Foundation.PluginFacades
{
internal static class DataProviderPluginFacade
{
internal static string UnittestDataProviderName { get { return "FallbackUnittestMemoryDataProvider"; } }
private static readonly ResourceLocker<Resources> _resourceLocker = new ResourceLocker<Resources>(new Resources(), Resources.Initialize);
internal static Func<IDataProviderFactory> DataProviderFactoryCreationDelegate = () => new ConfigurationDataProviderFactory();
@@ -35,8 +33,7 @@ static DataProviderPluginFacade()
public static bool HasConfiguration()
{
return ConfigurationServices.ConfigurationSource != null &&
ConfigurationServices.ConfigurationSource.GetSection(DataProviderSettings.SectionName) != null;
return ConfigurationServices.ConfigurationSource?.GetSection(DataProviderSettings.SectionName) != null;
}
@@ -67,7 +64,7 @@ public static IEnumerable<Type> GetKnownInterfaces(string providerName)
if (knownInterfaces.Contains(null))
{
Log.LogWarning("DataProviderPluginFacade", "Data Provider '{0}' returned (null) as a known interface type. Value is ignored.", providerName);
Log.LogWarning(nameof(DataProviderPluginFacade), $"Data Provider '{providerName}' returned (null) as a known interface type. Value is ignored.");
knownInterfaces.RemoveAll(f => f == null);
}
@@ -96,7 +93,7 @@ public static IQueryable<T> GetData<T>(string providerName)
{
using (TimerProfilerFacade.CreateTimerProfiler())
{
return SyncronizedCall<IDataProvider, IQueryable<T>>(providerName, provider => provider.GetData<T>());
return Call<IDataProvider, IQueryable<T>>(providerName, provider => provider.GetData<T>());
}
}
@@ -109,7 +106,7 @@ public static T GetData<T>(string providerName, IDataId dataId)
using (TimerProfilerFacade.CreateTimerProfiler())
{
return SyncronizedCall<IDataProvider, T>(providerName, provider => provider.GetData<T>(dataId));
return Call<IDataProvider, T>(providerName, provider => provider.GetData<T>(dataId));
}
}
@@ -121,9 +118,6 @@ public static void Update(string providerName, IEnumerable<IData> dataset)
using (TimerProfilerFacade.CreateTimerProfiler())
{
IData firstData = dataset.FirstOrDefault();
if (firstData == null) return;
SyncronizedCall<IWritableDataProvider>(providerName, provider => provider.Update(dataset));
}
}
@@ -149,9 +143,6 @@ public static void Delete(string providerName, IEnumerable<DataSourceId> dataSou
using (TimerProfilerFacade.CreateTimerProfiler())
{
DataSourceId firstDataSourceId = dataSourceIds.FirstOrDefault();
if (firstDataSourceId == null) return;
SyncronizedCall<IWritableDataProvider>(providerName, provider => provider.Delete(dataSourceIds));
}
}
@@ -175,7 +166,7 @@ public static bool ValidatePath<TFile>(TFile file, string providerName, out stri
public static void CreateStore(string providerName, DataTypeDescriptor typeDescriptor)
{
CreateStores(providerName, new[] {typeDescriptor});
CreateStores(providerName, new[] { typeDescriptor });
}
public static void CreateStores(string providerName, IReadOnlyCollection<DataTypeDescriptor> typeDescriptors)
@@ -194,7 +185,7 @@ public static void CreateStores(string providerName, IReadOnlyCollection<DataTyp
}
public static void AlterStore(UpdateDataTypeDescriptor updateDataTypeDescriptor, bool forceCompile)
{
using (TimerProfilerFacade.CreateTimerProfiler())
@@ -212,7 +203,7 @@ public static void AlterStore(UpdateDataTypeDescriptor updateDataTypeDescriptor,
public static void DropStore(string providerName, DataTypeDescriptor typeDescriptor)
{
Verify.ArgumentNotNull(typeDescriptor, "typeDescriptor");
using (TimerProfilerFacade.CreateTimerProfiler())
{
using (_resourceLocker.Locker)
@@ -251,27 +242,31 @@ public static void RemoveLocale(string providerName, CultureInfo cultureInfo)
}
}
private delegate void SyncronizedCallDelegate<T>(T provider) where T : class, IDataProvider;
private delegate TResult SyncronizedCallDelegate<T, TResult>(T provider)
where T : class, IDataProvider
where TResult : class;
private static TResult Call<TProvider, TResult>(string providerName, Func<TProvider, TResult> func)
where TProvider : class, IDataProvider
where TResult : class
{
var provider = GetDataProvider(providerName) as TProvider
?? throw new InvalidOperationException($"The data provider '{providerName}' does not implement the interface '{typeof(TProvider).FullName}'");
private static void SyncronizedCall<TProvider>(string providerName, SyncronizedCallDelegate<TProvider> func) where TProvider : class, IDataProvider
return func(provider);
}
private static void SyncronizedCall<TProvider>(string providerName, Action<TProvider> func) where TProvider : class, IDataProvider
{
SyncronizedCall<TProvider, object>(providerName, provider =>
{
func(provider);
return null;
});
{
func(provider);
return null;
});
}
private static TResult SyncronizedCall<TProvider, TResult>(string providerName, SyncronizedCallDelegate<TProvider, TResult> func)
private static TResult SyncronizedCall<TProvider, TResult>(string providerName, Func<TProvider, TResult> func)
where TProvider : class, IDataProvider
where TResult : class
{
IDataProvider provider = GetDataProvider(providerName);
Verify.That(provider is TProvider, "The data provider {0} does not implement the interface {1}", providerName, typeof(TProvider).FullName);
var provider = GetDataProvider(providerName) as TProvider
?? throw new InvalidOperationException($"The data provider '{providerName}' does not implement the interface '{typeof(TProvider).FullName}'");
// DDZ: hardcoded for now, to be fixed
bool syncDisabled = provider is SqlDataProvider;
@@ -284,58 +279,35 @@ public static void RemoveLocale(string providerName, CultureInfo cultureInfo)
scope = _resourceLocker.Locker;
}
return (TResult)func(provider as TProvider);
return func(provider);
}
finally
{
if (scope != null)
{
scope.Dispose();
}
scope?.Dispose();
}
}
public static bool IsWriteableProvider(string providerName)
{
var dataProvider = GetDataProvider(providerName);
return (dataProvider is IWritableDataProvider);
return GetDataProvider(providerName) is IWritableDataProvider;
}
public static bool IsDynamicProvider(string providerName)
{
var dataProvider = GetDataProvider(providerName);
return (dataProvider is IDynamicDataProvider);
return GetDataProvider(providerName) is IDynamicDataProvider;
}
public static bool IsGeneratedTypesProvider(string providerName)
{
using (TimerProfilerFacade.CreateTimerProfiler())
{
using (_resourceLocker.Locker)
{
var dataProvider = GetDataProvider(providerName);
return (dataProvider is IGeneratedTypesDataProvider);
}
}
return GetDataProvider(providerName) is IGeneratedTypesDataProvider;
}
public static bool IsLocalizedDataProvider(string providerName)
{
using (TimerProfilerFacade.CreateTimerProfiler())
{
using (_resourceLocker.Locker)
{
var dataProvider = GetDataProvider(providerName);
return (dataProvider is ILocalizedDataProvider);
}
}
return GetDataProvider(providerName) is ILocalizedDataProvider;
}
/// <summary>
@@ -346,22 +318,15 @@ public static bool AllowsResultsWrapping(string providerName)
{
var dataProvider = GetDataProvider(providerName);
return dataProvider != null
&& (!(dataProvider is ISupportCachingDataProvider)
|| (dataProvider as ISupportCachingDataProvider).AllowResultsWrapping);
return (dataProvider as ISupportCachingDataProvider)?.AllowResultsWrapping ?? true;
}
private static T GetDataProvider<T>(string providerName) where T: class, IDataProvider
private static T GetDataProvider<T>(string providerName) where T : class, IDataProvider
{
var provider = GetDataProvider(providerName) as T;
if (provider == null)
{
throw new InvalidOperationException(string.Format("The data provider {0} does not implement the interface {1}", providerName, typeof(T)));
}
return provider;
return provider ?? throw new InvalidOperationException($"The data provider '{providerName}' does not implement the interface '{typeof(T)}'"); ;
}
@@ -391,11 +356,7 @@ internal static IDataProvider GetDataProvider(string providerName)
_resourceLocker.Resources.ProviderCache.Add(providerName, dataProvider);
}
catch (ArgumentException ex)
{
HandleConfigurationError(ex);
}
catch (ConfigurationErrorsException ex)
catch (Exception ex) when (ex is ArgumentException || ex is ConfigurationErrorsException)
{
HandleConfigurationError(ex);
}
@@ -415,27 +376,23 @@ private static void HandleConfigurationError(Exception ex)
{
Flush();
throw new ConfigurationErrorsException(string.Format("Failed to load the configuration section '{0}' from the configuration.", DataProviderSettings.SectionName), ex);
}
throw new ConfigurationErrorsException($"Failed to load the configuration section '{DataProviderSettings.SectionName}' from the configuration.", ex);
}
private sealed class Resources
{
public IDataProviderFactory Factory { get; set; }
public Hashtable<string, IDataProvider> ProviderCache { get; set; }
public IDataProviderFactory Factory { get; private set; }
public Hashtable<string, IDataProvider> ProviderCache { get; private set; }
public static void Initialize(Resources resources)
{
try
{
resources.Factory = DataProviderFactoryCreationDelegate();
}
catch (NullReferenceException ex)
{
HandleConfigurationError(ex);
}
catch (ConfigurationErrorsException ex)
catch (Exception ex) when (ex is NullReferenceException || ex is ConfigurationErrorsException)
{
HandleConfigurationError(ex);
}
@@ -444,4 +401,4 @@ public static void Initialize(Resources resources)
}
}
}
}
}

1 comment on commit 4afc17e

@burningice2866

This comment has been minimized.

Show comment
Hide comment
@burningice2866

burningice2866 Nov 13, 2017

Contributor

+1

Contributor

burningice2866 commented on 4afc17e Nov 13, 2017

+1

Please sign in to comment.