Skip to content

Commit

Permalink
Working on caching and tokens (#4001)
Browse files Browse the repository at this point in the history
* Working on caching an tokens

* wip

* wip

* wip.

* Some comments

* Invalidates the cache at the end of the transaction, right now only done for SiteService.

* DeferredSignalToken to invalidate caches e.g after the session is committed.

* Minor changes

* Little updates for some syncing between the caching and async branches.

* Ensures that a deferred signal for a given key is sent once at the end of the scope.

* Re-introduces and uses the DeferredSignalToken extension helper.

* 2 places where the token was still get after consuming data.

* Final version of "ContentDefinitionManager" here because we keep it non async

* RoleClaims thread safety

* User thread safety

* Update after merging dev

* Revertd changes related to Users and Roles.

* Missing reverted update.

* Updates after merging dev

* Minor change to restart the CI

* Idem.

* wip

* Re-introduce roles immutability

* Minor changes

* Get / load pattern for AdminMenu through #4612 keeping other caching rules.

* Get / Load pattern for Roles.

* Don't save default value and refresh the cache in an isolated scope.

* Uses sesion.Detach()

* Get / Load pattern for Templates.

* Load / Get patter for SiteSettings.

* Get / Load pattern for Queries.

* Revert some previous changes no more required with the new pattern.

* Get / Load pattern for BackgroundTaskSettings.

* Get / Load pattern for Layers.

* ISessionHelper to LOAD for update / GET for caching.

* Use SessionHelper for SiteService

* Use SessionHelper for AdminMenuService.

* Use SessionHelper for other servies.

* Wip on GET / LOAD pattern for content definitions

* GET / LOAD pattern for types / parts definitions.

* Revert testing code, to be continued maybe in another PR.

* Prevents a deferred task lambda from holding a ref on a scoped service.

* Little formatting
  • Loading branch information
jtkech authored Nov 10, 2019
1 parent 061ba64 commit 6af5f1a
Show file tree
Hide file tree
Showing 102 changed files with 1,281 additions and 1,007 deletions.
19 changes: 8 additions & 11 deletions src/OrchardCore.Modules/OrchardCore.Admin/AdminThemeService.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
using Microsoft.Extensions.Caching.Memory;
using OrchardCore.Settings;
using OrchardCore.Environment.Extensions;
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using OrchardCore.Environment.Extensions;
using OrchardCore.Settings;

namespace OrchardCore.Admin
{
public class AdminThemeService : IAdminThemeService
{
private const string CacheKey = "AdminThemeName";

private readonly IExtensionManager _extensionManager;
private readonly ISiteService _siteService;
private readonly IExtensionManager _extensionManager;
private readonly IMemoryCache _memoryCache;

public AdminThemeService(
ISiteService siteService,
IExtensionManager extensionManager,
IMemoryCache memoryCache
)
IMemoryCache memoryCache)
{
_siteService = siteService;
_extensionManager = extensionManager;
Expand All @@ -38,10 +37,8 @@ public async Task<IExtensionInfo> GetAdminThemeAsync()

public async Task SetAdminThemeAsync(string themeName)
{
var site = await _siteService.GetSiteSettingsAsync();
var site = await _siteService.LoadSiteSettingsAsync();
site.Properties["CurrentAdminThemeName"] = themeName;
//(site as IContent).ContentItem.Content.CurrentAdminThemeName = themeName;
_memoryCache.Set(CacheKey, themeName);
await _siteService.UpdateSiteSettingsAsync(site);
}

Expand All @@ -50,10 +47,10 @@ public async Task<string> GetAdminThemeNameAsync()
string themeName;
if (!_memoryCache.TryGetValue(CacheKey, out themeName))
{
var changeToken = _siteService.ChangeToken;
var site = await _siteService.GetSiteSettingsAsync();
themeName = (string)site.Properties["CurrentAdminThemeName"];
// themeName = (string)(site as IContent).ContentItem.Content.CurrentAdminThemeName;
_memoryCache.Set(CacheKey, themeName);
_memoryCache.Set(CacheKey, themeName, changeToken);
}

return themeName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,13 @@ public async Task<IActionResult> Create(AdminMenuCreateViewModel model)

if (ModelState.IsValid)
{
var tree = new Models.AdminMenu {Name = model.Name};
var tree = new Models.AdminMenu { Name = model.Name };

await _adminMenuService.SaveAsync(tree);

return RedirectToAction(nameof(List));
}


return View(model);
}

Expand Down Expand Up @@ -191,7 +190,7 @@ public async Task<IActionResult> Edit(AdminMenuEditViewModel model)
{
adminMenu.Name = model.Name;

await _adminMenuService.SaveAsync(adminMenu);
await _adminMenuService.SaveAsync(adminMenu);

_notifier.Success(H["Admin menu updated successfully"]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ public async Task ProcessDeploymentStepAsync(DeploymentStep step, DeploymentPlan
));

// For each AdminNode, store info about its concrete type: linkAdminNode, contentTypesAdminNode etc...
var serializer = new JsonSerializer() { TypeNameHandling = TypeNameHandling.Auto };
var serializer = new JsonSerializer() { TypeNameHandling = TypeNameHandling.Auto };

foreach (var adminMenu in (await _adminMenuService.GetAdminMenuListAsync()).AdminMenu)
{
var objectData = JObject.FromObject(adminMenu, serializer);
var objectData = JObject.FromObject(adminMenu, serializer);
data.Add(objectData);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public bool RemoveMenuItem(AdminNode itemToRemove)
{
return true; // success
}
}
}
}

return false; // failure
Expand All @@ -76,7 +76,7 @@ public bool InsertMenuItemAt(AdminNode menuItemToInsert, AdminNode destinationMe
{
return true; // success
}
}
}
}
return false; // failure
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ private async Task BuildTreeAsync(Models.AdminMenu tree, NavigationBuilder build
foreach (MenuItem node in tree.MenuItems)
{
var nodeBuilder = _nodeBuilders.Where(x => x.Name == node.GetType().Name).FirstOrDefault();

if (nodeBuilder != null)
{
await nodeBuilder.BuildNavigationAsync(node, builder, _nodeBuilders);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,40 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Primitives;
using OrchardCore.AdminMenu.Models;
using OrchardCore.Data;
using OrchardCore.Environment.Cache;
using YesSql;

namespace OrchardCore.AdminMenu
{
public class AdminMenuService : IAdminMenuService
{
private readonly IMemoryCache _memoryCache;
private readonly ISignal _signal;
private readonly ISession _session;
private const string AdminMenuCacheKey = nameof(AdminMenuService);

private AdminMenuList _adminMenuList;
private readonly ISignal _signal;
private readonly ISession _session;
private readonly ISessionHelper _sessionHelper;
private readonly IMemoryCache _memoryCache;

public AdminMenuService(
ISignal signal,
ISession session,
IMemoryCache memoryCache
)
ISessionHelper sessionHelper,
IMemoryCache memoryCache)
{
_signal = signal;
_session = session;
_sessionHelper = sessionHelper;
_memoryCache = memoryCache;
}

public IChangeToken ChangeToken => _signal.GetToken(AdminMenuCacheKey);

public async Task<List<Models.AdminMenu>> GetAsync()
/// <summary>
/// Returns the document from the database to be updated.
/// </summary>
public Task<AdminMenuList> LoadAdminMenuListAsync() => _sessionHelper.LoadForUpdateAsync<AdminMenuList>();

/// <summary>
/// Returns the document from the cache or creates a new one. The result should not be updated.
/// </summary>
public async Task<AdminMenuList> GetAdminMenuListAsync()
{
return (await GetAdminMenuListAsync()).AdminMenu;
if (!_memoryCache.TryGetValue<AdminMenuList>(AdminMenuCacheKey, out var adminMenuList))
{
var changeToken = ChangeToken;

adminMenuList = await _sessionHelper.GetForCachingAsync<AdminMenuList>();

foreach (var adminMenu in adminMenuList.AdminMenu)
{
adminMenu.IsReadonly = true;
}

_memoryCache.Set(AdminMenuCacheKey, adminMenuList, changeToken);
}

return adminMenuList;
}

public async Task SaveAsync(Models.AdminMenu tree)
Expand All @@ -60,9 +83,7 @@ public async Task SaveAsync(Models.AdminMenu tree)
}

_session.Save(adminMenuList);

_memoryCache.Set(AdminMenuCacheKey, adminMenuList);
_signal.SignalToken(AdminMenuCacheKey);
_signal.DeferredSignalToken(AdminMenuCacheKey);
}

public Models.AdminMenu GetAdminMenuById(AdminMenuList adminMenuList, string id)
Expand All @@ -83,58 +104,9 @@ public async Task<int> DeleteAsync(Models.AdminMenu tree)
var count = adminMenuList.AdminMenu.RemoveAll(x => String.Equals(x.Id, tree.Id, StringComparison.OrdinalIgnoreCase));

_session.Save(adminMenuList);

_memoryCache.Set(AdminMenuCacheKey, adminMenuList);
_signal.SignalToken(AdminMenuCacheKey);
_signal.DeferredSignalToken(AdminMenuCacheKey);

return count;
}

/// <summary>
/// Returns the document from the database to be updated
/// </summary>
public async Task<AdminMenuList> LoadAdminMenuListAsync()
{
return _adminMenuList = _adminMenuList ?? await _session.Query<AdminMenuList>().FirstOrDefaultAsync() ?? new AdminMenuList();
}

/// <summary>
/// Returns the document from the cache or creates a new one. The result should not be updated.
/// </summary>
public async Task<AdminMenuList> GetAdminMenuListAsync()
{
AdminMenuList adminMenuList;

if (!_memoryCache.TryGetValue(AdminMenuCacheKey, out adminMenuList))
{
adminMenuList = await _session.Query<AdminMenuList>().FirstOrDefaultAsync();

if (adminMenuList == null)
{
lock (_memoryCache)
{
if (!_memoryCache.TryGetValue(AdminMenuCacheKey, out adminMenuList))
{
adminMenuList = new AdminMenuList();
_session.Save(adminMenuList);
_memoryCache.Set(AdminMenuCacheKey, adminMenuList);
_signal.SignalToken(AdminMenuCacheKey);
}
}
}
else
{
_memoryCache.Set(AdminMenuCacheKey, adminMenuList);
_signal.SignalToken(AdminMenuCacheKey);
}

foreach (var adminMenu in adminMenuList.AdminMenu)
{
adminMenu.IsReadonly = true;
}
}

return adminMenuList;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ namespace OrchardCore.AdminMenu
/// </summary>
public interface IAdminMenuService
{

/// <summary>
/// Returns all the admin menus for udpate.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/OrchardCore.Modules/OrchardCore.AdminMenu/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@ public override void Configure(IApplicationBuilder builder, IEndpointRouteBuilde
{
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public override async Task PublishedAsync(PublishContentContext context, Autorou

if (part.SetHomepage)
{
var site = await _siteService.GetSiteSettingsAsync();
var site = await _siteService.LoadSiteSettingsAsync();

if (site.HomeRoute == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ public async Task<IActionResult> Delete(string name)
return Unauthorized();
}

var document = await _backgroundTaskManager.GetDocumentAsync();
var document = await _backgroundTaskManager.LoadDocumentAsync();

if (!document.Settings.ContainsKey(name))
{
Expand All @@ -242,7 +242,7 @@ public async Task<IActionResult> Enable(string name)
return Unauthorized();
}

var document = await _backgroundTaskManager.GetDocumentAsync();
var document = await _backgroundTaskManager.LoadDocumentAsync();

if (!document.Settings.TryGetValue(name, out var settings))
{
Expand All @@ -266,7 +266,7 @@ public async Task<IActionResult> Disable(string name)
return Unauthorized();
}

var document = await _backgroundTaskManager.GetDocumentAsync();
var document = await _backgroundTaskManager.LoadDocumentAsync();

if (!document.Settings.TryGetValue(name, out var settings))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ namespace OrchardCore.BackgroundTasks.Models
{
public class BackgroundTaskDocument
{
public int Id { get; set; } // An identifier so that updates don't create new documents

public Dictionary<string, BackgroundTaskSettings> Settings { get; } = new Dictionary<string, BackgroundTaskSettings>();
}
}
Loading

0 comments on commit 6af5f1a

Please sign in to comment.