fix(advanced-search): C/G follow-up - cover synchronous setup + test isolation in try/finally
This commit is contained in:
parent
98e3451927
commit
f8c594779e
2 changed files with 78 additions and 62 deletions
|
|
@ -77,10 +77,19 @@ public class AdvancedSearchWorkerTests
|
|||
public void DoSearch_IsGuarded_AgainstReentry()
|
||||
{
|
||||
// White-box: flip the guard, assert a second entry is rejected, then clear.
|
||||
// _searchInProgress is process-global static state; release it in finally so a
|
||||
// failed assert here can't leak the guard into other tests.
|
||||
Assert.False(AdvancedSearchGump.IsSearchInProgress);
|
||||
Assert.True(AdvancedSearchGump.TryBeginSearch()); // acquires
|
||||
Assert.False(AdvancedSearchGump.TryBeginSearch()); // rejected
|
||||
AdvancedSearchGump.EndSearch(); // releases
|
||||
Assert.True(AdvancedSearchGump.TryBeginSearch()); // acquires
|
||||
try
|
||||
{
|
||||
Assert.False(AdvancedSearchGump.TryBeginSearch()); // rejected
|
||||
}
|
||||
finally
|
||||
{
|
||||
AdvancedSearchGump.EndSearch(); // releases
|
||||
}
|
||||
|
||||
Assert.False(AdvancedSearchGump.IsSearchInProgress);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -754,80 +754,87 @@ public class AdvancedSearchGump : Gump
|
|||
_threadId = 0;
|
||||
|
||||
var autoSave = AutoSave.SavesEnabled;
|
||||
if (autoSave)
|
||||
AutoSave.SavesEnabled = false;
|
||||
|
||||
try
|
||||
{
|
||||
AutoSave.SavesEnabled = false;
|
||||
}
|
||||
_threadWorkers ??= new AdvancedSearchThreadWorker[Math.Max(Environment.ProcessorCount - 1, 1)];
|
||||
|
||||
_threadWorkers ??= new AdvancedSearchThreadWorker[Math.Max(Environment.ProcessorCount - 1, 1)];
|
||||
var ignoreQueue = new ConcurrentQueue<IEntity>();
|
||||
var results = new ConcurrentQueue<AdvancedSearchResult>();
|
||||
var worldLocation = new WorldLocation(from.Location, from.Map);
|
||||
|
||||
var ignoreQueue = new ConcurrentQueue<IEntity>();
|
||||
var results = new ConcurrentQueue<AdvancedSearchResult>();
|
||||
var worldLocation = new WorldLocation(from.Location, from.Map);
|
||||
|
||||
for (var i = 0; i < _threadWorkers.Length; i++)
|
||||
{
|
||||
(_threadWorkers[i] ??= new AdvancedSearchThreadWorker()).Wake(worldLocation, Filter, results, ignoreQueue);
|
||||
}
|
||||
|
||||
var type = Filter.FilterType ? Filter.Type : null;
|
||||
|
||||
// Push the entities
|
||||
foreach (var item in World.Items.Values)
|
||||
{
|
||||
if (type == null || type.IsInstanceOfType(item))
|
||||
for (var i = 0; i < _threadWorkers.Length; i++)
|
||||
{
|
||||
PushToWorkers(item);
|
||||
(_threadWorkers[i] ??= new AdvancedSearchThreadWorker()).Wake(worldLocation, Filter, results, ignoreQueue);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var m in World.Mobiles.Values)
|
||||
{
|
||||
if (type == null || type.IsInstanceOfType(m))
|
||||
{
|
||||
PushToWorkers(m);
|
||||
}
|
||||
}
|
||||
var type = Filter.FilterType ? Filter.Type : null;
|
||||
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
{
|
||||
try
|
||||
// Push the entities
|
||||
foreach (var item in World.Items.Values)
|
||||
{
|
||||
// Block until everything is processed
|
||||
for (var i = 0; i < _threadWorkers.Length; i++)
|
||||
if (type == null || type.IsInstanceOfType(item))
|
||||
{
|
||||
_threadWorkers[i].Sleep();
|
||||
PushToWorkers(item);
|
||||
}
|
||||
}
|
||||
|
||||
var ignoredEntities = new HashSet<IEntity>(ignoreQueue);
|
||||
|
||||
// Force the GC to collect the ignored entities
|
||||
ignoreQueue.Clear();
|
||||
|
||||
var resultsList = new List<AdvancedSearchResult>(results.Count);
|
||||
foreach (var result in results)
|
||||
foreach (var m in World.Mobiles.Values)
|
||||
{
|
||||
if (type == null || type.IsInstanceOfType(m))
|
||||
{
|
||||
if (!ignoredEntities.Contains(result.Entity))
|
||||
PushToWorkers(m);
|
||||
}
|
||||
}
|
||||
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// Block until everything is processed
|
||||
for (var i = 0; i < _threadWorkers.Length; i++)
|
||||
{
|
||||
resultsList.Add(result);
|
||||
_threadWorkers[i].Sleep();
|
||||
}
|
||||
|
||||
var ignoredEntities = new HashSet<IEntity>(ignoreQueue);
|
||||
|
||||
// Force the GC to collect the ignored entities
|
||||
ignoreQueue.Clear();
|
||||
|
||||
var resultsList = new List<AdvancedSearchResult>(results.Count);
|
||||
foreach (var result in results)
|
||||
{
|
||||
if (!ignoredEntities.Contains(result.Entity))
|
||||
{
|
||||
resultsList.Add(result);
|
||||
}
|
||||
}
|
||||
|
||||
SearchResults = resultsList.ToArray();
|
||||
|
||||
// Force the GC to collect the results
|
||||
resultsList.Clear();
|
||||
resultsList.TrimExcess();
|
||||
|
||||
// Send the gump on the main thread
|
||||
Core.LoopContext.Post(() => Resend(from));
|
||||
}
|
||||
|
||||
SearchResults = resultsList.ToArray();
|
||||
|
||||
// Force the GC to collect the results
|
||||
resultsList.Clear();
|
||||
resultsList.TrimExcess();
|
||||
|
||||
// Send the gump on the main thread
|
||||
Core.LoopContext.Post(() => Resend(from));
|
||||
}
|
||||
finally
|
||||
{
|
||||
AutoSave.SavesEnabled = (bool)state!;
|
||||
EndSearch();
|
||||
}
|
||||
}, autoSave);
|
||||
finally
|
||||
{
|
||||
AutoSave.SavesEnabled = (bool)state!;
|
||||
EndSearch();
|
||||
}
|
||||
}, autoSave);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Setup failed before the work item took ownership of the release.
|
||||
AutoSave.SavesEnabled = autoSave;
|
||||
EndSearch();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetSortSwitches(int radioSwitch)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue