Browse Source

Performance improvements:

1. Caching for app tags
2. Caching for available languages.
pull/382/head
Sebastian 7 years ago
parent
commit
8476e5bfc0
  1. 6
      src/Squidex.Domain.Apps.Core.Operations/Tags/ITagService.cs
  2. 2
      src/Squidex.Domain.Apps.Core.Operations/Tags/TagsExport.cs
  3. 26
      src/Squidex.Domain.Apps.Core.Operations/Tags/TagsSet.cs
  4. 2
      src/Squidex.Domain.Apps.Entities/Assets/BackupAssets.cs
  5. 6
      src/Squidex.Domain.Apps.Entities/Tags/GrainTagService.cs
  6. 6
      src/Squidex.Domain.Apps.Entities/Tags/ITagGrain.cs
  7. 12
      src/Squidex.Domain.Apps.Entities/Tags/TagGrain.cs
  8. 6
      src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs
  9. 22
      src/Squidex/app/shared/state/languages.state.ts
  10. 2
      tests/Squidex.Domain.Apps.Entities.Tests/Tags/GrainTagServiceTests.cs
  11. 2
      tests/Squidex.Domain.Apps.Entities.Tests/Tags/TagGrainTests.cs

6
src/Squidex.Domain.Apps.Core.Operations/Tags/ITagService.cs

@ -19,11 +19,11 @@ namespace Squidex.Domain.Apps.Core.Tags
Task<Dictionary<string, string>> DenormalizeTagsAsync(Guid appId, string group, HashSet<string> ids); Task<Dictionary<string, string>> DenormalizeTagsAsync(Guid appId, string group, HashSet<string> ids);
Task<Dictionary<string, int>> GetTagsAsync(Guid appId, string group); Task<TagsSet> GetTagsAsync(Guid appId, string group);
Task<TagSet> GetExportableTagsAsync(Guid appId, string group); Task<TagsExport> GetExportableTagsAsync(Guid appId, string group);
Task RebuildTagsAsync(Guid appId, string group, TagSet tags); Task RebuildTagsAsync(Guid appId, string group, TagsExport tags);
Task ClearAsync(Guid appId, string group); Task ClearAsync(Guid appId, string group);
} }

2
src/Squidex.Domain.Apps.Core.Operations/Tags/TagSet.cs → src/Squidex.Domain.Apps.Core.Operations/Tags/TagsExport.cs

@ -9,7 +9,7 @@ using System.Collections.Generic;
namespace Squidex.Domain.Apps.Core.Tags namespace Squidex.Domain.Apps.Core.Tags
{ {
public sealed class TagSet : Dictionary<string, Tag> public sealed class TagsExport : Dictionary<string, Tag>
{ {
} }
} }

26
src/Squidex.Domain.Apps.Core.Operations/Tags/TagsSet.cs

@ -0,0 +1,26 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections.Generic;
namespace Squidex.Domain.Apps.Core.Tags
{
public sealed class TagsSet : Dictionary<string, int>
{
public long Version { get; set; }
public TagsSet()
{
}
public TagsSet(IDictionary<string, int> tags, long version)
: base(tags)
{
Version = version;
}
}
}

2
src/Squidex.Domain.Apps.Entities/Assets/BackupAssets.cs

@ -82,7 +82,7 @@ namespace Squidex.Domain.Apps.Entities.Assets
private async Task RestoreTagsAsync(Guid appId, BackupReader reader) private async Task RestoreTagsAsync(Guid appId, BackupReader reader)
{ {
var tags = await reader.ReadJsonAttachmentAsync<TagSet>(TagsFile); var tags = await reader.ReadJsonAttachmentAsync<TagsExport>(TagsFile);
await tagService.RebuildTagsAsync(appId, TagGroups.Assets, tags); await tagService.RebuildTagsAsync(appId, TagGroups.Assets, tags);
} }

6
src/Squidex.Domain.Apps.Entities/Tags/GrainTagService.cs

@ -45,17 +45,17 @@ namespace Squidex.Domain.Apps.Entities.Tags
return GetGrain(appId, group).DenormalizeTagsAsync(ids); return GetGrain(appId, group).DenormalizeTagsAsync(ids);
} }
public Task<Dictionary<string, int>> GetTagsAsync(Guid appId, string group) public Task<TagsSet> GetTagsAsync(Guid appId, string group)
{ {
return GetGrain(appId, group).GetTagsAsync(); return GetGrain(appId, group).GetTagsAsync();
} }
public Task<TagSet> GetExportableTagsAsync(Guid appId, string group) public Task<TagsExport> GetExportableTagsAsync(Guid appId, string group)
{ {
return GetGrain(appId, group).GetExportableTagsAsync(); return GetGrain(appId, group).GetExportableTagsAsync();
} }
public Task RebuildTagsAsync(Guid appId, string group, TagSet tags) public Task RebuildTagsAsync(Guid appId, string group, TagsExport tags)
{ {
return GetGrain(appId, group).RebuildAsync(tags); return GetGrain(appId, group).RebuildAsync(tags);
} }

6
src/Squidex.Domain.Apps.Entities/Tags/ITagGrain.cs

@ -20,12 +20,12 @@ namespace Squidex.Domain.Apps.Entities.Tags
Task<Dictionary<string, string>> DenormalizeTagsAsync(HashSet<string> ids); Task<Dictionary<string, string>> DenormalizeTagsAsync(HashSet<string> ids);
Task<Dictionary<string, int>> GetTagsAsync(); Task<TagsSet> GetTagsAsync();
Task<TagSet> GetExportableTagsAsync(); Task<TagsExport> GetExportableTagsAsync();
Task ClearAsync(); Task ClearAsync();
Task RebuildAsync(TagSet tags); Task RebuildAsync(TagsExport tags);
} }
} }

12
src/Squidex.Domain.Apps.Entities/Tags/TagGrain.cs

@ -20,7 +20,7 @@ namespace Squidex.Domain.Apps.Entities.Tags
[CollectionName("Index_Tags")] [CollectionName("Index_Tags")]
public sealed class GrainState public sealed class GrainState
{ {
public TagSet Tags { get; set; } = new TagSet(); public TagsExport Tags { get; set; } = new TagsExport();
} }
public TagGrain(IStore<string> store) public TagGrain(IStore<string> store)
@ -33,7 +33,7 @@ namespace Squidex.Domain.Apps.Entities.Tags
return ClearStateAsync(); return ClearStateAsync();
} }
public Task RebuildAsync(TagSet tags) public Task RebuildAsync(TagsExport tags)
{ {
State.Tags = tags; State.Tags = tags;
@ -132,12 +132,14 @@ namespace Squidex.Domain.Apps.Entities.Tags
return Task.FromResult(result); return Task.FromResult(result);
} }
public Task<Dictionary<string, int>> GetTagsAsync() public Task<TagsSet> GetTagsAsync()
{ {
return Task.FromResult(State.Tags.Values.ToDictionary(x => x.Name, x => x.Count)); var tags = State.Tags.Values.ToDictionary(x => x.Name, x => x.Count);
return Task.FromResult(new TagsSet(tags, Persistence.Version));
} }
public Task<TagSet> GetExportableTagsAsync() public Task<TagsExport> GetExportableTagsAsync()
{ {
return Task.FromResult(State.Tags); return Task.FromResult(State.Tags);
} }

6
src/Squidex/Areas/Api/Controllers/Assets/AssetsController.cs

@ -77,9 +77,11 @@ namespace Squidex.Areas.Api.Controllers.Assets
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> GetTags(string app) public async Task<IActionResult> GetTags(string app)
{ {
var response = await tagService.GetTagsAsync(AppId, TagGroups.Assets); var tags = await tagService.GetTagsAsync(AppId, TagGroups.Assets);
return Ok(response); Response.Headers[HeaderNames.ETag] = tags.Version.ToString();
return Ok(tags);
} }
/// <summary> /// <summary>

22
src/Squidex/app/shared/state/languages.state.ts

@ -7,7 +7,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { forkJoin, Observable } from 'rxjs'; import { forkJoin, Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators'; import { map, shareReplay, tap } from 'rxjs/operators';
import { import {
DialogService, DialogService,
@ -65,6 +65,8 @@ type LanguageResultList = ImmutableArray<SnapshotLanguage>;
@Injectable() @Injectable()
export class LanguagesState extends State<Snapshot> { export class LanguagesState extends State<Snapshot> {
private cachedLanguage$: Observable<LanguageDto[]>;
public languages = public languages =
this.project(x => x.languages); this.project(x => x.languages);
@ -96,9 +98,7 @@ export class LanguagesState extends State<Snapshot> {
this.resetState(); this.resetState();
} }
return forkJoin( return forkJoin(this.getAllLanguages(), this.getAppLanguages()).pipe(
this.languagesService.getLanguages(),
this.appLanguagesService.getLanguages(this.appName)).pipe(
map(args => { map(args => {
return { allLanguages: args[0], languages: args[1] }; return { allLanguages: args[0], languages: args[1] };
}), }),
@ -166,6 +166,20 @@ export class LanguagesState extends State<Snapshot> {
return this.snapshot.version; return this.snapshot.version;
} }
private getAppLanguages() {
return this.appLanguagesService.getLanguages(this.appName);
}
private getAllLanguages() {
if (!this.cachedLanguage$) {
this.cachedLanguage$ =
this.languagesService.getLanguages().pipe(
shareReplay(1));
}
return this.cachedLanguage$;
}
private createLanguage(language: AppLanguageDto, languages: AppLanguagesList): SnapshotLanguage { private createLanguage(language: AppLanguageDto, languages: AppLanguagesList): SnapshotLanguage {
return { return {
language, language,

2
tests/Squidex.Domain.Apps.Entities.Tests/Tags/GrainTagServiceTests.cs

@ -48,7 +48,7 @@ namespace Squidex.Domain.Apps.Entities.Tags
[Fact] [Fact]
public async Task Should_call_grain_when_rebuilding() public async Task Should_call_grain_when_rebuilding()
{ {
var tags = new TagSet(); var tags = new TagsExport();
await sut.RebuildTagsAsync(appId, TagGroups.Assets, tags); await sut.RebuildTagsAsync(appId, TagGroups.Assets, tags);

2
tests/Squidex.Domain.Apps.Entities.Tests/Tags/TagGrainTests.cs

@ -50,7 +50,7 @@ namespace Squidex.Domain.Apps.Entities.Tags
[Fact] [Fact]
public async Task Should_rebuild_tags() public async Task Should_rebuild_tags()
{ {
var tags = new TagSet var tags = new TagsExport
{ {
["id1"] = new Tag { Name = "name1", Count = 1 }, ["id1"] = new Tag { Name = "name1", Count = 1 },
["id2"] = new Tag { Name = "name2", Count = 2 }, ["id2"] = new Tag { Name = "name2", Count = 2 },

Loading…
Cancel
Save