Skip to content

Commit 0f89cd2

Browse files
committed
Added concurrency to AddNestedTopicsAsync
`AddNestedTopicsAsync()` now implements a local `taskQueue` so that it can process multiple children simultaneously. It also implements a lock pattern so that those children are only added to the source collection once they're fully populated; this avoids potential race conditions with concurrency where duplicates could be added to the cached topic.
1 parent bb46923 commit 0f89cd2

1 file changed

Lines changed: 46 additions & 8 deletions

File tree

Ignia.Topics.Web.Mvc/Controllers/LayoutControllerBase{T}.cs

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
| Project Topics Library
55
\=============================================================================================================================*/
66
using System;
7+
using System.Collections.Generic;
78
using System.Linq;
89
using System.Threading.Tasks;
910
using System.Web.Mvc;
@@ -198,22 +199,59 @@ protected async Task<T> AddNestedTopicsAsync(
198199
bool allowPageGroups = true,
199200
int tiers = 1
200201
) {
202+
203+
/*------------------------------------------------------------------------------------------------------------------------
204+
| Validate preconditions
205+
\-----------------------------------------------------------------------------------------------------------------------*/
201206
tiers--;
202207
if (sourceTopic == null) {
203208
return null;
204209
}
205-
var viewModel = await _topicMappingService.MapAsync<T>(sourceTopic, Relationships.None);
210+
211+
/*------------------------------------------------------------------------------------------------------------------------
212+
| Establish variables
213+
\-----------------------------------------------------------------------------------------------------------------------*/
214+
var taskQueue = new List<Task<T>>();
215+
var children = new List<T>();
216+
var viewModel = (T)null;
217+
218+
/*------------------------------------------------------------------------------------------------------------------------
219+
| Map object
220+
\-----------------------------------------------------------------------------------------------------------------------*/
221+
viewModel = await _topicMappingService.MapAsync<T>(sourceTopic, Relationships.None);
222+
223+
/*------------------------------------------------------------------------------------------------------------------------
224+
| Request mapping of children
225+
\-----------------------------------------------------------------------------------------------------------------------*/
206226
if (tiers >= 0 && (allowPageGroups || !sourceTopic.ContentType.Equals("PageGroup")) && viewModel.Children.Count == 0) {
207227
foreach (var topic in sourceTopic.Children.Where(t => t.IsVisible())) {
208-
viewModel.Children.Add(
209-
await AddNestedTopicsAsync(
210-
topic,
211-
allowPageGroups,
212-
tiers
213-
)
214-
);
228+
taskQueue.Add(AddNestedTopicsAsync(topic, allowPageGroups, tiers));
215229
}
216230
}
231+
232+
/*------------------------------------------------------------------------------------------------------------------------
233+
| Process children
234+
\-----------------------------------------------------------------------------------------------------------------------*/
235+
while (taskQueue.Count > 0 && viewModel.Children.Count == 0) {
236+
var dtoTask = await Task.WhenAny(taskQueue);
237+
taskQueue.Remove(dtoTask);
238+
children.Add(await dtoTask);
239+
}
240+
241+
/*------------------------------------------------------------------------------------------------------------------------
242+
| Add children to view model
243+
\-----------------------------------------------------------------------------------------------------------------------*/
244+
if (viewModel.Children.Count == 0) {
245+
lock (viewModel) {
246+
if (viewModel.Children.Count == 0) {
247+
children.ForEach(c => viewModel.Children.Add(c));
248+
}
249+
}
250+
}
251+
252+
/*------------------------------------------------------------------------------------------------------------------------
253+
| Return view model
254+
\-----------------------------------------------------------------------------------------------------------------------*/
217255
return viewModel;
218256
}
219257

0 commit comments

Comments
 (0)