123 lines
4.3 KiB
C#
123 lines
4.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using DCIT.Core.Models;
|
|
|
|
namespace DCIT.Core.Services
|
|
{
|
|
public sealed class BatchExecutionPlanner
|
|
{
|
|
public BatchExecutionPlan CreatePlan(IList<FileScanItem> selectedItems, int processorCount)
|
|
{
|
|
var executionItems = new List<FileScanItem>();
|
|
var skippedItems = new List<BatchExecutionSkipItem>();
|
|
var sourcePaths = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
var outputPaths = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
var diffPaths = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
if (selectedItems != null)
|
|
{
|
|
foreach (var item in selectedItems)
|
|
{
|
|
if (item == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var sourcePath = NormalizePath(item.SourcePath);
|
|
var outputPath = NormalizePath(item.OutputPath);
|
|
var diffPath = NormalizePath(item.DiffPath);
|
|
|
|
var collision = GetCollision(sourcePath, sourcePaths, BatchExecutionSkipReason.DuplicateSourcePath);
|
|
if (collision == null)
|
|
{
|
|
collision = GetCollision(outputPath, outputPaths, BatchExecutionSkipReason.DuplicateOutputPath);
|
|
}
|
|
|
|
if (collision == null && !string.IsNullOrWhiteSpace(diffPath))
|
|
{
|
|
collision = GetCollision(diffPath, diffPaths, BatchExecutionSkipReason.DuplicateDiffPath);
|
|
}
|
|
|
|
if (collision != null)
|
|
{
|
|
collision.Item = item;
|
|
skippedItems.Add(collision);
|
|
continue;
|
|
}
|
|
|
|
AddIfPresent(sourcePaths, sourcePath);
|
|
AddIfPresent(outputPaths, outputPath);
|
|
AddIfPresent(diffPaths, diffPath);
|
|
executionItems.Add(item);
|
|
}
|
|
}
|
|
|
|
var requiresSerialExecution = executionItems.Any(item => Path.GetExtension(item.SourcePath).Equals(".doc", StringComparison.OrdinalIgnoreCase));
|
|
var degreeOfParallelism = DetermineDegreeOfParallelism(executionItems.Count, processorCount, requiresSerialExecution);
|
|
|
|
return new BatchExecutionPlan
|
|
{
|
|
ExecutionItems = executionItems,
|
|
SkippedItems = skippedItems,
|
|
DegreeOfParallelism = degreeOfParallelism,
|
|
RequiresSerialExecution = requiresSerialExecution,
|
|
};
|
|
}
|
|
|
|
private static BatchExecutionSkipItem GetCollision(string path, HashSet<string> existingPaths, BatchExecutionSkipReason reason)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(path) || !existingPaths.Contains(path))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return new BatchExecutionSkipItem
|
|
{
|
|
Reason = reason,
|
|
ConflictingPath = path,
|
|
ExistingPath = path,
|
|
};
|
|
}
|
|
|
|
private static void AddIfPresent(HashSet<string> set, string path)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(path))
|
|
{
|
|
set.Add(path);
|
|
}
|
|
}
|
|
|
|
private static int DetermineDegreeOfParallelism(int itemCount, int processorCount, bool requiresSerialExecution)
|
|
{
|
|
if (itemCount <= 0 || requiresSerialExecution)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
var normalizedProcessorCount = processorCount > 0 ? processorCount : Environment.ProcessorCount;
|
|
normalizedProcessorCount = Math.Max(1, normalizedProcessorCount);
|
|
return Math.Max(1, Math.Min(itemCount, normalizedProcessorCount));
|
|
}
|
|
|
|
private static string NormalizePath(string path)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(path))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
try
|
|
{
|
|
return Path.GetFullPath(path)
|
|
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
|
}
|
|
catch
|
|
{
|
|
return path.Trim();
|
|
}
|
|
}
|
|
}
|
|
}
|