mirror of https://github.com/Squidex/squidex.git
committed by
GitHub
16 changed files with 343 additions and 525 deletions
@ -1,150 +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.IO; |
|
||||
using System.Linq; |
|
||||
using Lucene.Net.Store; |
|
||||
using MongoDB.Bson; |
|
||||
using MongoDB.Driver; |
|
||||
using MongoDB.Driver.GridFS; |
|
||||
using LuceneDirectory = Lucene.Net.Store.Directory; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.FullText |
|
||||
{ |
|
||||
public sealed class MongoDirectory : BaseDirectory |
|
||||
{ |
|
||||
private readonly IGridFSBucket<string> bucket; |
|
||||
private readonly string directory; |
|
||||
private readonly DirectoryInfo cacheDirectoryInfo; |
|
||||
private readonly LuceneDirectory cacheDirectory; |
|
||||
private bool isDisposed; |
|
||||
|
|
||||
public LuceneDirectory CacheDirectory |
|
||||
{ |
|
||||
get { return cacheDirectory; } |
|
||||
} |
|
||||
|
|
||||
public DirectoryInfo CacheDirectoryInfo |
|
||||
{ |
|
||||
get { return cacheDirectoryInfo; } |
|
||||
} |
|
||||
|
|
||||
public IGridFSBucket<string> Bucket |
|
||||
{ |
|
||||
get { return bucket; } |
|
||||
} |
|
||||
|
|
||||
public MongoDirectory(IGridFSBucket<string> bucket, string directory, DirectoryInfo cacheDirectoryInfo) |
|
||||
{ |
|
||||
this.bucket = bucket; |
|
||||
|
|
||||
this.directory = directory; |
|
||||
|
|
||||
this.cacheDirectoryInfo = cacheDirectoryInfo; |
|
||||
|
|
||||
cacheDirectoryInfo.Create(); |
|
||||
cacheDirectory = FSDirectory.Open(cacheDirectoryInfo); |
|
||||
|
|
||||
SetLockFactory(new NativeFSLockFactory(cacheDirectoryInfo)); |
|
||||
} |
|
||||
|
|
||||
protected override void Dispose(bool disposing) |
|
||||
{ |
|
||||
if (disposing) |
|
||||
{ |
|
||||
isDisposed = true; |
|
||||
|
|
||||
cacheDirectory.Dispose(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public override string GetLockID() |
|
||||
{ |
|
||||
return cacheDirectory.GetLockID(); |
|
||||
} |
|
||||
|
|
||||
public override IndexOutput CreateOutput(string name, IOContext context) |
|
||||
{ |
|
||||
return new MongoIndexOutput(this, context, name); |
|
||||
} |
|
||||
|
|
||||
public override IndexInput OpenInput(string name, IOContext context) |
|
||||
{ |
|
||||
return new MongoIndexInput(this, context, name); |
|
||||
} |
|
||||
|
|
||||
public override void DeleteFile(string name) |
|
||||
{ |
|
||||
EnsureNotDisposed(); |
|
||||
|
|
||||
var fullName = GetFullName(name); |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
Bucket.Delete(fullName); |
|
||||
} |
|
||||
catch (GridFSFileNotFoundException) |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public override long FileLength(string name) |
|
||||
{ |
|
||||
EnsureNotDisposed(); |
|
||||
|
|
||||
var file = FindFile(name) ?? throw new FileNotFoundException(null, GetFullName(name)); |
|
||||
|
|
||||
return file.Length; |
|
||||
} |
|
||||
|
|
||||
public override string[] ListAll() |
|
||||
{ |
|
||||
EnsureNotDisposed(); |
|
||||
|
|
||||
var files = Bucket.Find(Builders<GridFSFileInfo<string>>.Filter.Regex(x => x.Id, new BsonRegularExpression($"^{directory}/"))).ToList(); |
|
||||
|
|
||||
return files.Select(x => x.Filename).ToArray(); |
|
||||
} |
|
||||
|
|
||||
public GridFSFileInfo<string>? FindFile(string name) |
|
||||
{ |
|
||||
var fullName = GetFullName(name); |
|
||||
|
|
||||
return Bucket.Find(Builders<GridFSFileInfo<string>>.Filter.Eq(x => x.Id, fullName)).FirstOrDefault(); |
|
||||
} |
|
||||
|
|
||||
public override void Sync(ICollection<string> names) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
[Obsolete] |
|
||||
public override bool FileExists(string name) |
|
||||
{ |
|
||||
throw new NotSupportedException(); |
|
||||
} |
|
||||
|
|
||||
public string GetFullName(string name) |
|
||||
{ |
|
||||
return $"{directory}/{name}"; |
|
||||
} |
|
||||
|
|
||||
public string GetFullPath(string name) |
|
||||
{ |
|
||||
return Path.Combine(cacheDirectoryInfo.FullName, name); |
|
||||
} |
|
||||
|
|
||||
private void EnsureNotDisposed() |
|
||||
{ |
|
||||
if (isDisposed) |
|
||||
{ |
|
||||
throw new ObjectDisposedException(GetType().FullName); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,105 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System.IO; |
|
||||
using Lucene.Net.Store; |
|
||||
using MongoDB.Driver.GridFS; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.FullText |
|
||||
{ |
|
||||
public sealed class MongoIndexInput : IndexInput |
|
||||
{ |
|
||||
private readonly IndexInput cacheInput; |
|
||||
private readonly MongoDirectory indexDirectory; |
|
||||
private readonly IOContext context; |
|
||||
private readonly string indexFileName; |
|
||||
|
|
||||
public override long Length |
|
||||
{ |
|
||||
get { return cacheInput.Length; } |
|
||||
} |
|
||||
|
|
||||
public MongoIndexInput(MongoDirectory indexDirectory, IOContext context, string indexFileName) |
|
||||
: base(indexDirectory.GetFullName(indexFileName)) |
|
||||
{ |
|
||||
this.indexDirectory = indexDirectory; |
|
||||
this.indexFileName = indexFileName; |
|
||||
|
|
||||
this.context = context; |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
var file = indexDirectory.FindFile(indexFileName); |
|
||||
|
|
||||
if (file != null) |
|
||||
{ |
|
||||
var fileInfo = new FileInfo(indexDirectory.GetFullPath(indexFileName)); |
|
||||
|
|
||||
var writtenTime = file.Metadata["WrittenTime"].ToUniversalTime(); |
|
||||
|
|
||||
if (!fileInfo.Exists || fileInfo.LastWriteTimeUtc < writtenTime) |
|
||||
{ |
|
||||
using (var fs = new FileStream(fileInfo.FullName, FileMode.Create, FileAccess.Write)) |
|
||||
{ |
|
||||
var fullName = indexDirectory.GetFullName(indexFileName); |
|
||||
|
|
||||
indexDirectory.Bucket.DownloadToStream(fullName, fs); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
catch (GridFSFileNotFoundException) |
|
||||
{ |
|
||||
throw new FileNotFoundException(); |
|
||||
} |
|
||||
|
|
||||
cacheInput = indexDirectory.CacheDirectory.OpenInput(indexFileName, context); |
|
||||
} |
|
||||
|
|
||||
public MongoIndexInput(MongoIndexInput source) |
|
||||
: base("clone") |
|
||||
{ |
|
||||
cacheInput = (IndexInput)source.cacheInput.Clone(); |
|
||||
context = source.context; |
|
||||
indexDirectory = source.indexDirectory; |
|
||||
indexFileName = source.indexFileName; |
|
||||
} |
|
||||
|
|
||||
protected override void Dispose(bool disposing) |
|
||||
{ |
|
||||
if (disposing) |
|
||||
{ |
|
||||
cacheInput.Dispose(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public override long GetFilePointer() |
|
||||
{ |
|
||||
return cacheInput.GetFilePointer(); |
|
||||
} |
|
||||
|
|
||||
public override byte ReadByte() |
|
||||
{ |
|
||||
return cacheInput.ReadByte(); |
|
||||
} |
|
||||
|
|
||||
public override void ReadBytes(byte[] b, int offset, int len) |
|
||||
{ |
|
||||
cacheInput.ReadBytes(b, offset, len); |
|
||||
} |
|
||||
|
|
||||
public override void Seek(long pos) |
|
||||
{ |
|
||||
cacheInput.Seek(pos); |
|
||||
} |
|
||||
|
|
||||
public override object Clone() |
|
||||
{ |
|
||||
return new MongoIndexInput(indexDirectory, context, indexFileName); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,114 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.IO; |
|
||||
using System.Linq; |
|
||||
using Lucene.Net.Store; |
|
||||
using MongoDB.Bson; |
|
||||
using MongoDB.Driver; |
|
||||
using MongoDB.Driver.GridFS; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.FullText |
|
||||
{ |
|
||||
public sealed class MongoIndexOutput : IndexOutput |
|
||||
{ |
|
||||
private readonly IndexOutput cacheOutput; |
|
||||
private readonly MongoDirectory indexDirectory; |
|
||||
private readonly string indexFileName; |
|
||||
private bool isFlushed; |
|
||||
private bool isWritten; |
|
||||
|
|
||||
public override long Length |
|
||||
{ |
|
||||
get { return cacheOutput.Length; } |
|
||||
} |
|
||||
|
|
||||
public override long Checksum |
|
||||
{ |
|
||||
get { return cacheOutput.Checksum; } |
|
||||
} |
|
||||
|
|
||||
public MongoIndexOutput(MongoDirectory indexDirectory, IOContext context, string indexFileName) |
|
||||
{ |
|
||||
this.indexDirectory = indexDirectory; |
|
||||
this.indexFileName = indexFileName; |
|
||||
|
|
||||
cacheOutput = indexDirectory.CacheDirectory.CreateOutput(indexFileName, context); |
|
||||
} |
|
||||
|
|
||||
protected override void Dispose(bool disposing) |
|
||||
{ |
|
||||
if (disposing) |
|
||||
{ |
|
||||
Flush(); |
|
||||
|
|
||||
cacheOutput.Dispose(); |
|
||||
|
|
||||
if (isWritten && isFlushed) |
|
||||
{ |
|
||||
var fileInfo = new FileInfo(indexDirectory.GetFullPath(indexFileName)); |
|
||||
|
|
||||
using (var fs = new FileStream(indexDirectory.GetFullPath(indexFileName), FileMode.Open, FileAccess.Read)) |
|
||||
{ |
|
||||
var fullName = indexDirectory.GetFullName(indexFileName); |
|
||||
|
|
||||
var options = new GridFSUploadOptions |
|
||||
{ |
|
||||
Metadata = new BsonDocument |
|
||||
{ |
|
||||
["WrittenTime"] = fileInfo.LastWriteTimeUtc |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
indexDirectory.Bucket.UploadFromStream(fullName, indexFileName, fs, options); |
|
||||
} |
|
||||
catch (MongoBulkWriteException ex) when (ex.WriteErrors.Any(x => x.Code == 11000)) |
|
||||
{ |
|
||||
indexDirectory.Bucket.Delete(fullName); |
|
||||
indexDirectory.Bucket.UploadFromStream(fullName, indexFileName, fs, options); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public override long GetFilePointer() |
|
||||
{ |
|
||||
return cacheOutput.GetFilePointer(); |
|
||||
} |
|
||||
|
|
||||
public override void Flush() |
|
||||
{ |
|
||||
cacheOutput.Flush(); |
|
||||
|
|
||||
isFlushed = true; |
|
||||
} |
|
||||
|
|
||||
public override void WriteByte(byte b) |
|
||||
{ |
|
||||
cacheOutput.WriteByte(b); |
|
||||
|
|
||||
isWritten = true; |
|
||||
} |
|
||||
|
|
||||
public override void WriteBytes(byte[] b, int offset, int length) |
|
||||
{ |
|
||||
cacheOutput.WriteBytes(b, offset, length); |
|
||||
|
|
||||
isWritten = true; |
|
||||
} |
|
||||
|
|
||||
[Obsolete] |
|
||||
public override void Seek(long pos) |
|
||||
{ |
|
||||
cacheOutput.Seek(pos); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,117 +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.Tasks; |
|
||||
using FakeItEasy; |
|
||||
using Orleans.Concurrency; |
|
||||
using Squidex.Domain.Apps.Entities.Contents.Text.Lucene; |
|
||||
using Squidex.Infrastructure; |
|
||||
using Squidex.Infrastructure.Log; |
|
||||
using Xunit; |
|
||||
|
|
||||
#pragma warning disable xUnit1004 // Test methods should not be skipped
|
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.Contents.Text |
|
||||
{ |
|
||||
[Trait("Category", "Dependencies")] |
|
||||
public class TextIndexerBenchmark |
|
||||
{ |
|
||||
private const int Size = 200; |
|
||||
private readonly NamedId<Guid> appId = NamedId.Of(Guid.NewGuid(), "my-app"); |
|
||||
private readonly NamedId<Guid> schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); |
|
||||
|
|
||||
[Fact] |
|
||||
public async Task Should_index_and_search_in_temp_folder() |
|
||||
{ |
|
||||
await IndexAndSearchAsync(TestStorages.TempFolder()); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public async Task Should_index_and_search_in_assets() |
|
||||
{ |
|
||||
await IndexAndSearchAsync(TestStorages.Assets()); |
|
||||
} |
|
||||
|
|
||||
[Fact] |
|
||||
public async Task Should_index_and_search_in_mongoDB() |
|
||||
{ |
|
||||
await IndexAndSearchAsync(TestStorages.MongoDB()); |
|
||||
} |
|
||||
|
|
||||
private async Task IndexAndSearchAsync(IIndexStorage storage) |
|
||||
{ |
|
||||
var factory = new IndexManager(storage, A.Fake<ISemanticLog>()); |
|
||||
|
|
||||
var grain = new LuceneTextIndexGrain(factory); |
|
||||
|
|
||||
await grain.ActivateAsync(appId.Id); |
|
||||
|
|
||||
var elapsed1 = await IndexAsync(grain); |
|
||||
var elapsed2 = await SearchAsync(grain); |
|
||||
var elapsed3 = await SearchAsync(grain); |
|
||||
|
|
||||
Assert.Equal(new long[0], new[] { elapsed1, elapsed2, elapsed3 }); |
|
||||
} |
|
||||
|
|
||||
private async Task<long> IndexAsync(LuceneTextIndexGrain grain) |
|
||||
{ |
|
||||
var text = new Dictionary<string, string> |
|
||||
{ |
|
||||
["iv"] = "Hello World" |
|
||||
}; |
|
||||
|
|
||||
var ids = new Guid[Size]; |
|
||||
|
|
||||
for (var i = 0; i < ids.Length; i++) |
|
||||
{ |
|
||||
ids[i] = Guid.NewGuid(); |
|
||||
} |
|
||||
|
|
||||
var watch = ValueStopwatch.StartNew(); |
|
||||
|
|
||||
foreach (var id in ids) |
|
||||
{ |
|
||||
var commands = new IndexCommand[] |
|
||||
{ |
|
||||
new UpsertIndexEntry |
|
||||
{ |
|
||||
ContentId = id, |
|
||||
DocId = id.ToString(), |
|
||||
ServeAll = true, |
|
||||
ServePublished = true, |
|
||||
Texts = text |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
await grain.IndexAsync(schemaId, commands.AsImmutable()); |
|
||||
} |
|
||||
|
|
||||
return watch.Stop(); |
|
||||
} |
|
||||
|
|
||||
private async Task<long> SearchAsync(LuceneTextIndexGrain grain) |
|
||||
{ |
|
||||
var searchContext = new SearchContext |
|
||||
{ |
|
||||
Languages = new HashSet<string>() |
|
||||
}; |
|
||||
|
|
||||
var watch = ValueStopwatch.StartNew(); |
|
||||
|
|
||||
for (var i = 0; i < Size; i++) |
|
||||
{ |
|
||||
var result = await grain.SearchAsync("Hello", default, searchContext); |
|
||||
|
|
||||
Assert.NotEmpty(result); |
|
||||
} |
|
||||
|
|
||||
return watch.Stop(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,24 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
<PropertyGroup> |
||||
|
<OutputType>Exe</OutputType> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
</PropertyGroup> |
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="BenchmarkDotNet" Version="0.12.0" /> |
||||
|
<PackageReference Include="Lorem.Universal.Net" Version="3.0.64" /> |
||||
|
<PackageReference Include="Microsoft.Orleans.Core.Abstractions" Version="3.1.2" /> |
||||
|
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> |
||||
|
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> |
||||
|
</ItemGroup> |
||||
|
<PropertyGroup> |
||||
|
<CodeAnalysisRuleSet>..\..\Squidex.ruleset</CodeAnalysisRuleSet> |
||||
|
</PropertyGroup> |
||||
|
<ItemGroup> |
||||
|
<AdditionalFiles Include="..\..\stylecop.json" Link="stylecop.json" /> |
||||
|
</ItemGroup> |
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Entities.MongoDb\Squidex.Domain.Apps.Entities.MongoDb.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Entities\Squidex.Domain.Apps.Entities.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\Squidex.Infrastructure\Squidex.Infrastructure.csproj" /> |
||||
|
</ItemGroup> |
||||
|
</Project> |
||||
@ -0,0 +1,49 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using MongoDB.Driver; |
||||
|
using MongoDB.Driver.GridFS; |
||||
|
using Squidex.Domain.Apps.Entities.Contents.Text.Lucene; |
||||
|
using Squidex.Domain.Apps.Entities.Contents.Text.Lucene.Storage; |
||||
|
using Squidex.Domain.Apps.Entities.MongoDb.FullText; |
||||
|
using Squidex.Infrastructure.Assets; |
||||
|
|
||||
|
namespace Benchmarks |
||||
|
{ |
||||
|
public static class IndexStorages |
||||
|
{ |
||||
|
public static IIndexStorage Assets() |
||||
|
{ |
||||
|
var storage = new AssetIndexStorage(new MemoryAssetStore()); |
||||
|
|
||||
|
return storage; |
||||
|
} |
||||
|
|
||||
|
public static IIndexStorage TempFolder() |
||||
|
{ |
||||
|
var storage = new FileIndexStorage(); |
||||
|
|
||||
|
return storage; |
||||
|
} |
||||
|
|
||||
|
public static IIndexStorage MongoDB() |
||||
|
{ |
||||
|
var mongoClient = new MongoClient("mongodb://localhost"); |
||||
|
var mongoDatabase = mongoClient.GetDatabase("FullText"); |
||||
|
|
||||
|
var mongoBucket = new GridFSBucket<string>(mongoDatabase, new GridFSBucketOptions |
||||
|
{ |
||||
|
BucketName = $"bucket_{DateTime.UtcNow.Ticks}" |
||||
|
}); |
||||
|
|
||||
|
var storage = new MongoIndexStorage(mongoBucket); |
||||
|
|
||||
|
return storage; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,103 @@ |
|||||
|
// ==========================================================================
|
||||
|
// 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.Tasks; |
||||
|
using BenchmarkDotNet.Attributes; |
||||
|
using Benchmarks.Utils; |
||||
|
using LoremNET; |
||||
|
using Orleans.Concurrency; |
||||
|
using Squidex.Domain.Apps.Entities.Contents.Text; |
||||
|
using Squidex.Domain.Apps.Entities.Contents.Text.Lucene; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Benchmarks |
||||
|
{ |
||||
|
[ShortRunJob] |
||||
|
[StopOnFirstError] |
||||
|
[RPlotExporter] |
||||
|
public class IndexingBenchmarks |
||||
|
{ |
||||
|
private readonly IIndexStorage storageAssets = IndexStorages.Assets(); |
||||
|
private readonly IIndexStorage storageTempFolder = IndexStorages.TempFolder(); |
||||
|
private readonly IIndexStorage storageMongoDB = IndexStorages.MongoDB(); |
||||
|
private readonly Dictionary<string, string> texts; |
||||
|
|
||||
|
public IndexingBenchmarks() |
||||
|
{ |
||||
|
texts = new Dictionary<string, string> |
||||
|
{ |
||||
|
["iv"] = Lorem.Paragraph(10, 10) |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
[Params(1000)] |
||||
|
public int N { get; set; } |
||||
|
|
||||
|
[Params(10)] |
||||
|
public int M { get; set; } |
||||
|
|
||||
|
[Benchmark(Baseline = true)] |
||||
|
public async Task Index_TempFolder() |
||||
|
{ |
||||
|
await IndexAndSearchAsync(storageTempFolder); |
||||
|
} |
||||
|
|
||||
|
[Benchmark] |
||||
|
public async Task Index_Assets() |
||||
|
{ |
||||
|
await IndexAndSearchAsync(storageAssets); |
||||
|
} |
||||
|
|
||||
|
[Benchmark] |
||||
|
public async Task Index_MongoDB() |
||||
|
{ |
||||
|
await IndexAndSearchAsync(storageMongoDB); |
||||
|
} |
||||
|
|
||||
|
private async Task IndexAndSearchAsync(IIndexStorage storage) |
||||
|
{ |
||||
|
var schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); |
||||
|
|
||||
|
var factory = new IndexManager(storage, new NoopLog()); |
||||
|
|
||||
|
var grain = new LuceneTextIndexGrain(factory); |
||||
|
|
||||
|
await grain.ActivateAsync(Guid.NewGuid()); |
||||
|
|
||||
|
for (var i = 0; i < M; i++) |
||||
|
{ |
||||
|
var ids = new Guid[N]; |
||||
|
|
||||
|
for (var j = 0; j < ids.Length; j++) |
||||
|
{ |
||||
|
ids[j] = Guid.NewGuid(); |
||||
|
} |
||||
|
|
||||
|
foreach (var id in ids) |
||||
|
{ |
||||
|
var commands = new IndexCommand[] |
||||
|
{ |
||||
|
new UpsertIndexEntry |
||||
|
{ |
||||
|
ContentId = id, |
||||
|
DocId = id.ToString(), |
||||
|
ServeAll = true, |
||||
|
ServePublished = true, |
||||
|
Texts = texts |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
await grain.IndexAsync(schemaId, commands.AsImmutable()); |
||||
|
} |
||||
|
|
||||
|
await grain.CommitAsync(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using BenchmarkDotNet.Running; |
||||
|
|
||||
|
namespace Benchmarks |
||||
|
{ |
||||
|
public static class Program |
||||
|
{ |
||||
|
public static void Main() |
||||
|
{ |
||||
|
BenchmarkRunner.Run<IndexingBenchmarks>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using Squidex.Infrastructure.Log; |
||||
|
|
||||
|
namespace Benchmarks.Utils |
||||
|
{ |
||||
|
public sealed class NoopLog : ISemanticLog |
||||
|
{ |
||||
|
public ISemanticLog CreateScope(Action<IObjectWriter> objectWriter) |
||||
|
{ |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
public void Log<T>(SemanticLogLevel logLevel, T context, Exception exception, LogFormatter<T> action) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public void Log(SemanticLogLevel logLevel, Exception exception, LogFormatter action) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue