Faster languages

This commit is contained in:
Stephan
2018-04-11 15:31:21 +02:00
parent 26af63549f
commit 392965bb3a
5 changed files with 68 additions and 8 deletions

View File

@@ -156,7 +156,7 @@ namespace Umbraco.Core.Cache
}
// does NOT clone anything, so be nice with the returned values
private IEnumerable<TEntity> GetAllCached(Func<TId[], IEnumerable<TEntity>> performGetAll)
internal IEnumerable<TEntity> GetAllCached(Func<TId[], IEnumerable<TEntity>> performGetAll)
{
// try the cache first
var all = Cache.GetCacheItem<DeepCloneableList<TEntity>>(GetEntityTypeCacheKey());

View File

@@ -6,5 +6,8 @@ namespace Umbraco.Core.Persistence.Repositories
{
ILanguage GetByCultureName(string cultureName);
ILanguage GetByIsoCode(string isoCode);
int GetIdByIsoCode(string isoCode);
string GetIsoCodeById(int id);
}
}

View File

@@ -18,21 +18,24 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
/// </summary>
internal class LanguageRepository : NPocoRepositoryBase<int, ILanguage>, ILanguageRepository
{
private readonly Dictionary<string, int> _codeIdMap = new Dictionary<string, int>();
private readonly Dictionary<int, string> _idCodeMap = new Dictionary<int, string>();
private FullDataSetRepositoryCachePolicy<ILanguage, int> _cachePolicy;
public LanguageRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger)
: base(scopeAccessor, cache, logger)
{ }
protected override IRepositoryCachePolicy<ILanguage, int> CreateCachePolicy()
{
return new FullDataSetRepositoryCachePolicy<ILanguage, int>(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false);
return _cachePolicy = new FullDataSetRepositoryCachePolicy<ILanguage, int>(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false);
}
#region Overrides of RepositoryBase<int,Language>
protected override ILanguage PerformGet(int id)
{
//use the underlying GetAll which will force cache all domains
return GetMany().FirstOrDefault(x => x.Id == id);
throw new NotSupportedException(); // not required since policy is full dataset
}
protected override IEnumerable<ILanguage> PerformGetAll(params int[] ids)
@@ -47,8 +50,22 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
//even though legacy didn't sort, it should be by id
sql.OrderBy<LanguageDto>(dto => dto.Id);
// get languages
var languages = Database.Fetch<LanguageDto>(sql).Select(ConvertFromDto).ToList();
return Database.Fetch<LanguageDto>(sql).Select(ConvertFromDto);
// initialize the code-id map
lock (_codeIdMap)
{
_codeIdMap.Clear();
_idCodeMap.Clear();
foreach (var language in languages)
{
_codeIdMap[language.IsoCode] = language.Id;
_idCodeMap[language.Id] = language.IsoCode;
}
}
return languages;
}
protected override IEnumerable<ILanguage> PerformGetByQuery(IQuery<ILanguage> query)
@@ -184,14 +201,40 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
public ILanguage GetByCultureName(string cultureName)
{
//use the underlying GetAll which will force cache all languages
// use the underlying GetMany which will force cache all languages
// TODO we are cloning ALL in GetMany just to retrieve ONE, this is surely not optimized
return GetMany().FirstOrDefault(x => x.CultureName.InvariantEquals(cultureName));
}
public ILanguage GetByIsoCode(string isoCode)
{
//use the underlying GetAll which will force cache all languages
return GetMany().FirstOrDefault(x => x.IsoCode.InvariantEquals(isoCode));
_cachePolicy.GetAllCached(PerformGetAll); // ensure cache is populated, in a non-expensive way
var id = GetIdByIsoCode(isoCode);
return Get(id);
}
// fast way of getting an id for an isoCode - avoiding cloning
// _codeIdMap is rebuilt whenever PerformGetAll runs
public int GetIdByIsoCode(string isoCode)
{
_cachePolicy.GetAllCached(PerformGetAll); // ensure cache is populated, in a non-expensive way
lock (_codeIdMap)
{
if (_codeIdMap.TryGetValue(isoCode, out var id)) return id;
}
throw new ArgumentException($"Code {isoCode} does not correspond to an existing language.", nameof(isoCode));
}
// fast way of getting an isoCode for an id - avoiding cloning
// _idCodeMap is rebuilt whenever PerformGetAll runs
public string GetIsoCodeById(int id)
{
_cachePolicy.GetAllCached(PerformGetAll); // ensure cache is populated, in a non-expensive way
lock (_codeIdMap) // yes, we want to lock _codeIdMap
{
if (_idCodeMap.TryGetValue(id, out var isoCode)) return isoCode;
}
throw new ArgumentException($"Id {id} does not correspond to an existing language.", nameof(id),);
}
}
}

View File

@@ -117,6 +117,11 @@ namespace Umbraco.Core.Services
/// <returns><see cref="Language"/></returns>
ILanguage GetLanguageByIsoCode(string isoCode);
/// <summary>
/// Gets a language identifier by its iso code.
/// </summary>
int GetLanguageIdByIsoCode(string isoCode);
/// <summary>
/// Gets all available languages
/// </summary>

View File

@@ -316,6 +316,15 @@ namespace Umbraco.Core.Services.Implement
}
}
/// <inheritdoc />
public int GetLanguageIdByIsoCode(string isoCode)
{
using (ScopeProvider.CreateScope(autoComplete: true))
{
return _languageRepository.GetIdByIsoCode(isoCode);
}
}
/// <summary>
/// Gets all available languages
/// </summary>