Browse Source

Better abstraction.

pull/460/head
Sebastian 6 years ago
parent
commit
d4ef377f92
  1. 8
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/FullText/MongoIndexStorage.cs
  2. 14
      backend/src/Squidex.Domain.Apps.Entities/Contents/Text/AssetIndexStorage.cs
  3. 6
      backend/src/Squidex.Domain.Apps.Entities/Contents/Text/FileIndexStorage.cs
  4. 28
      backend/src/Squidex.Domain.Apps.Entities/Contents/Text/IIndex.cs
  5. 6
      backend/src/Squidex.Domain.Apps.Entities/Contents/Text/IIndexStorage.cs
  6. 162
      backend/src/Squidex.Domain.Apps.Entities/Contents/Text/IndexHolder.cs
  7. 110
      backend/src/Squidex.Domain.Apps.Entities/Contents/Text/IndexHolderFactory.cs
  8. 148
      backend/src/Squidex.Domain.Apps.Entities/Contents/Text/IndexManager.cs
  9. 176
      backend/src/Squidex.Domain.Apps.Entities/Contents/Text/IndexManager_Impl.cs
  10. 4
      backend/src/Squidex.Domain.Apps.Entities/Contents/Text/IndexState.cs
  11. 6
      backend/src/Squidex.Domain.Apps.Entities/Contents/Text/TextIndexContent.cs
  12. 38
      backend/src/Squidex.Domain.Apps.Entities/Contents/Text/TextIndexerGrain.cs
  13. 2
      backend/src/Squidex/Config/Domain/ContentsServices.cs
  14. 4
      backend/src/Squidex/Config/Domain/StoreServices.cs
  15. 2
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerBenchmark.cs
  16. 6
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerGrainTestsBase.cs
  17. 23
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerGrainTests_Assets.cs
  18. 8
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerGrainTests_FS.cs
  19. 8
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerGrainTests_Mongo.cs

8
backend/src/Squidex.Domain.Apps.Entities.MongoDb/FullText/MongoDirectoryFactory.cs → backend/src/Squidex.Domain.Apps.Entities.MongoDb/FullText/MongoIndexStorage.cs

@ -15,16 +15,16 @@ using LuceneDirectory = Lucene.Net.Store.Directory;
namespace Squidex.Domain.Apps.Entities.MongoDb.FullText
{
public sealed class MongoDirectoryFactory : IDirectoryFactory
public sealed class MongoIndexStorage : IIndexStorage
{
private readonly IGridFSBucket<string> bucket;
public MongoDirectoryFactory(IGridFSBucket<string> bucket)
public MongoIndexStorage(IGridFSBucket<string> bucket)
{
this.bucket = bucket;
}
public Task<LuceneDirectory> CreateAsync(Guid schemaId)
public Task<LuceneDirectory> CreateDirectoryAsync(Guid schemaId)
{
var folderName = schemaId.ToString();
@ -36,7 +36,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.FullText
return Task.FromResult<LuceneDirectory>(directory);
}
public Task WriteAsync(IndexWriter writer, SnapshotDeletionPolicy snapshotter)
public Task WriteAsync(LuceneDirectory directory, SnapshotDeletionPolicy snapshotter)
{
return Task.CompletedTask;
}

14
backend/src/Squidex.Domain.Apps.Entities/Contents/Text/AssetStoreDirectoryFactory.cs → backend/src/Squidex.Domain.Apps.Entities/Contents/Text/AssetIndexStorage.cs

@ -17,20 +17,20 @@ using LuceneDirectory = Lucene.Net.Store.Directory;
namespace Squidex.Domain.Apps.Entities.Contents.Text
{
public sealed class AssetStoreDirectoryFactory : IDirectoryFactory
public sealed class AssetIndexStorage : IIndexStorage
{
private const string ArchiveFile = "Archive.zip";
private const string LockFile = "write.lock";
private readonly IAssetStore assetStore;
public AssetStoreDirectoryFactory(IAssetStore assetStore)
public AssetIndexStorage(IAssetStore assetStore)
{
Guard.NotNull(assetStore);
this.assetStore = assetStore;
}
public async Task<LuceneDirectory> CreateAsync(Guid schemaId)
public async Task<LuceneDirectory> CreateDirectoryAsync(Guid schemaId)
{
var directoryInfo = new DirectoryInfo(Path.Combine(Path.GetTempPath(), "LocalIndices", schemaId.ToString()));
@ -64,12 +64,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
return directory;
}
public async Task WriteAsync(IndexWriter writer, SnapshotDeletionPolicy snapshotter)
public async Task WriteAsync(LuceneDirectory directory, SnapshotDeletionPolicy snapshotter)
{
Guard.NotNull(writer);
Guard.NotNull(writer);
Guard.NotNull(directory);
Guard.NotNull(snapshotter);
var directoryInfo = ((FSDirectory)writer.Directory).Directory;
var directoryInfo = ((FSDirectory)directory).Directory;
var commit = snapshotter.Snapshot();
try

6
backend/src/Squidex.Domain.Apps.Entities/Contents/Text/FSDirectoryFactory.cs → backend/src/Squidex.Domain.Apps.Entities/Contents/Text/FileIndexStorage.cs

@ -14,9 +14,9 @@ using LuceneDirectory = Lucene.Net.Store.Directory;
namespace Squidex.Domain.Apps.Entities.Contents.Text
{
public sealed class FSDirectoryFactory : IDirectoryFactory
public sealed class FileIndexStorage : IIndexStorage
{
public Task<LuceneDirectory> CreateAsync(Guid schemaId)
public Task<LuceneDirectory> CreateDirectoryAsync(Guid schemaId)
{
var folderName = $"Indexes/{schemaId}";
var folderPath = Path.Combine(Path.GetTempPath(), folderName);
@ -24,7 +24,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
return Task.FromResult<LuceneDirectory>(FSDirectory.Open(folderPath));
}
public Task WriteAsync(IndexWriter writer, SnapshotDeletionPolicy snapshotter)
public Task WriteAsync(LuceneDirectory directory, SnapshotDeletionPolicy snapshotter)
{
return Task.CompletedTask;
}

28
backend/src/Squidex.Domain.Apps.Entities/Contents/Text/IIndex.cs

@ -0,0 +1,28 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Lucene.Net.Analysis;
using Lucene.Net.Index;
using Lucene.Net.Search;
namespace Squidex.Domain.Apps.Entities.Contents.Text
{
public interface IIndex
{
Analyzer? Analyzer { get; }
IndexReader? Reader { get; }
IndexSearcher? Searcher { get; }
IndexWriter Writer { get; }
void EnsureReader();
void MarkStale();
}
}

6
backend/src/Squidex.Domain.Apps.Entities/Contents/Text/IDirectoryFactory.cs → backend/src/Squidex.Domain.Apps.Entities/Contents/Text/IIndexStorage.cs

@ -12,10 +12,10 @@ using Lucene.Net.Store;
namespace Squidex.Domain.Apps.Entities.Contents.Text
{
public interface IDirectoryFactory
public interface IIndexStorage
{
Task<Directory> CreateAsync(Guid schemaId);
Task<Directory> CreateDirectoryAsync(Guid schemaId);
Task WriteAsync(IndexWriter writer, SnapshotDeletionPolicy snapshotter);
Task WriteAsync(Directory directory, SnapshotDeletionPolicy snapshotter);
}
}

162
backend/src/Squidex.Domain.Apps.Entities/Contents/Text/IndexHolder.cs

@ -1,162 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Lucene.Net.Analysis;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Lucene.Net.Util;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Entities.Contents.Text
{
public sealed class IndexHolder : DisposableObjectBase
{
private const LuceneVersion Version = LuceneVersion.LUCENE_48;
private static readonly MergeScheduler MergeScheduler = new ConcurrentMergeScheduler();
private static readonly Analyzer SharedAnalyzer = new MultiLanguageAnalyzer(Version);
private readonly SnapshotDeletionPolicy snapshotter = new SnapshotDeletionPolicy(new KeepOnlyLastCommitDeletionPolicy());
private readonly Directory directory;
private readonly IDirectoryFactory directoryFactory;
private IndexWriter indexWriter;
private IndexSearcher? indexSearcher;
private DirectoryReader? indexReader;
public Analyzer Analyzer
{
get
{
ThrowIfDisposed();
return SharedAnalyzer;
}
}
public SnapshotDeletionPolicy Snapshotter
{
get
{
ThrowIfDisposed();
return snapshotter;
}
}
public IndexWriter Writer
{
get
{
ThrowIfDisposed();
return indexWriter;
}
}
public IndexReader? Reader
{
get
{
ThrowIfDisposed();
return indexReader;
}
}
public IndexSearcher? Searcher
{
get
{
ThrowIfDisposed();
return indexSearcher;
}
}
public IndexHolder(Directory directory, IDirectoryFactory directoryFactory)
{
this.directory = directory;
this.directoryFactory = directoryFactory;
}
public void Open()
{
RecreateIndexWriter();
if (indexWriter.NumDocs > 0)
{
EnsureReader();
}
}
protected override void DisposeObject(bool disposing)
{
if (disposing)
{
indexWriter?.Dispose();
}
}
private void RecreateIndexWriter()
{
var config = new IndexWriterConfig(Version, Analyzer)
{
IndexDeletionPolicy = snapshotter,
MergePolicy = new TieredMergePolicy(),
MergeScheduler = MergeScheduler
};
indexWriter = new IndexWriter(directory, config);
MarkStale();
}
public void EnsureReader()
{
ThrowIfDisposed();
if (indexReader == null)
{
indexReader = indexWriter.GetReader(true);
indexSearcher = new IndexSearcher(indexReader);
}
}
public void MarkStale()
{
ThrowIfDisposed();
if (indexReader != null)
{
indexReader.Dispose();
indexReader = null;
indexSearcher = null;
}
}
public async Task CommitAsync()
{
ThrowIfDisposed();
try
{
MarkStale();
indexWriter.Commit();
await directoryFactory.WriteAsync(indexWriter, snapshotter);
}
catch (OutOfMemoryException)
{
RecreateIndexWriter();
throw;
}
}
}
}

110
backend/src/Squidex.Domain.Apps.Entities/Contents/Text/IndexHolderFactory.cs

@ -1,110 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Log;
namespace Squidex.Domain.Apps.Entities.Contents.Text
{
public sealed class IndexHolderFactory : DisposableObjectBase
{
private readonly Dictionary<Guid, IndexHolder> indices = new Dictionary<Guid, IndexHolder>();
private readonly SemaphoreSlim lockObject = new SemaphoreSlim(1);
private readonly IDirectoryFactory directoryFactory;
private readonly ISemanticLog log;
public IndexHolderFactory(IDirectoryFactory directoryFactory, ISemanticLog log)
{
Guard.NotNull(directoryFactory);
Guard.NotNull(log);
this.directoryFactory = directoryFactory;
this.log = log;
}
protected override void DisposeObject(bool disposing)
{
if (disposing)
{
try
{
lockObject.Wait();
if (indices.Count > 0)
{
log.LogWarning(w => w
.WriteProperty("message", "Unreleased indices found.")
.WriteProperty("count", indices.Count));
foreach (var index in indices)
{
index.Value.Dispose();
}
indices.Clear();
}
}
finally
{
lockObject.Release();
}
}
}
public async Task<IndexHolder> AcquireAsync(Guid schemaId)
{
IndexHolder? index;
try
{
await lockObject.WaitAsync();
if (indices.TryGetValue(schemaId, out index))
{
log.LogWarning(w => w
.WriteProperty("message", "Unreleased index found.")
.WriteProperty("schemaId", schemaId.ToString()));
index.Dispose();
}
var directory = await directoryFactory.CreateAsync(schemaId);
index = new IndexHolder(directory, directoryFactory);
indices[schemaId] = index;
}
finally
{
lockObject.Release();
}
index.Open();
return index;
}
public void Release(Guid id)
{
try
{
lockObject.Wait();
indices.Remove(id);
}
finally
{
lockObject.Release();
}
}
}
}

148
backend/src/Squidex.Domain.Apps.Entities/Contents/Text/IndexManager.cs

@ -0,0 +1,148 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Log;
namespace Squidex.Domain.Apps.Entities.Contents.Text
{
public sealed partial class IndexManager : DisposableObjectBase
{
private readonly Dictionary<Guid, IndexHolder> indices = new Dictionary<Guid, IndexHolder>();
private readonly SemaphoreSlim lockObject = new SemaphoreSlim(1);
private readonly IIndexStorage directoryFactory;
private readonly ISemanticLog log;
public IndexManager(IIndexStorage directoryFactory, ISemanticLog log)
{
Guard.NotNull(directoryFactory);
Guard.NotNull(log);
this.directoryFactory = directoryFactory;
this.log = log;
}
protected override void DisposeObject(bool disposing)
{
if (disposing)
{
ReleaseAllAsync().Wait();
}
}
public async Task<IIndex> AcquireAsync(Guid schemaId)
{
IndexHolder? indexHolder;
try
{
await lockObject.WaitAsync();
if (indices.TryGetValue(schemaId, out indexHolder))
{
log.LogWarning(w => w
.WriteProperty("message", "Unreleased index found.")
.WriteProperty("schemaId", schemaId.ToString()));
await CommitInternalAsync(indexHolder, true);
}
indexHolder = new IndexHolder(schemaId);
indices[schemaId] = indexHolder;
}
finally
{
lockObject.Release();
}
var directory = await directoryFactory.CreateDirectoryAsync(schemaId);
indexHolder.Open(directory);
return indexHolder;
}
public async Task ReleaseAsync(IIndex index)
{
Guard.NotNull(index);
var indexHolder = (IndexHolder)index;
try
{
lockObject.Wait();
indexHolder.Release();
indices.Remove(indexHolder.Id);
}
finally
{
lockObject.Release();
}
await CommitInternalAsync(indexHolder, true);
}
public Task CommitAsync(IIndex index)
{
Guard.NotNull(index);
return CommitInternalAsync(index, false);
}
private async Task CommitInternalAsync(IIndex index, bool dispose)
{
if (index is IndexHolder holder)
{
if (dispose)
{
holder.Dispose();
}
else
{
holder.Commit();
}
await directoryFactory.WriteAsync(holder.GetUnsafeWriter().Directory, holder.Snapshotter);
}
}
private async Task ReleaseAllAsync()
{
var current = indices.Values.ToList();
try
{
lockObject.Wait();
indices.Clear();
}
finally
{
lockObject.Release();
}
if (current.Count > 0)
{
log.LogWarning(w => w
.WriteProperty("message", "Unreleased indices found.")
.WriteProperty("count", indices.Count));
foreach (var index in current)
{
await CommitInternalAsync(index, true);
}
}
}
}
}

176
backend/src/Squidex.Domain.Apps.Entities/Contents/Text/IndexManager_Impl.cs

@ -0,0 +1,176 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using Lucene.Net.Analysis;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Lucene.Net.Util;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Entities.Contents.Text
{
public sealed partial class IndexManager
{
private sealed class IndexHolder : IDisposable, IIndex
{
private const LuceneVersion Version = LuceneVersion.LUCENE_48;
private static readonly MergeScheduler MergeScheduler = new ConcurrentMergeScheduler();
private static readonly Analyzer SharedAnalyzer = new MultiLanguageAnalyzer(Version);
private readonly SnapshotDeletionPolicy snapshotter = new SnapshotDeletionPolicy(new KeepOnlyLastCommitDeletionPolicy());
private Directory directory;
private IndexWriter indexWriter;
private IndexSearcher? indexSearcher;
private DirectoryReader? indexReader;
private bool isReleased;
public Analyzer Analyzer
{
get { return SharedAnalyzer; }
}
public SnapshotDeletionPolicy Snapshotter
{
get { return snapshotter; }
}
public IndexWriter Writer
{
get
{
ThrowIfReleased();
return indexWriter;
}
}
public IndexReader? Reader
{
get
{
ThrowIfReleased();
return indexReader;
}
}
public IndexSearcher? Searcher
{
get
{
ThrowIfReleased();
return indexSearcher;
}
}
public Guid Id { get; }
public IndexHolder(Guid id)
{
Id = id;
}
public void Dispose()
{
indexReader?.Dispose();
indexWriter?.Dispose();
}
public void Open(Directory directory)
{
Guard.NotNull(directory);
this.directory = directory;
RecreateIndexWriter();
if (indexWriter.NumDocs > 0)
{
EnsureReader();
}
}
private void RecreateIndexWriter()
{
var config = new IndexWriterConfig(Version, Analyzer)
{
IndexDeletionPolicy = snapshotter,
MergePolicy = new TieredMergePolicy(),
MergeScheduler = MergeScheduler
};
indexWriter = new IndexWriter(directory, config);
MarkStale();
}
public void EnsureReader()
{
ThrowIfReleased();
if (indexReader == null)
{
indexReader = indexWriter.GetReader(true);
indexSearcher = new IndexSearcher(indexReader);
}
}
public void MarkStale()
{
ThrowIfReleased();
MarkStaleInternal();
}
private void MarkStaleInternal()
{
if (indexReader != null)
{
indexReader.Dispose();
indexReader = null;
indexSearcher = null;
}
}
internal void Commit()
{
try
{
MarkStaleInternal();
indexWriter.Commit();
}
catch (OutOfMemoryException)
{
RecreateIndexWriter();
throw;
}
}
internal void ThrowIfReleased()
{
if (isReleased)
{
throw new InvalidOperationException("Index is already released.");
}
}
internal void Release()
{
isReleased = true;
}
internal IndexWriter GetUnsafeWriter()
{
return indexWriter;
}
}
}
}

4
backend/src/Squidex.Domain.Apps.Entities/Contents/Text/IndexState.cs

@ -20,11 +20,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
private const int NotFound = -1;
private const string MetaFor = "_fd";
private readonly Dictionary<(Guid, Scope), BytesRef> lastChanges = new Dictionary<(Guid, Scope), BytesRef>();
private readonly IndexHolder index;
private readonly IIndex index;
private IndexReader? lastReader;
private BinaryDocValues binaryValues;
public IndexState(IndexHolder index)
public IndexState(IIndex index)
{
this.index = index;
}

6
backend/src/Squidex.Domain.Apps.Entities/Contents/Text/TextIndexContent.cs

@ -16,11 +16,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
{
private const string MetaId = "_id";
private const string MetaKey = "_key";
private readonly IndexHolder index;
private readonly IIndex index;
private readonly IndexState indexState;
private readonly Guid id;
public TextIndexContent(IndexHolder index, IndexState indexState, Guid id)
public TextIndexContent(IIndex index, IndexState indexState, Guid id)
{
this.index = index;
this.indexState = indexState;
@ -33,7 +33,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
index.Writer.DeleteDocuments(new Term(MetaId, id.ToString()));
}
public static bool TryGetId(int docId, Scope scope, IndexHolder index, IndexState indexState, out Guid result)
public static bool TryGetId(int docId, Scope scope, IIndex index, IndexState indexState, out Guid result)
{
result = Guid.Empty;

38
backend/src/Squidex.Domain.Apps.Entities/Contents/Text/TextIndexerGrain.cs

@ -26,32 +26,32 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
private const int MaxUpdates = 400;
private static readonly TimeSpan CommitDelay = TimeSpan.FromSeconds(10);
private static readonly string[] Invariant = { InvariantPartitioning.Key };
private readonly IndexHolderFactory indexHolderFactory;
private readonly IndexManager indexManager;
private IDisposable? timer;
private IndexHolder index;
private IIndex index;
private IndexState indexState;
private QueryParser? queryParser;
private HashSet<string>? currentLanguages;
private int updates;
public TextIndexerGrain(IndexHolderFactory indexHolderFactory)
public TextIndexerGrain(IndexManager indexManager)
{
Guard.NotNull(indexHolderFactory);
Guard.NotNull(indexManager);
this.indexHolderFactory = indexHolderFactory;
this.indexManager = indexManager;
}
public override Task OnDeactivateAsync()
public override async Task OnDeactivateAsync()
{
index?.Dispose();
indexHolderFactory.Release(Key);
return Task.CompletedTask;
if (index != null)
{
await indexManager.ReleaseAsync(index);
}
}
protected override async Task OnActivateAsync(Guid key)
{
index = await indexHolderFactory.AcquireAsync(key);
index = await indexManager.AcquireAsync(key);
indexState = new IndexState(index);
}
@ -62,7 +62,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
content.Index(update.Text, update.OnlyDraft);
return TryFlushAsync();
return TryCommitAsync();
}
public Task<bool> CopyAsync(Guid id, bool fromDraft)
@ -71,7 +71,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
content.Copy(fromDraft);
return TryFlushAsync();
return TryCommitAsync();
}
public Task<bool> DeleteAsync(Guid id)
@ -80,7 +80,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
content.Delete();
return TryFlushAsync();
return TryCommitAsync();
}
public Task<List<Guid>> SearchAsync(string queryText, SearchContext context)
@ -139,7 +139,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
}
}
private async Task<bool> TryFlushAsync()
private async Task<bool> TryCommitAsync()
{
timer?.Dispose();
@ -147,7 +147,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
if (updates >= MaxUpdates)
{
await FlushAsync();
await CommitAsync();
return true;
}
@ -157,7 +157,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
try
{
timer = RegisterTimer(_ => FlushAsync(), null, CommitDelay, CommitDelay);
timer = RegisterTimer(_ => CommitAsync(), null, CommitDelay, CommitDelay);
}
catch (InvalidOperationException)
{
@ -168,11 +168,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
return false;
}
public async Task FlushAsync()
public async Task CommitAsync()
{
if (updates > 0)
{
await index.CommitAsync();
await indexManager.CommitAsync(index);
updates = 0;
}

2
backend/src/Squidex/Config/Domain/ContentsServices.cs

@ -51,7 +51,7 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<GrainTextIndexer>()
.As<ITextIndexer>().As<IEventConsumer>();
services.AddSingletonAs<IndexHolderFactory>()
services.AddSingletonAs<IndexManager>()
.AsSelf();
services.AddSingletonAs<GrainBootstrap<IContentSchedulerGrain>>()

4
backend/src/Squidex/Config/Domain/StoreServices.cs

@ -133,8 +133,8 @@ namespace Squidex.Config.Domain
BucketName = "fullText"
});
return new MongoDirectoryFactory(mongoBucket);
}).As<IDirectoryFactory>();
return new MongoIndexStorage(mongoBucket);
}).As<IIndexStorage>();
}
});

2
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerBenchmark.cs

@ -22,7 +22,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
public TextIndexerBenchmark()
{
var factory = new IndexHolderFactory(new FSDirectoryFactory(), A.Fake<ISemanticLog>());
var factory = new IndexManager(new FileIndexStorage(), A.Fake<ISemanticLog>());
sut = new TextIndexerGrain(factory);
sut.ActivateAsync(schemaId).Wait();

6
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerGrainTestsBase.cs

@ -25,7 +25,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
private readonly SearchContext context;
private readonly TextIndexerGrain sut;
public abstract IDirectoryFactory DirectoryFactory { get; }
public abstract IIndexStorage Storage { get; }
protected TextIndexerGrainTestsBase()
{
@ -34,7 +34,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
Languages = new HashSet<string> { "de", "en" }
};
var factory = new IndexHolderFactory(DirectoryFactory, A.Fake<ISemanticLog>());
var factory = new IndexManager(Storage, A.Fake<ISemanticLog>());
sut = new TextIndexerGrain(factory);
sut.ActivateAsync(schemaId).Wait();
@ -58,7 +58,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
await sut.OnDeactivateAsync();
var other = new TextIndexerGrain(new IndexHolderFactory(DirectoryFactory, A.Fake<ISemanticLog>()));
var other = new TextIndexerGrain(new IndexManager(Storage, A.Fake<ISemanticLog>()));
try
{
await other.ActivateAsync(schemaId);

23
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerGrainTests_Assets.cs

@ -0,0 +1,23 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Squidex.Infrastructure.Assets;
namespace Squidex.Domain.Apps.Entities.Contents.Text
{
public class TextIndexerGrainTests_Assets : TextIndexerGrainTestsBase
{
public override IIndexStorage Storage { get; } = CreateStorage();
private static IIndexStorage CreateStorage()
{
var storage = new AssetIndexStorage(new MemoryAssetStore());
return storage;
}
}
}

8
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerGrainTests_FS.cs

@ -9,13 +9,13 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
{
public class TextIndexerGrainTests_FS : TextIndexerGrainTestsBase
{
public override IDirectoryFactory DirectoryFactory => CreateFactory();
public override IIndexStorage Storage => CreateStorage();
private static IDirectoryFactory CreateFactory()
private static IIndexStorage CreateStorage()
{
var directoryFactory = new FSDirectoryFactory();
var storage = new FileIndexStorage();
return directoryFactory;
return storage;
}
}
}

8
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerGrainTests_Mongo.cs

@ -13,9 +13,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
{
internal class TextIndexerGrainTests_Mongo : TextIndexerGrainTestsBase
{
public override IDirectoryFactory DirectoryFactory => CreateFactory();
public override IIndexStorage Storage => CreateStorage();
private static IDirectoryFactory CreateFactory()
private static IIndexStorage CreateStorage()
{
var mongoClient = new MongoClient("mongodb://localhost");
var mongoDatabase = mongoClient.GetDatabase("FullText");
@ -25,9 +25,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
BucketName = "fs"
});
var directoryFactory = new MongoDirectoryFactory(mongoBucket);
var storage = new MongoIndexStorage(mongoBucket);
return directoryFactory;
return storage;
}
}
}

Loading…
Cancel
Save