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