XML comments added Builds cleanly.
oddly a ignore in the gitignore went missing. restored.
This commit is contained in:
parent
8a6f9144c4
commit
0ae815cf2c
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
|||||||
# Ignore Build
|
# Ignore Build
|
||||||
|
.vscode/
|
||||||
/docfx_project
|
/docfx_project
|
||||||
/src/AdvChkSys/bin
|
/src/AdvChkSys/bin
|
||||||
/src/AdvChkSys/obj
|
/src/AdvChkSys/obj
|
||||||
|
|||||||
@ -14,21 +14,36 @@ namespace AdvChkSys.Dependencies
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public enum DependencyType
|
public enum DependencyType
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates a neighboring chunk relationship.
|
||||||
|
/// </summary>
|
||||||
Neighbor,
|
Neighbor,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates a reference relationship between chunks.
|
||||||
|
/// </summary>
|
||||||
Reference,
|
Reference,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates an update relationship between chunks.
|
||||||
|
/// </summary>
|
||||||
Update,
|
Update,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates a custom dependency relationship.
|
||||||
|
/// </summary>
|
||||||
Custom
|
Custom
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dictionary to track dependencies: source chunk -> (target chunk, dependency type)
|
// Dictionary to track dependencies: source chunk -> (target chunk, dependency type)
|
||||||
private readonly Dictionary<IChunk, HashSet<(IChunk Target, DependencyType Type)>> _dependencies = new();
|
private readonly Dictionary<IChunk, HashSet<(IChunk Target, DependencyType Type)>> _dependencies = new();
|
||||||
|
|
||||||
// Dictionary to track dependents: target chunk -> (source chunk, dependency type)
|
// Dictionary to track dependents: target chunk -> (source chunk, dependency type)
|
||||||
private readonly Dictionary<IChunk, HashSet<(IChunk Source, DependencyType Type)>> _dependents = new();
|
private readonly Dictionary<IChunk, HashSet<(IChunk Source, DependencyType Type)>> _dependents = new();
|
||||||
|
|
||||||
// Lock object for thread safety
|
// Lock object for thread safety
|
||||||
private readonly object _lock = new();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a dependency between two chunks.
|
/// Registers a dependency between two chunks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -36,7 +51,7 @@ namespace AdvChkSys.Dependencies
|
|||||||
{
|
{
|
||||||
if (source == null || target == null)
|
if (source == null || target == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
// Add to dependencies
|
// Add to dependencies
|
||||||
@ -46,7 +61,7 @@ namespace AdvChkSys.Dependencies
|
|||||||
_dependencies[source] = targetSet;
|
_dependencies[source] = targetSet;
|
||||||
}
|
}
|
||||||
targetSet.Add((target, type));
|
targetSet.Add((target, type));
|
||||||
|
|
||||||
// Add to dependents
|
// Add to dependents
|
||||||
if (!_dependents.TryGetValue(target, out var sourceSet))
|
if (!_dependents.TryGetValue(target, out var sourceSet))
|
||||||
{
|
{
|
||||||
@ -56,7 +71,7 @@ namespace AdvChkSys.Dependencies
|
|||||||
sourceSet.Add((source, type));
|
sourceSet.Add((source, type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes a dependency between two chunks.
|
/// Removes a dependency between two chunks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -64,7 +79,7 @@ namespace AdvChkSys.Dependencies
|
|||||||
{
|
{
|
||||||
if (source == null || target == null)
|
if (source == null || target == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
// Remove from dependencies
|
// Remove from dependencies
|
||||||
@ -76,7 +91,7 @@ namespace AdvChkSys.Dependencies
|
|||||||
_dependencies.Remove(source);
|
_dependencies.Remove(source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove from dependents
|
// Remove from dependents
|
||||||
if (_dependents.TryGetValue(target, out var sourceSet))
|
if (_dependents.TryGetValue(target, out var sourceSet))
|
||||||
{
|
{
|
||||||
@ -88,7 +103,7 @@ namespace AdvChkSys.Dependencies
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all chunks that depend on the specified chunk.
|
/// Gets all chunks that depend on the specified chunk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -96,14 +111,14 @@ namespace AdvChkSys.Dependencies
|
|||||||
{
|
{
|
||||||
if (chunk == null)
|
if (chunk == null)
|
||||||
return new List<IChunk>();
|
return new List<IChunk>();
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (!_dependents.TryGetValue(chunk, out var sourceSet))
|
if (!_dependents.TryGetValue(chunk, out var sourceSet))
|
||||||
{
|
{
|
||||||
return new List<IChunk>();
|
return new List<IChunk>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = new List<IChunk>(sourceSet.Count);
|
var result = new List<IChunk>(sourceSet.Count);
|
||||||
foreach (var (source, _) in sourceSet)
|
foreach (var (source, _) in sourceSet)
|
||||||
{
|
{
|
||||||
@ -112,7 +127,7 @@ namespace AdvChkSys.Dependencies
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all chunks that the specified chunk depends on.
|
/// Gets all chunks that the specified chunk depends on.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -120,14 +135,14 @@ namespace AdvChkSys.Dependencies
|
|||||||
{
|
{
|
||||||
if (chunk == null)
|
if (chunk == null)
|
||||||
return new List<IChunk>();
|
return new List<IChunk>();
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (!_dependencies.TryGetValue(chunk, out var targetSet))
|
if (!_dependencies.TryGetValue(chunk, out var targetSet))
|
||||||
{
|
{
|
||||||
return new List<IChunk>();
|
return new List<IChunk>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = new List<IChunk>(targetSet.Count);
|
var result = new List<IChunk>(targetSet.Count);
|
||||||
foreach (var (target, _) in targetSet)
|
foreach (var (target, _) in targetSet)
|
||||||
{
|
{
|
||||||
@ -136,7 +151,7 @@ namespace AdvChkSys.Dependencies
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all chunks that depend on the specified chunk with their dependency types.
|
/// Gets all chunks that depend on the specified chunk with their dependency types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -144,14 +159,14 @@ namespace AdvChkSys.Dependencies
|
|||||||
{
|
{
|
||||||
if (chunk == null)
|
if (chunk == null)
|
||||||
return new List<(IChunk, DependencyType)>();
|
return new List<(IChunk, DependencyType)>();
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (!_dependents.TryGetValue(chunk, out var sourceDependents))
|
if (!_dependents.TryGetValue(chunk, out var sourceDependents))
|
||||||
{
|
{
|
||||||
return new List<(IChunk, DependencyType)>();
|
return new List<(IChunk, DependencyType)>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = new List<(IChunk, DependencyType)>(sourceDependents.Count);
|
var result = new List<(IChunk, DependencyType)>(sourceDependents.Count);
|
||||||
foreach (var (source, type) in sourceDependents)
|
foreach (var (source, type) in sourceDependents)
|
||||||
{
|
{
|
||||||
@ -160,7 +175,7 @@ namespace AdvChkSys.Dependencies
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all chunks that the specified chunk depends on with their dependency types.
|
/// Gets all chunks that the specified chunk depends on with their dependency types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -168,14 +183,14 @@ namespace AdvChkSys.Dependencies
|
|||||||
{
|
{
|
||||||
if (chunk == null)
|
if (chunk == null)
|
||||||
return new List<(IChunk, DependencyType)>();
|
return new List<(IChunk, DependencyType)>();
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (!_dependencies.TryGetValue(chunk, out var targetSet))
|
if (!_dependencies.TryGetValue(chunk, out var targetSet))
|
||||||
{
|
{
|
||||||
return new List<(IChunk, DependencyType)>();
|
return new List<(IChunk, DependencyType)>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = new List<(IChunk, DependencyType)>(targetSet.Count);
|
var result = new List<(IChunk, DependencyType)>(targetSet.Count);
|
||||||
foreach (var (target, type) in targetSet)
|
foreach (var (target, type) in targetSet)
|
||||||
{
|
{
|
||||||
@ -184,7 +199,7 @@ namespace AdvChkSys.Dependencies
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if a dependency exists between source and target chunks.
|
/// Checks if a dependency exists between source and target chunks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -192,14 +207,14 @@ namespace AdvChkSys.Dependencies
|
|||||||
{
|
{
|
||||||
if (source == null || target == null)
|
if (source == null || target == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (!_dependencies.TryGetValue(source, out var targetSet))
|
if (!_dependencies.TryGetValue(source, out var targetSet))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (t, _) in targetSet)
|
foreach (var (t, _) in targetSet)
|
||||||
{
|
{
|
||||||
if (t.Equals(target))
|
if (t.Equals(target))
|
||||||
@ -207,11 +222,11 @@ namespace AdvChkSys.Dependencies
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the dependency type between source and target chunks, or null if no dependency exists.
|
/// Gets the dependency type between source and target chunks, or null if no dependency exists.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -219,14 +234,14 @@ namespace AdvChkSys.Dependencies
|
|||||||
{
|
{
|
||||||
if (source == null || target == null)
|
if (source == null || target == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (!_dependencies.TryGetValue(source, out var targetSet))
|
if (!_dependencies.TryGetValue(source, out var targetSet))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (t, type) in targetSet)
|
foreach (var (t, type) in targetSet)
|
||||||
{
|
{
|
||||||
if (t.Equals(target))
|
if (t.Equals(target))
|
||||||
@ -234,11 +249,11 @@ namespace AdvChkSys.Dependencies
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears all dependencies for a specific chunk.
|
/// Clears all dependencies for a specific chunk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -246,7 +261,7 @@ namespace AdvChkSys.Dependencies
|
|||||||
{
|
{
|
||||||
if (chunk == null)
|
if (chunk == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
// Remove all dependencies where this chunk is the source
|
// Remove all dependencies where this chunk is the source
|
||||||
@ -265,7 +280,7 @@ namespace AdvChkSys.Dependencies
|
|||||||
}
|
}
|
||||||
_dependencies.Remove(chunk);
|
_dependencies.Remove(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all dependencies where this chunk is the target
|
// Remove all dependencies where this chunk is the target
|
||||||
if (_dependents.TryGetValue(chunk, out var sourceSets))
|
if (_dependents.TryGetValue(chunk, out var sourceSets))
|
||||||
{
|
{
|
||||||
@ -284,7 +299,7 @@ namespace AdvChkSys.Dependencies
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all chunks that have any dependencies.
|
/// Gets all chunks that have any dependencies.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -295,7 +310,7 @@ namespace AdvChkSys.Dependencies
|
|||||||
return new HashSet<IChunk>(_dependencies.Keys);
|
return new HashSet<IChunk>(_dependencies.Keys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all chunks that have any dependents.
|
/// Gets all chunks that have any dependents.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -18,13 +18,32 @@ namespace AdvChkSys.Loading
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public enum Priority
|
public enum Priority
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Immediate priority - process as soon as possible
|
||||||
|
/// </summary>
|
||||||
Immediate,
|
Immediate,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// High priority - process after immediate requests
|
||||||
|
/// </summary>
|
||||||
High,
|
High,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Normal priority - standard processing order
|
||||||
|
/// </summary>
|
||||||
Normal,
|
Normal,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Low priority - process after normal requests
|
||||||
|
/// </summary>
|
||||||
Low,
|
Low,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Background priority - process when system is idle
|
||||||
|
/// </summary>
|
||||||
Background
|
Background
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a chunk loading request with priority.
|
/// Represents a chunk loading request with priority.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -34,47 +53,47 @@ namespace AdvChkSys.Loading
|
|||||||
/// The X coordinate of the chunk.
|
/// The X coordinate of the chunk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int X { get; }
|
public int X { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Y coordinate of the chunk.
|
/// The Y coordinate of the chunk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Y { get; }
|
public int Y { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Z coordinate of the chunk (optional, for 3D chunks).
|
/// The Z coordinate of the chunk (optional, for 3D chunks).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Z { get; }
|
public int Z { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The priority of this loading request.
|
/// The priority of this loading request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Priority LoadPriority { get; }
|
public Priority LoadPriority { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The width of the chunk.
|
/// The width of the chunk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Width { get; }
|
public int Width { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The height of the chunk.
|
/// The height of the chunk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Height { get; }
|
public int Height { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The depth of the chunk (for 3D chunks).
|
/// The depth of the chunk (for 3D chunks).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Depth { get; }
|
public int Depth { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Timestamp when the request was created.
|
/// Timestamp when the request was created.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTime Timestamp { get; }
|
public DateTime Timestamp { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unique identifier for this request.
|
/// Unique identifier for this request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid RequestId { get; }
|
public Guid RequestId { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new 2D chunk loading request.
|
/// Creates a new 2D chunk loading request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -90,7 +109,7 @@ namespace AdvChkSys.Loading
|
|||||||
Timestamp = DateTime.UtcNow;
|
Timestamp = DateTime.UtcNow;
|
||||||
RequestId = Guid.NewGuid();
|
RequestId = Guid.NewGuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new 3D chunk loading request.
|
/// Creates a new 3D chunk loading request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -107,39 +126,39 @@ namespace AdvChkSys.Loading
|
|||||||
RequestId = Guid.NewGuid();
|
RequestId = Guid.NewGuid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Priority queues for each priority level
|
// Priority queues for each priority level
|
||||||
private readonly Dictionary<Priority, Queue<ChunkLoadRequest>> _requestQueues = new();
|
private readonly Dictionary<Priority, Queue<ChunkLoadRequest>> _requestQueues = new();
|
||||||
|
|
||||||
// Lookup for fast cancellation and status checks
|
// Lookup for fast cancellation and status checks
|
||||||
private readonly Dictionary<Guid, ChunkLoadRequest> _requestLookup = new();
|
private readonly Dictionary<Guid, ChunkLoadRequest> _requestLookup = new();
|
||||||
|
|
||||||
// Active tasks to prevent duplicate loading
|
// Active tasks to prevent duplicate loading
|
||||||
private readonly Dictionary<(int X, int Y, int Z), Task> _activeTasks = new();
|
private readonly Dictionary<(int X, int Y, int Z), Task> _activeTasks = new();
|
||||||
|
|
||||||
// Synchronization
|
// Synchronization
|
||||||
private readonly SemaphoreSlim _queueSemaphore = new(1, 1);
|
private readonly SemaphoreSlim _queueSemaphore = new(1, 1);
|
||||||
private readonly SemaphoreSlim _processSemaphore;
|
private readonly SemaphoreSlim _processSemaphore;
|
||||||
private readonly CancellationTokenSource _cancellationSource = new();
|
private readonly CancellationTokenSource _cancellationSource = new();
|
||||||
|
|
||||||
// Processing state
|
// Processing state
|
||||||
private bool _isProcessing;
|
private bool _isProcessing;
|
||||||
private Task? _processingTask;
|
private Task? _processingTask;
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
private readonly int _maxConcurrentLoads;
|
private readonly int _maxConcurrentLoads;
|
||||||
private readonly TimeSpan _requestTimeout;
|
private readonly TimeSpan _requestTimeout;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event raised when a chunk load request is completed.
|
/// Event raised when a chunk load request is completed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<ChunkLoadRequest>? RequestCompleted;
|
public event EventHandler<ChunkLoadRequest>? RequestCompleted;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event raised when a chunk load request fails.
|
/// Event raised when a chunk load request fails.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<(ChunkLoadRequest Request, Exception Exception)>? RequestFailed;
|
public event EventHandler<(ChunkLoadRequest Request, Exception Exception)>? RequestFailed;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the ChunkLoadingPriority class.
|
/// Initializes a new instance of the ChunkLoadingPriority class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -150,14 +169,14 @@ namespace AdvChkSys.Loading
|
|||||||
_maxConcurrentLoads = maxConcurrentLoads;
|
_maxConcurrentLoads = maxConcurrentLoads;
|
||||||
_requestTimeout = TimeSpan.FromSeconds(requestTimeoutSeconds);
|
_requestTimeout = TimeSpan.FromSeconds(requestTimeoutSeconds);
|
||||||
_processSemaphore = new SemaphoreSlim(maxConcurrentLoads, maxConcurrentLoads);
|
_processSemaphore = new SemaphoreSlim(maxConcurrentLoads, maxConcurrentLoads);
|
||||||
|
|
||||||
// Initialize queues for each priority level
|
// Initialize queues for each priority level
|
||||||
foreach (Priority priority in Enum.GetValues(typeof(Priority)))
|
foreach (Priority priority in Enum.GetValues(typeof(Priority)))
|
||||||
{
|
{
|
||||||
_requestQueues[priority] = new Queue<ChunkLoadRequest>();
|
_requestQueues[priority] = new Queue<ChunkLoadRequest>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enqueues a chunk load request with the specified priority.
|
/// Enqueues a chunk load request with the specified priority.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -168,7 +187,7 @@ namespace AdvChkSys.Loading
|
|||||||
EnqueueRequest(request);
|
EnqueueRequest(request);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enqueues a 3D chunk load request with the specified priority.
|
/// Enqueues a 3D chunk load request with the specified priority.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -179,7 +198,7 @@ namespace AdvChkSys.Loading
|
|||||||
EnqueueRequest(request);
|
EnqueueRequest(request);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enqueues a pre-created chunk load request.
|
/// Enqueues a pre-created chunk load request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -194,11 +213,11 @@ namespace AdvChkSys.Loading
|
|||||||
{
|
{
|
||||||
return; // Already loading this chunk
|
return; // Already loading this chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to appropriate queue
|
// Add to appropriate queue
|
||||||
_requestQueues[request.LoadPriority].Enqueue(request);
|
_requestQueues[request.LoadPriority].Enqueue(request);
|
||||||
_requestLookup[request.RequestId] = request;
|
_requestLookup[request.RequestId] = request;
|
||||||
|
|
||||||
// Start processing if not already running
|
// Start processing if not already running
|
||||||
EnsureProcessingStarted();
|
EnsureProcessingStarted();
|
||||||
}
|
}
|
||||||
@ -206,14 +225,14 @@ namespace AdvChkSys.Loading
|
|||||||
{
|
{
|
||||||
_queueSemaphore.Release();
|
_queueSemaphore.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
// For immediate priority, wait for processing to start
|
// For immediate priority, wait for processing to start
|
||||||
if (request.LoadPriority == Priority.Immediate)
|
if (request.LoadPriority == Priority.Immediate)
|
||||||
{
|
{
|
||||||
TriggerImmediateProcessing();
|
TriggerImmediateProcessing();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cancels a pending chunk load request.
|
/// Cancels a pending chunk load request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -237,7 +256,7 @@ namespace AdvChkSys.Loading
|
|||||||
_queueSemaphore.Release();
|
_queueSemaphore.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cancels all pending chunk load requests.
|
/// Cancels all pending chunk load requests.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -257,7 +276,7 @@ namespace AdvChkSys.Loading
|
|||||||
_queueSemaphore.Release();
|
_queueSemaphore.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Starts the processing of chunk load requests if not already running.
|
/// Starts the processing of chunk load requests if not already running.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -265,11 +284,11 @@ namespace AdvChkSys.Loading
|
|||||||
{
|
{
|
||||||
if (_isProcessing)
|
if (_isProcessing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_isProcessing = true;
|
_isProcessing = true;
|
||||||
_processingTask = Task.Run(ProcessRequestsAsync);
|
_processingTask = Task.Run(ProcessRequestsAsync);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Triggers immediate processing of high-priority requests.
|
/// Triggers immediate processing of high-priority requests.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -278,7 +297,7 @@ namespace AdvChkSys.Loading
|
|||||||
// This is a hint to the processor to check for immediate requests now
|
// This is a hint to the processor to check for immediate requests now
|
||||||
// We don't need to do anything special as the processor checks immediate first
|
// We don't need to do anything special as the processor checks immediate first
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Main processing loop for chunk load requests.
|
/// Main processing loop for chunk load requests.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -287,13 +306,13 @@ namespace AdvChkSys.Loading
|
|||||||
while (!_cancellationSource.IsCancellationRequested)
|
while (!_cancellationSource.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
ChunkLoadRequest? request = null;
|
ChunkLoadRequest? request = null;
|
||||||
|
|
||||||
// Get the next request from the highest priority queue
|
// Get the next request from the highest priority queue
|
||||||
await _queueSemaphore.WaitAsync();
|
await _queueSemaphore.WaitAsync();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
request = DequeueNextRequest();
|
request = DequeueNextRequest();
|
||||||
|
|
||||||
if (request == null)
|
if (request == null)
|
||||||
{
|
{
|
||||||
// No requests to process, pause briefly
|
// No requests to process, pause briefly
|
||||||
@ -302,7 +321,7 @@ namespace AdvChkSys.Loading
|
|||||||
await Task.Delay(50);
|
await Task.Delay(50);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark this chunk as being processed
|
// Mark this chunk as being processed
|
||||||
var key = (request.X, request.Y, request.Z);
|
var key = (request.X, request.Y, request.Z);
|
||||||
if (_activeTasks.ContainsKey(key))
|
if (_activeTasks.ContainsKey(key))
|
||||||
@ -310,7 +329,7 @@ namespace AdvChkSys.Loading
|
|||||||
// Already processing this chunk, skip
|
// Already processing this chunk, skip
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a task for this request but don't start it yet
|
// Create a task for this request but don't start it yet
|
||||||
var loadTask = ProcessRequestAsync(request);
|
var loadTask = ProcessRequestAsync(request);
|
||||||
_activeTasks[key] = loadTask;
|
_activeTasks[key] = loadTask;
|
||||||
@ -322,10 +341,10 @@ namespace AdvChkSys.Loading
|
|||||||
_queueSemaphore.Release();
|
_queueSemaphore.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for a processing slot
|
// Wait for a processing slot
|
||||||
await _processSemaphore.WaitAsync();
|
await _processSemaphore.WaitAsync();
|
||||||
|
|
||||||
// Start the task and continue without waiting
|
// Start the task and continue without waiting
|
||||||
_ = Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@ -336,7 +355,7 @@ namespace AdvChkSys.Loading
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_processSemaphore.Release();
|
_processSemaphore.Release();
|
||||||
|
|
||||||
// Remove from active tasks
|
// Remove from active tasks
|
||||||
await _queueSemaphore.WaitAsync();
|
await _queueSemaphore.WaitAsync();
|
||||||
try
|
try
|
||||||
@ -351,7 +370,7 @@ namespace AdvChkSys.Loading
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dequeues the next request from the highest priority queue.
|
/// Dequeues the next request from the highest priority queue.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -361,30 +380,30 @@ namespace AdvChkSys.Loading
|
|||||||
foreach (Priority priority in Enum.GetValues(typeof(Priority)))
|
foreach (Priority priority in Enum.GetValues(typeof(Priority)))
|
||||||
{
|
{
|
||||||
var queue = _requestQueues[priority];
|
var queue = _requestQueues[priority];
|
||||||
|
|
||||||
while (queue.Count > 0)
|
while (queue.Count > 0)
|
||||||
{
|
{
|
||||||
var request = queue.Dequeue();
|
var request = queue.Dequeue();
|
||||||
|
|
||||||
// Skip if the request has been canceled
|
// Skip if the request has been canceled
|
||||||
if (!_requestLookup.ContainsKey(request.RequestId))
|
if (!_requestLookup.ContainsKey(request.RequestId))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Skip if the request has timed out
|
// Skip if the request has timed out
|
||||||
if (DateTime.UtcNow - request.Timestamp > _requestTimeout)
|
if (DateTime.UtcNow - request.Timestamp > _requestTimeout)
|
||||||
{
|
{
|
||||||
_requestLookup.Remove(request.RequestId);
|
_requestLookup.Remove(request.RequestId);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid request found
|
// Valid request found
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null; // No valid requests found
|
return null; // No valid requests found
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Processes a single chunk load request.
|
/// Processes a single chunk load request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -394,7 +413,7 @@ namespace AdvChkSys.Loading
|
|||||||
{
|
{
|
||||||
// This would be integrated with your chunk manager
|
// This would be integrated with your chunk manager
|
||||||
// For now, we'll just simulate the loading with a delay
|
// For now, we'll just simulate the loading with a delay
|
||||||
|
|
||||||
// Simulate different loading times based on priority
|
// Simulate different loading times based on priority
|
||||||
int delayMs = request.LoadPriority switch
|
int delayMs = request.LoadPriority switch
|
||||||
{
|
{
|
||||||
@ -405,9 +424,9 @@ namespace AdvChkSys.Loading
|
|||||||
Priority.Background => 1000,
|
Priority.Background => 1000,
|
||||||
_ => 200
|
_ => 200
|
||||||
};
|
};
|
||||||
|
|
||||||
await Task.Delay(delayMs);
|
await Task.Delay(delayMs);
|
||||||
|
|
||||||
// Notify completion
|
// Notify completion
|
||||||
RequestCompleted?.Invoke(this, request);
|
RequestCompleted?.Invoke(this, request);
|
||||||
}
|
}
|
||||||
@ -430,7 +449,7 @@ namespace AdvChkSys.Loading
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of pending requests for each priority level.
|
/// Gets the number of pending requests for each priority level.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -451,7 +470,7 @@ namespace AdvChkSys.Loading
|
|||||||
_queueSemaphore.Release();
|
_queueSemaphore.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the total number of pending requests.
|
/// Gets the total number of pending requests.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -472,14 +491,14 @@ namespace AdvChkSys.Loading
|
|||||||
_queueSemaphore.Release();
|
_queueSemaphore.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stops processing and releases resources.
|
/// Stops processing and releases resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task ShutdownAsync()
|
public async Task ShutdownAsync()
|
||||||
{
|
{
|
||||||
_cancellationSource.Cancel();
|
_cancellationSource.Cancel();
|
||||||
|
|
||||||
if (_processingTask != null)
|
if (_processingTask != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -495,12 +514,12 @@ namespace AdvChkSys.Loading
|
|||||||
// Ignore other exceptions during shutdown
|
// Ignore other exceptions during shutdown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_queueSemaphore.Dispose();
|
_queueSemaphore.Dispose();
|
||||||
_processSemaphore.Dispose();
|
_processSemaphore.Dispose();
|
||||||
_cancellationSource.Dispose();
|
_cancellationSource.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a ChunkLoadingPriority instance with default settings.
|
/// Creates a ChunkLoadingPriority instance with default settings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -508,7 +527,7 @@ namespace AdvChkSys.Loading
|
|||||||
{
|
{
|
||||||
return new ChunkLoadingPriority();
|
return new ChunkLoadingPriority();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a ChunkLoadingPriority instance optimized for high throughput.
|
/// Creates a ChunkLoadingPriority instance optimized for high throughput.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -518,7 +537,7 @@ namespace AdvChkSys.Loading
|
|||||||
maxConcurrentLoads: Environment.ProcessorCount * 2,
|
maxConcurrentLoads: Environment.ProcessorCount * 2,
|
||||||
requestTimeoutSeconds: 60);
|
requestTimeoutSeconds: 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a ChunkLoadingPriority instance optimized for low latency.
|
/// Creates a ChunkLoadingPriority instance optimized for low latency.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -528,7 +547,7 @@ namespace AdvChkSys.Loading
|
|||||||
maxConcurrentLoads: Math.Max(2, Environment.ProcessorCount / 2),
|
maxConcurrentLoads: Math.Max(2, Environment.ProcessorCount / 2),
|
||||||
requestTimeoutSeconds: 15);
|
requestTimeoutSeconds: 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Integrates with a chunk manager to process load requests.
|
/// Integrates with a chunk manager to process load requests.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -539,7 +558,7 @@ namespace AdvChkSys.Loading
|
|||||||
// Replace the ProcessRequestAsync method with one that uses the chunk manager
|
// Replace the ProcessRequestAsync method with one that uses the chunk manager
|
||||||
// This is a simplified example - in a real implementation, you'd need to handle
|
// This is a simplified example - in a real implementation, you'd need to handle
|
||||||
// both 2D and 3D chunk managers and properly cast the interface
|
// both 2D and 3D chunk managers and properly cast the interface
|
||||||
|
|
||||||
RequestCompleted += (sender, request) =>
|
RequestCompleted += (sender, request) =>
|
||||||
{
|
{
|
||||||
// The chunk has been loaded, you might want to do something with it
|
// The chunk has been loaded, you might want to do something with it
|
||||||
@ -547,7 +566,7 @@ namespace AdvChkSys.Loading
|
|||||||
// Additional processing if needed
|
// Additional processing if needed
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the estimated time until a request with the given priority would be processed.
|
/// Gets the estimated time until a request with the given priority would be processed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -558,7 +577,7 @@ namespace AdvChkSys.Loading
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
int totalHigherPriorityRequests = 0;
|
int totalHigherPriorityRequests = 0;
|
||||||
|
|
||||||
// Count requests with higher or equal priority
|
// Count requests with higher or equal priority
|
||||||
foreach (Priority p in Enum.GetValues(typeof(Priority)))
|
foreach (Priority p in Enum.GetValues(typeof(Priority)))
|
||||||
{
|
{
|
||||||
@ -567,13 +586,13 @@ namespace AdvChkSys.Loading
|
|||||||
totalHigherPriorityRequests += _requestQueues[p].Count;
|
totalHigherPriorityRequests += _requestQueues[p].Count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no requests or no active tasks, return 0
|
// If no requests or no active tasks, return 0
|
||||||
if (totalHigherPriorityRequests == 0 || _activeTasks.Count == 0)
|
if (totalHigherPriorityRequests == 0 || _activeTasks.Count == 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Estimate based on current processing rate
|
// Estimate based on current processing rate
|
||||||
// This is a very simple estimate and could be improved with actual metrics
|
// This is a very simple estimate and could be improved with actual metrics
|
||||||
int averageProcessingTimeMs = priority switch
|
int averageProcessingTimeMs = priority switch
|
||||||
@ -585,10 +604,10 @@ namespace AdvChkSys.Loading
|
|||||||
Priority.Background => 1000,
|
Priority.Background => 1000,
|
||||||
_ => 200
|
_ => 200
|
||||||
};
|
};
|
||||||
|
|
||||||
// Calculate how many batches of concurrent requests we'll need
|
// Calculate how many batches of concurrent requests we'll need
|
||||||
int batches = (int)Math.Ceiling(totalHigherPriorityRequests / (double)_maxConcurrentLoads);
|
int batches = (int)Math.Ceiling(totalHigherPriorityRequests / (double)_maxConcurrentLoads);
|
||||||
|
|
||||||
return batches * averageProcessingTimeMs;
|
return batches * averageProcessingTimeMs;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@ -596,7 +615,7 @@ namespace AdvChkSys.Loading
|
|||||||
_queueSemaphore.Release();
|
_queueSemaphore.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adjusts the priority of an existing request.
|
/// Adjusts the priority of an existing request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -605,7 +624,7 @@ namespace AdvChkSys.Loading
|
|||||||
{
|
{
|
||||||
// Note: This is not an efficient operation as we don't directly modify the queue
|
// Note: This is not an efficient operation as we don't directly modify the queue
|
||||||
// Instead, we mark the request for priority change when it's processed
|
// Instead, we mark the request for priority change when it's processed
|
||||||
|
|
||||||
_queueSemaphore.Wait();
|
_queueSemaphore.Wait();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -616,26 +635,26 @@ namespace AdvChkSys.Loading
|
|||||||
{
|
{
|
||||||
// Remove from lookup (it will be skipped when dequeued)
|
// Remove from lookup (it will be skipped when dequeued)
|
||||||
_requestLookup.Remove(requestId);
|
_requestLookup.Remove(requestId);
|
||||||
|
|
||||||
// Create a new request with the same parameters but higher priority
|
// Create a new request with the same parameters but higher priority
|
||||||
var newRequest = request.Depth > 1
|
var newRequest = request.Depth > 1
|
||||||
? new ChunkLoadRequest(request.X, request.Y, request.Z, request.Width, request.Height, request.Depth, newPriority)
|
? new ChunkLoadRequest(request.X, request.Y, request.Z, request.Width, request.Height, request.Depth, newPriority)
|
||||||
: new ChunkLoadRequest(request.X, request.Y, request.Width, request.Height, newPriority);
|
: new ChunkLoadRequest(request.X, request.Y, request.Width, request.Height, newPriority);
|
||||||
|
|
||||||
// Add the new request
|
// Add the new request
|
||||||
_requestQueues[newPriority].Enqueue(newRequest);
|
_requestQueues[newPriority].Enqueue(newRequest);
|
||||||
_requestLookup[newRequest.RequestId] = newRequest;
|
_requestLookup[newRequest.RequestId] = newRequest;
|
||||||
|
|
||||||
// If upgrading to immediate, trigger processing
|
// If upgrading to immediate, trigger processing
|
||||||
if (newPriority == Priority.Immediate)
|
if (newPriority == Priority.Immediate)
|
||||||
{
|
{
|
||||||
TriggerImmediateProcessing();
|
TriggerImmediateProcessing();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@ -643,7 +662,7 @@ namespace AdvChkSys.Loading
|
|||||||
_queueSemaphore.Release();
|
_queueSemaphore.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets statistics about the current state of the chunk loading system.
|
/// Gets statistics about the current state of the chunk loading system.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -659,13 +678,13 @@ namespace AdvChkSys.Loading
|
|||||||
["IsProcessing"] = _isProcessing,
|
["IsProcessing"] = _isProcessing,
|
||||||
["MaxConcurrentLoads"] = _maxConcurrentLoads
|
["MaxConcurrentLoads"] = _maxConcurrentLoads
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add queue sizes for each priority
|
// Add queue sizes for each priority
|
||||||
foreach (Priority priority in Enum.GetValues(typeof(Priority)))
|
foreach (Priority priority in Enum.GetValues(typeof(Priority)))
|
||||||
{
|
{
|
||||||
stats[$"Queue_{priority}"] = _requestQueues[priority].Count;
|
stats[$"Queue_{priority}"] = _requestQueues[priority].Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@ -674,4 +693,4 @@ namespace AdvChkSys.Loading
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -14,17 +13,17 @@ namespace AdvChkSys.Threading
|
|||||||
{
|
{
|
||||||
private static ChunkThreadingManager? _instance;
|
private static ChunkThreadingManager? _instance;
|
||||||
private static readonly object _instanceLock = new();
|
private static readonly object _instanceLock = new();
|
||||||
|
|
||||||
// Thread safety utilities
|
// Thread safety utilities
|
||||||
private readonly ChunkThreadSafetyManager _threadSafety;
|
private readonly ChunkThreadSafetyManager _threadSafety;
|
||||||
private readonly ChunkAsyncLock _asyncLock;
|
private readonly ChunkAsyncLock _asyncLock;
|
||||||
|
|
||||||
// Operation queue
|
// Operation queue
|
||||||
private readonly ChunkOperationQueue _operationQueue;
|
private readonly ChunkOperationQueue _operationQueue;
|
||||||
|
|
||||||
// Cancellation for shutdown
|
// Cancellation for shutdown
|
||||||
private readonly CancellationTokenSource _shutdownCts = new();
|
private readonly CancellationTokenSource _shutdownCts = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the singleton instance of the ChunkThreadingManager.
|
/// Gets the singleton instance of the ChunkThreadingManager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -42,7 +41,7 @@ namespace AdvChkSys.Threading
|
|||||||
return _instance;
|
return _instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the ChunkThreadingManager class.
|
/// Initializes a new instance of the ChunkThreadingManager class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -50,29 +49,29 @@ namespace AdvChkSys.Threading
|
|||||||
{
|
{
|
||||||
_threadSafety = new ChunkThreadSafetyManager(
|
_threadSafety = new ChunkThreadSafetyManager(
|
||||||
ChunkThreadingConfiguration.LockCleanupIntervalMinutes);
|
ChunkThreadingConfiguration.LockCleanupIntervalMinutes);
|
||||||
|
|
||||||
_asyncLock = new ChunkAsyncLock(
|
_asyncLock = new ChunkAsyncLock(
|
||||||
ChunkThreadingConfiguration.LockCleanupIntervalMinutes);
|
ChunkThreadingConfiguration.LockCleanupIntervalMinutes);
|
||||||
|
|
||||||
_operationQueue = new ChunkOperationQueue(
|
_operationQueue = new ChunkOperationQueue(
|
||||||
ChunkThreadingConfiguration.DefaultMaxDegreeOfParallelism);
|
ChunkThreadingConfiguration.DefaultMaxDegreeOfParallelism);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the thread safety manager for synchronous locking.
|
/// Gets the thread safety manager for synchronous locking.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ChunkThreadSafetyManager ThreadSafety => _threadSafety;
|
public ChunkThreadSafetyManager ThreadSafety => _threadSafety;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the async lock manager for asynchronous locking.
|
/// Gets the async lock manager for asynchronous locking.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ChunkAsyncLock AsyncLock => _asyncLock;
|
public ChunkAsyncLock AsyncLock => _asyncLock;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the operation queue for sequential chunk operations.
|
/// Gets the operation queue for sequential chunk operations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ChunkOperationQueue OperationQueue => _operationQueue;
|
public ChunkOperationQueue OperationQueue => _operationQueue;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Acquires an exclusive lock on a chunk.
|
/// Acquires an exclusive lock on a chunk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -82,7 +81,7 @@ namespace AdvChkSys.Threading
|
|||||||
{
|
{
|
||||||
return _threadSafety.AcquireLock(chunk);
|
return _threadSafety.AcquireLock(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Acquires a read lock on a chunk.
|
/// Acquires a read lock on a chunk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -92,7 +91,7 @@ namespace AdvChkSys.Threading
|
|||||||
{
|
{
|
||||||
return _threadSafety.AcquireReadLock(chunk);
|
return _threadSafety.AcquireReadLock(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Acquires a write lock on a chunk.
|
/// Acquires a write lock on a chunk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -102,7 +101,7 @@ namespace AdvChkSys.Threading
|
|||||||
{
|
{
|
||||||
return _threadSafety.AcquireWriteLock(chunk);
|
return _threadSafety.AcquireWriteLock(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Acquires a lock on a chunk asynchronously.
|
/// Acquires a lock on a chunk asynchronously.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -113,7 +112,7 @@ namespace AdvChkSys.Threading
|
|||||||
{
|
{
|
||||||
return _asyncLock.LockAsync(chunk, cancellationToken);
|
return _asyncLock.LockAsync(chunk, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enqueues an operation to be performed on a chunk.
|
/// Enqueues an operation to be performed on a chunk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -124,7 +123,7 @@ namespace AdvChkSys.Threading
|
|||||||
{
|
{
|
||||||
return _operationQueue.EnqueueOperationAsync(chunk, operation);
|
return _operationQueue.EnqueueOperationAsync(chunk, operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs an action with a lock on the chunk.
|
/// Runs an action with a lock on the chunk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -135,7 +134,7 @@ namespace AdvChkSys.Threading
|
|||||||
using var lockObj = AcquireLock(chunk);
|
using var lockObj = AcquireLock(chunk);
|
||||||
action();
|
action();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs a function with a lock on the chunk and returns the result.
|
/// Runs a function with a lock on the chunk and returns the result.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -148,7 +147,7 @@ namespace AdvChkSys.Threading
|
|||||||
using var lockObj = AcquireLock(chunk);
|
using var lockObj = AcquireLock(chunk);
|
||||||
return func();
|
return func();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs an async action with a lock on the chunk.
|
/// Runs an async action with a lock on the chunk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -160,7 +159,7 @@ namespace AdvChkSys.Threading
|
|||||||
using var lockObj = await LockAsync(chunk, cancellationToken).ConfigureAwait(false);
|
using var lockObj = await LockAsync(chunk, cancellationToken).ConfigureAwait(false);
|
||||||
await action().ConfigureAwait(false);
|
await action().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs an async function with a lock on the chunk and returns the result.
|
/// Runs an async function with a lock on the chunk and returns the result.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -174,7 +173,7 @@ namespace AdvChkSys.Threading
|
|||||||
using var lockObj = await LockAsync(chunk, cancellationToken).ConfigureAwait(false);
|
using var lockObj = await LockAsync(chunk, cancellationToken).ConfigureAwait(false);
|
||||||
return await func().ConfigureAwait(false);
|
return await func().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs an action on multiple chunks with proper locking to avoid deadlocks.
|
/// Runs an action on multiple chunks with proper locking to avoid deadlocks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -184,7 +183,7 @@ namespace AdvChkSys.Threading
|
|||||||
{
|
{
|
||||||
// Sort chunks by ID to prevent deadlocks
|
// Sort chunks by ID to prevent deadlocks
|
||||||
var sortedChunks = SortChunksById(chunks);
|
var sortedChunks = SortChunksById(chunks);
|
||||||
|
|
||||||
// Acquire locks in order
|
// Acquire locks in order
|
||||||
var locks = new IDisposable[sortedChunks.Length];
|
var locks = new IDisposable[sortedChunks.Length];
|
||||||
try
|
try
|
||||||
@ -193,7 +192,7 @@ namespace AdvChkSys.Threading
|
|||||||
{
|
{
|
||||||
locks[i] = AcquireLock(sortedChunks[i]);
|
locks[i] = AcquireLock(sortedChunks[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the action
|
// Execute the action
|
||||||
action();
|
action();
|
||||||
}
|
}
|
||||||
@ -206,7 +205,7 @@ namespace AdvChkSys.Threading
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs an async action on multiple chunks with proper locking to avoid deadlocks.
|
/// Runs an async action on multiple chunks with proper locking to avoid deadlocks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -217,7 +216,7 @@ namespace AdvChkSys.Threading
|
|||||||
{
|
{
|
||||||
// Sort chunks by ID to prevent deadlocks
|
// Sort chunks by ID to prevent deadlocks
|
||||||
var sortedChunks = SortChunksById(chunks);
|
var sortedChunks = SortChunksById(chunks);
|
||||||
|
|
||||||
// Acquire locks in order
|
// Acquire locks in order
|
||||||
var locks = new IDisposable[sortedChunks.Length];
|
var locks = new IDisposable[sortedChunks.Length];
|
||||||
try
|
try
|
||||||
@ -226,7 +225,7 @@ namespace AdvChkSys.Threading
|
|||||||
{
|
{
|
||||||
locks[i] = await LockAsync(sortedChunks[i], cancellationToken).ConfigureAwait(false);
|
locks[i] = await LockAsync(sortedChunks[i], cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the action
|
// Execute the action
|
||||||
await action().ConfigureAwait(false);
|
await action().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -239,7 +238,7 @@ namespace AdvChkSys.Threading
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sorts chunks by ID to prevent deadlocks when acquiring multiple locks.
|
/// Sorts chunks by ID to prevent deadlocks when acquiring multiple locks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -248,24 +247,24 @@ namespace AdvChkSys.Threading
|
|||||||
// Use System.Linq for OrderBy
|
// Use System.Linq for OrderBy
|
||||||
return chunks.OrderBy(c => c.GetHashCode()).ToArray();
|
return chunks.OrderBy(c => c.GetHashCode()).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disposes all resources.
|
/// Disposes all resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_shutdownCts.Cancel();
|
_shutdownCts.Cancel();
|
||||||
|
|
||||||
// Shutdown operation queue
|
// Shutdown operation queue
|
||||||
_operationQueue.ShutdownAsync().GetAwaiter().GetResult();
|
_operationQueue.ShutdownAsync().GetAwaiter().GetResult();
|
||||||
|
|
||||||
// Dispose thread safety managers
|
// Dispose thread safety managers
|
||||||
(_threadSafety as IDisposable)?.Dispose();
|
(_threadSafety as IDisposable)?.Dispose();
|
||||||
(_asyncLock as IDisposable)?.Dispose();
|
(_asyncLock as IDisposable)?.Dispose();
|
||||||
|
|
||||||
_shutdownCts.Dispose();
|
_shutdownCts.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resets the singleton instance (for testing).
|
/// Resets the singleton instance (for testing).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace AdvChkSys.Threading
|
namespace AdvChkSys.Threading
|
||||||
{
|
{
|
||||||
@ -15,19 +15,19 @@ namespace AdvChkSys.Threading
|
|||||||
{
|
{
|
||||||
// Performance metrics
|
// Performance metrics
|
||||||
private readonly ConcurrentDictionary<string, PerformanceMetric> _metrics = new();
|
private readonly ConcurrentDictionary<string, PerformanceMetric> _metrics = new();
|
||||||
|
|
||||||
// Sampling timer
|
// Sampling timer
|
||||||
private readonly Timer _samplingTimer;
|
private readonly Timer _samplingTimer;
|
||||||
|
|
||||||
// Sampling interval
|
// Sampling interval
|
||||||
private readonly TimeSpan _samplingInterval;
|
private readonly TimeSpan _samplingInterval;
|
||||||
|
|
||||||
// Maximum history to keep
|
// Maximum history to keep
|
||||||
private readonly int _maxHistory;
|
private readonly int _maxHistory;
|
||||||
|
|
||||||
// Whether monitoring is enabled
|
// Whether monitoring is enabled
|
||||||
private bool _isEnabled;
|
private bool _isEnabled;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the ChunkThreadingPerformanceMonitor class.
|
/// Initializes a new instance of the ChunkThreadingPerformanceMonitor class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -39,7 +39,7 @@ namespace AdvChkSys.Threading
|
|||||||
_maxHistory = maxHistory;
|
_maxHistory = maxHistory;
|
||||||
_samplingTimer = new Timer(SamplePerformance, null, Timeout.Infinite, Timeout.Infinite);
|
_samplingTimer = new Timer(SamplePerformance, null, Timeout.Infinite, Timeout.Infinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Starts monitoring performance.
|
/// Starts monitoring performance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -51,7 +51,7 @@ namespace AdvChkSys.Threading
|
|||||||
_samplingTimer.Change(TimeSpan.Zero, _samplingInterval);
|
_samplingTimer.Change(TimeSpan.Zero, _samplingInterval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stops monitoring performance.
|
/// Stops monitoring performance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -63,7 +63,7 @@ namespace AdvChkSys.Threading
|
|||||||
_samplingTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
_samplingTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Samples performance metrics.
|
/// Samples performance metrics.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -71,28 +71,28 @@ namespace AdvChkSys.Threading
|
|||||||
{
|
{
|
||||||
if (!_isEnabled)
|
if (!_isEnabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Sample thread pool information
|
// Sample thread pool information
|
||||||
ThreadPool.GetAvailableThreads(out int workerThreads, out int completionPortThreads);
|
ThreadPool.GetAvailableThreads(out int workerThreads, out int completionPortThreads);
|
||||||
ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxCompletionPortThreads);
|
ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxCompletionPortThreads);
|
||||||
|
|
||||||
// Calculate thread pool usage
|
// Calculate thread pool usage
|
||||||
double workerThreadUsage = 1.0 - ((double)workerThreads / maxWorkerThreads);
|
double workerThreadUsage = 1.0 - ((double)workerThreads / maxWorkerThreads);
|
||||||
double ioThreadUsage = 1.0 - ((double)completionPortThreads / maxCompletionPortThreads);
|
double ioThreadUsage = 1.0 - ((double)completionPortThreads / maxCompletionPortThreads);
|
||||||
|
|
||||||
// Update metrics
|
// Update metrics
|
||||||
UpdateMetric("ThreadPool.WorkerThreadUsage", workerThreadUsage);
|
UpdateMetric("ThreadPool.WorkerThreadUsage", workerThreadUsage);
|
||||||
UpdateMetric("ThreadPool.IOThreadUsage", ioThreadUsage);
|
UpdateMetric("ThreadPool.IOThreadUsage", ioThreadUsage);
|
||||||
|
|
||||||
// Sample operation queue information
|
// Sample operation queue information
|
||||||
var operationQueue = ChunkThreadingManager.Instance.OperationQueue;
|
var operationQueue = ChunkThreadingManager.Instance.OperationQueue;
|
||||||
UpdateMetric("OperationQueue.PendingOperations", operationQueue.PendingOperationCount);
|
UpdateMetric("OperationQueue.PendingOperations", operationQueue.PendingOperationCount);
|
||||||
UpdateMetric("OperationQueue.ActiveOperations", operationQueue.ActiveOperationCount);
|
UpdateMetric("OperationQueue.ActiveOperations", operationQueue.ActiveOperationCount);
|
||||||
|
|
||||||
// Sample diagnostics information
|
// Sample diagnostics information
|
||||||
UpdateMetric("Diagnostics.ActiveOperations", ChunkThreadingDiagnostics.GetActiveOperationCount());
|
UpdateMetric("Diagnostics.ActiveOperations", ChunkThreadingDiagnostics.GetActiveOperationCount());
|
||||||
UpdateMetric("Diagnostics.LockContentions", ChunkThreadingDiagnostics.GetTotalLockContentionCount());
|
UpdateMetric("Diagnostics.LockContentions", ChunkThreadingDiagnostics.GetTotalLockContentionCount());
|
||||||
|
|
||||||
// Sample process information
|
// Sample process information
|
||||||
var process = Process.GetCurrentProcess();
|
var process = Process.GetCurrentProcess();
|
||||||
// Fix: Use process.TotalProcessorTime and calculate uptime manually
|
// Fix: Use process.TotalProcessorTime and calculate uptime manually
|
||||||
@ -101,7 +101,7 @@ namespace AdvChkSys.Threading
|
|||||||
UpdateMetric("Process.Memory", process.WorkingSet64 / 1024.0 / 1024.0); // MB
|
UpdateMetric("Process.Memory", process.WorkingSet64 / 1024.0 / 1024.0); // MB
|
||||||
UpdateMetric("Process.Threads", process.Threads.Count);
|
UpdateMetric("Process.Threads", process.Threads.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates a performance metric.
|
/// Updates a performance metric.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -112,36 +112,36 @@ namespace AdvChkSys.Threading
|
|||||||
metric = new PerformanceMetric(_maxHistory);
|
metric = new PerformanceMetric(_maxHistory);
|
||||||
_metrics[name] = metric;
|
_metrics[name] = metric;
|
||||||
}
|
}
|
||||||
|
|
||||||
metric.AddSample(value);
|
metric.AddSample(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a performance report.
|
/// Gets a performance report.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<string, PerformanceReport> GetPerformanceReport()
|
public Dictionary<string, PerformanceReport> GetPerformanceReport()
|
||||||
{
|
{
|
||||||
var report = new Dictionary<string, PerformanceReport>();
|
var report = new Dictionary<string, PerformanceReport>();
|
||||||
|
|
||||||
foreach (var kvp in _metrics)
|
foreach (var kvp in _metrics)
|
||||||
{
|
{
|
||||||
report[kvp.Key] = kvp.Value.GetReport();
|
report[kvp.Key] = kvp.Value.GetReport();
|
||||||
}
|
}
|
||||||
|
|
||||||
return report;
|
return report;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a formatted performance report.
|
/// Gets a formatted performance report.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string GetFormattedReport()
|
public string GetFormattedReport()
|
||||||
{
|
{
|
||||||
var report = new System.Text.StringBuilder();
|
var report = new System.Text.StringBuilder();
|
||||||
|
|
||||||
report.AppendLine("=== Chunk Threading Performance Report ===");
|
report.AppendLine("=== Chunk Threading Performance Report ===");
|
||||||
report.AppendLine($"Generated: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC");
|
report.AppendLine($"Generated: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC");
|
||||||
report.AppendLine();
|
report.AppendLine();
|
||||||
|
|
||||||
var metrics = _metrics.OrderBy(m => m.Key).ToList();
|
var metrics = _metrics.OrderBy(m => m.Key).ToList();
|
||||||
foreach (var kvp in metrics)
|
foreach (var kvp in metrics)
|
||||||
{
|
{
|
||||||
@ -153,10 +153,10 @@ namespace AdvChkSys.Threading
|
|||||||
report.AppendLine($" Max: {metricReport.Max:F3}");
|
report.AppendLine($" Max: {metricReport.Max:F3}");
|
||||||
report.AppendLine();
|
report.AppendLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
return report.ToString();
|
return report.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disposes resources.
|
/// Disposes resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -165,7 +165,7 @@ namespace AdvChkSys.Threading
|
|||||||
Stop();
|
Stop();
|
||||||
_samplingTimer.Dispose();
|
_samplingTimer.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a performance metric with history.
|
/// Represents a performance metric with history.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -173,26 +173,26 @@ namespace AdvChkSys.Threading
|
|||||||
{
|
{
|
||||||
private readonly Queue<double> _samples;
|
private readonly Queue<double> _samples;
|
||||||
private readonly int _maxSamples;
|
private readonly int _maxSamples;
|
||||||
|
|
||||||
public PerformanceMetric(int maxSamples)
|
public PerformanceMetric(int maxSamples)
|
||||||
{
|
{
|
||||||
_maxSamples = maxSamples;
|
_maxSamples = maxSamples;
|
||||||
_samples = new Queue<double>(maxSamples);
|
_samples = new Queue<double>(maxSamples);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddSample(double value)
|
public void AddSample(double value)
|
||||||
{
|
{
|
||||||
lock (_samples)
|
lock (_samples)
|
||||||
{
|
{
|
||||||
_samples.Enqueue(value);
|
_samples.Enqueue(value);
|
||||||
|
|
||||||
while (_samples.Count > _maxSamples)
|
while (_samples.Count > _maxSamples)
|
||||||
{
|
{
|
||||||
_samples.Dequeue();
|
_samples.Dequeue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public PerformanceReport GetReport()
|
public PerformanceReport GetReport()
|
||||||
{
|
{
|
||||||
lock (_samples)
|
lock (_samples)
|
||||||
@ -201,7 +201,7 @@ namespace AdvChkSys.Threading
|
|||||||
{
|
{
|
||||||
return new PerformanceReport(0, 0, 0, 0, Array.Empty<double>());
|
return new PerformanceReport(0, 0, 0, 0, Array.Empty<double>());
|
||||||
}
|
}
|
||||||
|
|
||||||
var samplesArray = _samples.ToArray();
|
var samplesArray = _samples.ToArray();
|
||||||
return new PerformanceReport(
|
return new PerformanceReport(
|
||||||
samplesArray.Last(),
|
samplesArray.Last(),
|
||||||
@ -213,7 +213,7 @@ namespace AdvChkSys.Threading
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a performance report.
|
/// Represents a performance report.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -223,27 +223,35 @@ namespace AdvChkSys.Threading
|
|||||||
/// The current value.
|
/// The current value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double Current { get; }
|
public double Current { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The average value.
|
/// The average value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double Average { get; }
|
public double Average { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The minimum value.
|
/// The minimum value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double Min { get; }
|
public double Min { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum value.
|
/// The maximum value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double Max { get; }
|
public double Max { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The history of values.
|
/// The history of values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double[] History { get; }
|
public double[] History { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="current"></param>
|
||||||
|
/// <param name="average"></param>
|
||||||
|
/// <param name="min"></param>
|
||||||
|
/// <param name="max"></param>
|
||||||
|
/// <param name="history"></param>
|
||||||
public PerformanceReport(double current, double average, double min, double max, double[] history)
|
public PerformanceReport(double current, double average, double min, double max, double[] history)
|
||||||
{
|
{
|
||||||
Current = current;
|
Current = current;
|
||||||
|
|||||||
@ -35,8 +35,10 @@ namespace AdvChkSys.Util
|
|||||||
|
|
||||||
private static ulong GetAvailableMemoryWindows()
|
private static ulong GetAvailableMemoryWindows()
|
||||||
{
|
{
|
||||||
var memStatus = new MEMORYSTATUSEX();
|
var memStatus = new MEMORYSTATUSEX
|
||||||
memStatus.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
|
{
|
||||||
|
dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX))
|
||||||
|
};
|
||||||
if (GlobalMemoryStatusEx(ref memStatus))
|
if (GlobalMemoryStatusEx(ref memStatus))
|
||||||
{
|
{
|
||||||
return memStatus.ullAvailPhys;
|
return memStatus.ullAvailPhys;
|
||||||
@ -81,21 +83,61 @@ namespace AdvChkSys.Util
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Structure containing memory status information for Windows systems.
|
||||||
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||||
public struct MEMORYSTATUSEX
|
public struct MEMORYSTATUSEX
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The size of the structure, in bytes. You must set this member before calling GlobalMemoryStatusEx.
|
||||||
|
/// </summary>
|
||||||
public uint dwLength;
|
public uint dwLength;
|
||||||
|
/// <summary>
|
||||||
|
/// A number between 0 and 100 that specifies the approximate percentage of physical memory
|
||||||
|
/// that is in use (0 indicates no memory use and 100 indicates full memory use).
|
||||||
|
/// </summary>
|
||||||
public uint dwMemoryLoad;
|
public uint dwMemoryLoad;
|
||||||
|
/// <summary>
|
||||||
|
/// The total size of physical memory, in bytes.
|
||||||
|
/// </summary>
|
||||||
public ulong ullTotalPhys;
|
public ulong ullTotalPhys;
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of physical memory currently available, in bytes.
|
||||||
|
/// This is the amount of physical memory that can be immediately reused without having to write its contents to disk first.
|
||||||
|
/// </summary>
|
||||||
public ulong ullAvailPhys;
|
public ulong ullAvailPhys;
|
||||||
|
/// <summary>
|
||||||
|
/// The current committed memory limit for the system or the current process, whichever is smaller, in bytes.
|
||||||
|
/// </summary>
|
||||||
public ulong ullTotalPageFile;
|
public ulong ullTotalPageFile;
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum amount of memory the current process can commit, in bytes.
|
||||||
|
/// This value is equal to or smaller than the system-wide available commit value.
|
||||||
|
/// </summary>
|
||||||
public ulong ullAvailPageFile;
|
public ulong ullAvailPageFile;
|
||||||
|
/// <summary>
|
||||||
|
/// The size of the user-mode portion of the virtual address space of the calling process, in bytes.
|
||||||
|
/// </summary>
|
||||||
public ulong ullTotalVirtual;
|
public ulong ullTotalVirtual;
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of unreserved and uncommitted memory currently in the user-mode portion
|
||||||
|
/// of the virtual address space of the calling process, in bytes.
|
||||||
|
/// </summary>
|
||||||
public ulong ullAvailVirtual;
|
public ulong ullAvailVirtual;
|
||||||
|
/// <summary>
|
||||||
|
/// Reserved. This value is always 0.
|
||||||
|
/// </summary>
|
||||||
public ulong ullAvailExtendedVirtual;
|
public ulong ullAvailExtendedVirtual;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves information about the system's current usage of both physical and virtual memory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lpBuffer">A pointer to a <see cref="MEMORYSTATUSEX"/> structure that receives the memory status information.</param>
|
||||||
|
/// <returns>If the function succeeds, the return value is <c>true</c>. If the function fails, the return value is <c>false</c>.</returns>
|
||||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||||
public static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);
|
public static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user