mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2026-06-13 14:38:43 +00:00
Deadlock test
This commit is contained in:
@@ -63,6 +63,8 @@ partial class EpConnection
|
|||||||
// (e.g. two concurrent fetches A<->B) so a placeholder can break the deadlock, while
|
// (e.g. two concurrent fetches A<->B) so a placeholder can break the deadlock, while
|
||||||
// independent/app-facing fetches of an in-flight resource simply wait for full attachment.
|
// independent/app-facing fetches of an in-flight resource simply wait for full attachment.
|
||||||
readonly Dictionary<uint, HashSet<uint>> _fetchBlockedOn = new Dictionary<uint, HashSet<uint>>();
|
readonly Dictionary<uint, HashSet<uint>> _fetchBlockedOn = new Dictionary<uint, HashSet<uint>>();
|
||||||
|
readonly object _deliveredRootsLock = new object();
|
||||||
|
readonly Dictionary<uint, WeakReference<EpResource>> _deliveredRoots = new Dictionary<uint, WeakReference<EpResource>>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Strategy FetchResource uses for an in-flight resource. Defaults to the new wait + cycle
|
/// Strategy FetchResource uses for an in-flight resource. Defaults to the new wait + cycle
|
||||||
@@ -1990,10 +1992,10 @@ partial class EpConnection
|
|||||||
|
|
||||||
req.Then(result =>
|
req.Then(result =>
|
||||||
{
|
{
|
||||||
// The resource is being handed to the application: publish its fully-attached
|
// The resource is being handed to the application: remember it and publish its graph
|
||||||
// graph so that, if any dependency is only partially attached, it stays unpublished.
|
// once all reachable dependencies have attached.
|
||||||
if (result is EpResource resource)
|
if (result is EpResource resource)
|
||||||
PublishGraph(resource);
|
TrackDeliveredRoot(resource);
|
||||||
|
|
||||||
rt.Trigger(result);
|
rt.Trigger(result);
|
||||||
}).Error(ex => rt.TriggerError(ex));
|
}).Error(ex => rt.TriggerError(ex));
|
||||||
@@ -2134,7 +2136,7 @@ partial class EpConnection
|
|||||||
|
|
||||||
reachable.Add(node);
|
reachable.Add(node);
|
||||||
|
|
||||||
if (node.Status != ResourceStatus.Attached)
|
if (node.Status != ResourceStatus.Attached && node.Status != ResourceStatus.Published)
|
||||||
{
|
{
|
||||||
fullyAttached = false;
|
fullyAttached = false;
|
||||||
continue; // do not traverse into a not-yet-attached node
|
continue; // do not traverse into a not-yet-attached node
|
||||||
@@ -2149,6 +2151,32 @@ partial class EpConnection
|
|||||||
node.Publish();
|
node.Publish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TrackDeliveredRoot(EpResource root)
|
||||||
|
{
|
||||||
|
lock (_deliveredRootsLock)
|
||||||
|
_deliveredRoots[root.ResourceInstanceId] = new WeakReference<EpResource>(root);
|
||||||
|
|
||||||
|
TryPublishDeliveredRoots();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TryPublishDeliveredRoots()
|
||||||
|
{
|
||||||
|
lock (_deliveredRootsLock)
|
||||||
|
{
|
||||||
|
var stale = new List<uint>();
|
||||||
|
foreach (var pair in _deliveredRoots)
|
||||||
|
{
|
||||||
|
if (pair.Value.TryGetTarget(out var root))
|
||||||
|
PublishGraph(root);
|
||||||
|
else
|
||||||
|
stale.Add(pair.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var key in stale)
|
||||||
|
_deliveredRoots.Remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public AsyncReply<EpResource> FetchResource(uint id, uint[] requestSequence)
|
public AsyncReply<EpResource> FetchResource(uint id, uint[] requestSequence)
|
||||||
{
|
{
|
||||||
//lock (fetchLock)
|
//lock (fetchLock)
|
||||||
@@ -2288,6 +2316,7 @@ partial class EpConnection
|
|||||||
_attachedResources[id] = new WeakReference<EpResource>(dr);
|
_attachedResources[id] = new WeakReference<EpResource>(dr);
|
||||||
// attached: no longer part of the in-flight wait-for graph.
|
// attached: no longer part of the in-flight wait-for graph.
|
||||||
ClearFetchNode(id);
|
ClearFetchNode(id);
|
||||||
|
TryPublishDeliveredRoots();
|
||||||
reply.Trigger(dr);
|
reply.Trigger(dr);
|
||||||
}).Error(ex => { _resourceRequests.Remove(id); ClearFetchNode(id); reply.TriggerError(ex); });
|
}).Error(ex => { _resourceRequests.Remove(id); ClearFetchNode(id); reply.TriggerError(ex); });
|
||||||
};
|
};
|
||||||
@@ -2418,6 +2447,7 @@ partial class EpConnection
|
|||||||
_neededResources.Remove(id);
|
_neededResources.Remove(id);
|
||||||
_attachedResources[id] = new WeakReference<EpResource>(resource);
|
_attachedResources[id] = new WeakReference<EpResource>(resource);
|
||||||
ClearFetchNode(id);
|
ClearFetchNode(id);
|
||||||
|
TryPublishDeliveredRoots();
|
||||||
reply.Trigger(resource);
|
reply.Trigger(resource);
|
||||||
})
|
})
|
||||||
.Error(ex => { _resourceRequests.Remove(id); ClearFetchNode(id); reply.TriggerError(ex); });
|
.Error(ex => { _resourceRequests.Remove(id); ClearFetchNode(id); reply.TriggerError(ex); });
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ public class DeadlockIntegrationTests
|
|||||||
if (node == null || !seen.Add(node.ResourceInstanceId))
|
if (node == null || !seen.Add(node.ResourceInstanceId))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (node.Status != Resource.ResourceStatus.Attached)
|
if (node.Status != Resource.ResourceStatus.Attached && node.Status != Resource.ResourceStatus.Published)
|
||||||
{
|
{
|
||||||
allAttached = false;
|
allAttached = false;
|
||||||
continue; // do not traverse into a partially attached node
|
continue; // do not traverse into a partially attached node
|
||||||
@@ -293,7 +293,8 @@ public class DeadlockIntegrationTests
|
|||||||
if (node.Status != ResourceStatus.Published)
|
if (node.Status != ResourceStatus.Published)
|
||||||
unpublished++;
|
unpublished++;
|
||||||
|
|
||||||
if ((node.Status == ResourceStatus.Attached) && node.TryGetPropertyValue((byte)1, out var linksObj) && linksObj is IEnumerable links)
|
if ((node.Status == ResourceStatus.Attached || node.Status == ResourceStatus.Published)
|
||||||
|
&& node.TryGetPropertyValue((byte)1, out var linksObj) && linksObj is IEnumerable links)
|
||||||
foreach (var child in links)
|
foreach (var child in links)
|
||||||
if (child is EpResource childResource)
|
if (child is EpResource childResource)
|
||||||
queue.Enqueue(childResource);
|
queue.Enqueue(childResource);
|
||||||
|
|||||||
Reference in New Issue
Block a user