Browse Source

Fix cancellation.

pull/719/head
Sebastian 5 years ago
parent
commit
0263e7f8a6
  1. 6
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository.cs
  2. 24
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs
  3. 36
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs
  4. 8
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs
  5. 14
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/OperationBase.cs
  6. 13
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryAsStream.cs
  7. 32
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryByQuery.cs
  8. 14
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryReferrers.cs
  9. 12
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryScheduled.cs
  10. 8
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs
  11. 2
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs
  12. 1
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryIntegrationTests.cs

6
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository.cs

@ -52,7 +52,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
var assetFolderEntities = var assetFolderEntities =
await Collection.Find(filter).SortBy(x => x.FolderName) await Collection.Find(filter).SortBy(x => x.FolderName)
.ToListAsync(ct = default); .ToListAsync(ct);
return ResultList.Create<IAssetFolderEntity>(assetFolderEntities.Count, assetFolderEntities); return ResultList.Create<IAssetFolderEntity>(assetFolderEntities.Count, assetFolderEntities);
} }
@ -67,7 +67,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
var assetFolderEntities = var assetFolderEntities =
await Collection.Find(filter).Only(x => x.Id) await Collection.Find(filter).Only(x => x.Id)
.ToListAsync(ct = default); .ToListAsync(ct);
var field = Field.Of<MongoAssetFolderEntity>(x => nameof(x.Id)); var field = Field.Of<MongoAssetFolderEntity>(x => nameof(x.Id));
@ -84,7 +84,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
var assetFolderEntity = var assetFolderEntity =
await Collection.Find(x => x.DocumentId == documentId && !x.IsDeleted) await Collection.Find(x => x.DocumentId == documentId && !x.IsDeleted)
.FirstOrDefaultAsync(ct = default); .FirstOrDefaultAsync(ct);
return assetFolderEntity; return assetFolderEntity;
} }

24
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs

@ -76,9 +76,9 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
{ {
var find = Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted); var find = Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted);
using (var cursor = await find.ToCursorAsync(ct = default)) using (var cursor = await find.ToCursorAsync(ct))
{ {
while (await cursor.MoveNextAsync(ct = default)) while (await cursor.MoveNextAsync(ct))
{ {
foreach (var entity in cursor.Current) foreach (var entity in cursor.Current)
{ {
@ -103,7 +103,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
await Collection.Find(filter).SortByDescending(x => x.LastModified).ThenBy(x => x.Id) await Collection.Find(filter).SortByDescending(x => x.LastModified).ThenBy(x => x.Id)
.QueryLimit(q.Query) .QueryLimit(q.Query)
.QuerySkip(q.Query) .QuerySkip(q.Query)
.ToListAsync(ct = default); .ToListAsync(ct);
long assetTotal = assetEntities.Count; long assetTotal = assetEntities.Count;
if (q.NoTotal) if (q.NoTotal)
@ -112,7 +112,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
} }
else if (assetEntities.Count >= q.Query.Take || q.Query.Skip > 0) else if (assetEntities.Count >= q.Query.Take || q.Query.Skip > 0)
{ {
assetTotal = await Collection.Find(filter).CountDocumentsAsync(ct = default); assetTotal = await Collection.Find(filter).CountDocumentsAsync(ct);
} }
return ResultList.Create(assetTotal, assetEntities.OfType<IAssetEntity>()); return ResultList.Create(assetTotal, assetEntities.OfType<IAssetEntity>());
@ -128,7 +128,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
.QueryLimit(query) .QueryLimit(query)
.QuerySkip(query) .QuerySkip(query)
.QuerySort(query) .QuerySort(query)
.ToListAsync(ct = default); .ToListAsync(ct);
long assetTotal = assetEntities.Count; long assetTotal = assetEntities.Count;
if (q.NoTotal) if (q.NoTotal)
@ -137,7 +137,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
} }
else if (assetEntities.Count >= q.Query.Take || q.Query.Skip > 0) else if (assetEntities.Count >= q.Query.Take || q.Query.Skip > 0)
{ {
assetTotal = await Collection.Find(filter).CountDocumentsAsync(ct = default); assetTotal = await Collection.Find(filter).CountDocumentsAsync(ct);
} }
return ResultList.Create<IAssetEntity>(assetTotal, assetEntities); return ResultList.Create<IAssetEntity>(assetTotal, assetEntities);
@ -157,7 +157,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
{ {
var assetEntities = var assetEntities =
await Collection.Find(BuildFilter(appId, ids)).Only(x => x.Id) await Collection.Find(BuildFilter(appId, ids)).Only(x => x.Id)
.ToListAsync(ct = default); .ToListAsync(ct);
var field = Field.Of<MongoAssetFolderEntity>(x => nameof(x.Id)); var field = Field.Of<MongoAssetFolderEntity>(x => nameof(x.Id));
@ -172,7 +172,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
{ {
var assetEntities = var assetEntities =
await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.ParentId == parentId).Only(x => x.Id) await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.ParentId == parentId).Only(x => x.Id)
.ToListAsync(ct = default); .ToListAsync(ct);
var field = Field.Of<MongoAssetFolderEntity>(x => nameof(x.Id)); var field = Field.Of<MongoAssetFolderEntity>(x => nameof(x.Id));
@ -187,7 +187,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
{ {
var assetEntity = var assetEntity =
await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.FileHash == hash && x.FileName == fileName && x.FileSize == fileSize) await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.FileHash == hash && x.FileName == fileName && x.FileSize == fileSize)
.FirstOrDefaultAsync(ct = default); .FirstOrDefaultAsync(ct);
return assetEntity; return assetEntity;
} }
@ -200,7 +200,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
{ {
var assetEntity = var assetEntity =
await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.Slug == slug) await Collection.Find(x => x.IndexedAppId == appId && !x.IsDeleted && x.Slug == slug)
.FirstOrDefaultAsync(ct = default); .FirstOrDefaultAsync(ct);
return assetEntity; return assetEntity;
} }
@ -215,7 +215,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
var assetEntity = var assetEntity =
await Collection.Find(x => x.DocumentId == documentId && !x.IsDeleted) await Collection.Find(x => x.DocumentId == documentId && !x.IsDeleted)
.FirstOrDefaultAsync(ct = default); .FirstOrDefaultAsync(ct);
return assetEntity; return assetEntity;
} }
@ -228,7 +228,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets
{ {
var assetEntity = var assetEntity =
await Collection.Find(x => x.Id == id && !x.IsDeleted) await Collection.Find(x => x.Id == id && !x.IsDeleted)
.FirstOrDefaultAsync(ct = default); .FirstOrDefaultAsync(ct);
return assetEntity; return assetEntity;
} }

36
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollection.cs

@ -7,6 +7,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver; using MongoDB.Driver;
@ -33,9 +34,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
private readonly QueryReferrers queryReferrers; private readonly QueryReferrers queryReferrers;
private readonly QueryScheduled queryScheduled; private readonly QueryScheduled queryScheduled;
private readonly string name; private readonly string name;
private readonly bool useWildcardIndex;
public MongoContentCollection(string name, IMongoDatabase database, IAppProvider appProvider, bool useWildcardIndex) public MongoContentCollection(string name, IMongoDatabase database, IAppProvider appProvider)
: base(database) : base(database)
{ {
this.name = name; this.name = name;
@ -47,8 +47,6 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
queryReferences = new QueryReferences(queryByIds); queryReferences = new QueryReferences(queryByIds);
queryReferrers = new QueryReferrers(); queryReferrers = new QueryReferrers();
queryScheduled = new QueryScheduled(); queryScheduled = new QueryScheduled();
this.useWildcardIndex = useWildcardIndex;
} }
public IMongoCollection<MongoContentEntity> GetInternalCollection() public IMongoCollection<MongoContentEntity> GetInternalCollection()
@ -61,26 +59,26 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
return name; return name;
} }
protected override async Task SetupCollectionAsync(IMongoCollection<MongoContentEntity> collection, protected override Task SetupCollectionAsync(IMongoCollection<MongoContentEntity> collection,
CancellationToken ct) CancellationToken ct)
{ {
if (useWildcardIndex) var operations = new OperationBase[]
{
queryAsStream,
queryBdId,
queryByIds,
queryByQuery,
queryReferences,
queryReferrers,
queryScheduled
};
foreach (var operation in operations)
{ {
await collection.Indexes.CreateOneAsync( operation.Setup(collection);
new CreateIndexModel<MongoContentEntity>(
Index.Wildcard()
), null, ct);
} }
var skipIndex = useWildcardIndex; return collection.Indexes.CreateManyAsync(operations.SelectMany(x => x.CreateIndexes()), ct);
await queryAsStream.PrepareAsync(collection, skipIndex, ct);
await queryBdId.PrepareAsync(collection, skipIndex, ct);
await queryByIds.PrepareAsync(collection, skipIndex, ct);
await queryByQuery.PrepareAsync(collection, skipIndex, ct);
await queryReferences.PrepareAsync(collection, skipIndex, ct);
await queryReferrers.PrepareAsync(collection, skipIndex, ct);
await queryScheduled.PrepareAsync(collection, skipIndex, ct);
} }
public Task ResetScheduledAsync(DomainId documentId, public Task ResetScheduledAsync(DomainId documentId,

8
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs

@ -34,17 +34,15 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
TypeConverterStringSerializer<Status>.Register(); TypeConverterStringSerializer<Status>.Register();
} }
public MongoContentRepository(IMongoDatabase database, IAppProvider appProvider, bool useWildcardIndex) public MongoContentRepository(IMongoDatabase database, IAppProvider appProvider)
{ {
Guard.NotNull(appProvider, nameof(appProvider)); Guard.NotNull(appProvider, nameof(appProvider));
collectionAll = collectionAll =
new MongoContentCollection( new MongoContentCollection("States_Contents_All3", database, appProvider);
"States_Contents_All3", database, appProvider, useWildcardIndex);
collectionPublished = collectionPublished =
new MongoContentCollection( new MongoContentCollection("States_Contents_Published3", database, appProvider);
"States_Contents_Published3", database, appProvider, useWildcardIndex);
this.appProvider = appProvider; this.appProvider = appProvider;
} }

14
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/OperationBase.cs

@ -5,8 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Threading; using System.Collections.Generic;
using System.Threading.Tasks;
using MongoDB.Driver; using MongoDB.Driver;
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
@ -21,19 +20,14 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
public IMongoCollection<MongoContentEntity> Collection { get; private set; } public IMongoCollection<MongoContentEntity> Collection { get; private set; }
public async Task PrepareAsync(IMongoCollection<MongoContentEntity> collection, bool skipIndex, CancellationToken ct = default) public void Setup(IMongoCollection<MongoContentEntity> collection)
{ {
Collection = collection; Collection = collection;
if (!skipIndex)
{
await PrepareAsync(ct);
}
} }
protected virtual Task PrepareAsync(CancellationToken ct) public virtual IEnumerable<CreateIndexModel<MongoContentEntity>> CreateIndexes()
{ {
return Task.CompletedTask; yield break;
} }
} }
} }

13
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryAsStream.cs

@ -17,15 +17,12 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
{ {
public sealed class QueryAsStream : OperationBase public sealed class QueryAsStream : OperationBase
{ {
protected override async Task PrepareAsync(CancellationToken ct) public override IEnumerable<CreateIndexModel<MongoContentEntity>> CreateIndexes()
{ {
var indexBySchema = yield return new CreateIndexModel<MongoContentEntity>(Index
new CreateIndexModel<MongoContentEntity>(Index .Ascending(x => x.IndexedAppId)
.Ascending(x => x.IndexedAppId) .Ascending(x => x.IsDeleted)
.Ascending(x => x.IsDeleted) .Ascending(x => x.IndexedSchemaId));
.Ascending(x => x.IndexedSchemaId));
await Collection.Indexes.CreateOneAsync(indexBySchema, cancellationToken: ct);
} }
public async IAsyncEnumerable<IContentEntity> StreamAll(DomainId appId, HashSet<DomainId>? schemaIds, public async IAsyncEnumerable<IContentEntity> StreamAll(DomainId appId, HashSet<DomainId>? schemaIds,

32
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryByQuery.cs

@ -41,26 +41,20 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
this.appProvider = appProvider; this.appProvider = appProvider;
} }
protected override async Task PrepareAsync(CancellationToken ct) public override IEnumerable<CreateIndexModel<MongoContentEntity>> CreateIndexes()
{ {
var indexBySchemaWithRefs = yield return new CreateIndexModel<MongoContentEntity>(Index
new CreateIndexModel<MongoContentEntity>(Index .Descending(x => x.LastModified)
.Descending(x => x.LastModified) .Ascending(x => x.Id)
.Ascending(x => x.Id) .Ascending(x => x.IndexedAppId)
.Ascending(x => x.IndexedAppId) .Ascending(x => x.IndexedSchemaId)
.Ascending(x => x.IndexedSchemaId) .Ascending(x => x.IsDeleted)
.Ascending(x => x.IsDeleted) .Ascending(x => x.ReferencedIds));
.Ascending(x => x.ReferencedIds));
yield return new CreateIndexModel<MongoContentEntity>(Index
await Collection.Indexes.CreateOneAsync(indexBySchemaWithRefs, cancellationToken: ct); .Ascending(x => x.IndexedSchemaId)
.Ascending(x => x.IsDeleted)
var indexBySchema = .Descending(x => x.LastModified));
new CreateIndexModel<MongoContentEntity>(Index
.Ascending(x => x.IndexedSchemaId)
.Ascending(x => x.IsDeleted)
.Descending(x => x.LastModified));
await Collection.Indexes.CreateOneAsync(indexBySchema, cancellationToken: ct);
} }
public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, DomainId schemaId, FilterNode<ClrValue> filterNode, public async Task<IReadOnlyList<(DomainId SchemaId, DomainId Id, Status Status)>> QueryIdsAsync(DomainId appId, DomainId schemaId, FilterNode<ClrValue> filterNode,

14
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryReferrers.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver; using MongoDB.Driver;
@ -15,15 +16,12 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
{ {
internal sealed class QueryReferrers : OperationBase internal sealed class QueryReferrers : OperationBase
{ {
protected override Task PrepareAsync(CancellationToken ct) public override IEnumerable<CreateIndexModel<MongoContentEntity>> CreateIndexes()
{ {
var index = yield return new CreateIndexModel<MongoContentEntity>(Index
new CreateIndexModel<MongoContentEntity>(Index .Ascending(x => x.ReferencedIds)
.Ascending(x => x.ReferencedIds) .Ascending(x => x.IndexedAppId)
.Ascending(x => x.IndexedAppId) .Ascending(x => x.IsDeleted));
.Ascending(x => x.IsDeleted));
return Collection.Indexes.CreateOneAsync(index, cancellationToken: ct);
} }
public async Task<bool> CheckExistsAsync(DomainId appId, DomainId contentId, public async Task<bool> CheckExistsAsync(DomainId appId, DomainId contentId,

12
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/Operations/QueryScheduled.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System; using System;
using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver; using MongoDB.Driver;
@ -18,14 +19,11 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations
{ {
internal sealed class QueryScheduled : OperationBase internal sealed class QueryScheduled : OperationBase
{ {
protected override Task PrepareAsync(CancellationToken ct) public override IEnumerable<CreateIndexModel<MongoContentEntity>> CreateIndexes()
{ {
var index = yield return new CreateIndexModel<MongoContentEntity>(Index
new CreateIndexModel<MongoContentEntity>(Index .Ascending(x => x.ScheduledAt)
.Ascending(x => x.ScheduledAt) .Ascending(x => x.IsDeleted));
.Ascending(x => x.IsDeleted));
return Collection.Indexes.CreateOneAsync(index, cancellationToken: ct);
} }
public Task QueryAsync(Instant now, Func<IContentEntity, Task> callback, public Task QueryAsync(Instant now, Func<IContentEntity, Task> callback,

8
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs

@ -39,7 +39,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules
protected override async Task SetupCollectionAsync(IMongoCollection<MongoRuleEventEntity> collection, protected override async Task SetupCollectionAsync(IMongoCollection<MongoRuleEventEntity> collection,
CancellationToken ct = default) CancellationToken ct = default)
{ {
await statisticsCollection.InitializeAsync(ct = default); await statisticsCollection.InitializeAsync(ct);
await collection.Indexes.CreateManyAsync(new[] await collection.Indexes.CreateManyAsync(new[]
{ {
@ -73,12 +73,12 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules
filter = Filter.And(filter, Filter.Eq(x => x.RuleId, ruleId.Value)); filter = Filter.And(filter, Filter.Eq(x => x.RuleId, ruleId.Value));
} }
var ruleEventEntities = await Collection.Find(filter).Skip(skip).Limit(take).SortByDescending(x => x.Created).ToListAsync(ct = default); var ruleEventEntities = await Collection.Find(filter).Skip(skip).Limit(take).SortByDescending(x => x.Created).ToListAsync(ct);
var ruleEventTotal = (long)ruleEventEntities.Count; var ruleEventTotal = (long)ruleEventEntities.Count;
if (ruleEventTotal >= take || skip > 0) if (ruleEventTotal >= take || skip > 0)
{ {
ruleEventTotal = await Collection.Find(filter).CountDocumentsAsync(ct = default); ruleEventTotal = await Collection.Find(filter).CountDocumentsAsync(ct);
} }
return ResultList.Create(ruleEventTotal, ruleEventEntities); return ResultList.Create(ruleEventTotal, ruleEventEntities);
@ -88,7 +88,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules
{ {
var ruleEvent = var ruleEvent =
await Collection.Find(x => x.DocumentId == id) await Collection.Find(x => x.DocumentId == id)
.FirstOrDefaultAsync(ct = default); .FirstOrDefaultAsync(ct);
return ruleEvent; return ruleEvent;
} }

2
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs

@ -62,7 +62,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
ContentRepository = ContentRepository =
new MongoContentRepository( new MongoContentRepository(
mongoDatabase, mongoDatabase,
appProvider, false); appProvider);
Task.Run(async () => Task.Run(async () =>
{ {

1
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryIntegrationTests.cs

@ -198,6 +198,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb
var q = var q =
Q.Empty Q.Empty
.WithoutTotal()
.WithQuery(clrQuery) .WithQuery(clrQuery)
.WithReference(reference); .WithReference(reference);

Loading…
Cancel
Save