Skip to content

Commit b755629

Browse files
authored
Fixed a multithreading bug where index can be called multiple times. (#142)
* Fixed a multithreading bug where index can be called multiple times. * Ensures index deletion is thread-safe. Makes the index deletion operation thread-safe by acquiring a lock before deleting the index and resetting the `_isEnsured` flag.
1 parent e1a78e8 commit b755629

File tree

2 files changed

+25
-10
lines changed

2 files changed

+25
-10
lines changed

src/Foundatio.Repositories.Elasticsearch/Configuration/Index.cs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
using System;
1+
using System;
2+
using System.Collections.Concurrent;
23
using System.Collections.Generic;
34
using System.Linq;
45
using System.Linq.Expressions;
56
using System.Threading.Tasks;
7+
using Foundatio.AsyncEx;
68
using Foundatio.Parsers.ElasticQueries;
79
using Foundatio.Parsers.ElasticQueries.Extensions;
810
using Foundatio.Parsers.LuceneQueries.Visitors;
@@ -26,8 +28,9 @@ public class Index : IIndex
2628
private readonly Lazy<ElasticQueryParser> _queryParser;
2729
private readonly Lazy<ElasticMappingResolver> _mappingResolver;
2830
private readonly Lazy<QueryFieldResolver> _fieldResolver;
31+
private readonly ConcurrentDictionary<string, ICustomFieldType> _customFieldTypes = new();
32+
private readonly AsyncLock _lock = new();
2933
protected readonly ILogger _logger;
30-
private readonly IDictionary<string, ICustomFieldType> _customFieldTypes = new Dictionary<string, ICustomFieldType>();
3134

3235
public Index(IElasticConfiguration configuration, string name = null)
3336
{
@@ -149,14 +152,14 @@ public virtual async Task EnsureIndexAsync(object target)
149152
if (_isEnsured)
150153
return;
151154

152-
bool existsResult = await IndexExistsAsync(Name).AnyContext();
153-
if (existsResult)
155+
using (await _lock.LockAsync().AnyContext())
154156
{
157+
if (_isEnsured)
158+
return;
159+
160+
await ConfigureAsync().AnyContext();
155161
_isEnsured = true;
156-
return;
157162
}
158-
159-
await ConfigureAsync().AnyContext();
160163
}
161164

162165
public virtual Task MaintainAsync(bool includeOptionalTasks = true)
@@ -176,9 +179,13 @@ public virtual IPromise<IAliases> ConfigureIndexAliases(AliasesDescriptor aliase
176179

177180
public int BulkBatchSize { get; set; } = 1000;
178181

179-
public virtual Task DeleteAsync()
182+
public virtual async Task DeleteAsync()
180183
{
181-
return DeleteIndexAsync(Name);
184+
using (await _lock.LockAsync().AnyContext())
185+
{
186+
await DeleteIndexAsync(Name).AnyContext();
187+
_isEnsured = false;
188+
}
182189
}
183190

184191
protected virtual async Task CreateIndexAsync(string name, Func<CreateIndexDescriptor, CreateIndexDescriptor> descriptor = null)

src/Foundatio.Repositories/Extensions/TaskExtensions.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
using System.Diagnostics;
1+
using System;
2+
using System.Diagnostics;
23
using System.Runtime.CompilerServices;
34
using System.Threading.Tasks;
5+
using Foundatio.AsyncEx;
46

57
namespace Foundatio.Repositories.Extensions;
68

@@ -17,4 +19,10 @@ public static ConfiguredTaskAwaitable AnyContext(this Task task)
1719
{
1820
return task.ConfigureAwait(continueOnCapturedContext: false);
1921
}
22+
23+
[DebuggerStepThrough]
24+
public static ConfiguredTaskAwaitable<TResult> AnyContext<TResult>(this AwaitableDisposable<TResult> task) where TResult : IDisposable
25+
{
26+
return task.ConfigureAwait(continueOnCapturedContext: false);
27+
}
2028
}

0 commit comments

Comments
 (0)