diff --git a/Assets/PatchKit Patcher/Scripts/AppData/Local/MapHashExtractedFiles.cs b/Assets/PatchKit Patcher/Scripts/AppData/Local/MapHashExtractedFiles.cs index 674bc33b..eb042c9d 100644 --- a/Assets/PatchKit Patcher/Scripts/AppData/Local/MapHashExtractedFiles.cs +++ b/Assets/PatchKit Patcher/Scripts/AppData/Local/MapHashExtractedFiles.cs @@ -4,25 +4,32 @@ namespace PatchKit.Unity.Patcher.AppData.Local { public class MapHashExtractedFiles { - private Dictionary MapHash; + private volatile Dictionary _mapHash; public MapHashExtractedFiles() { - MapHash = new Dictionary(); + _mapHash = new Dictionary(); } public string Add(string path) { string nameHash = HashCalculator.ComputeMD5Hash(path); - MapHash.Add(path, nameHash); + lock (_mapHash) + { + _mapHash.Add(path, nameHash); + } + return nameHash; } public bool TryGetHash(string path,out string nameHash) { - if (MapHash.TryGetValue(path, out nameHash)) + lock (_mapHash) { - return true; + if (_mapHash.TryGetValue(path, out nameHash)) + { + return true; + } } return false; diff --git a/Assets/PatchKit Patcher/Scripts/AppData/Local/Pack1Unarchiver.cs b/Assets/PatchKit Patcher/Scripts/AppData/Local/Pack1Unarchiver.cs index 283e4e3c..37ac54a1 100755 --- a/Assets/PatchKit Patcher/Scripts/AppData/Local/Pack1Unarchiver.cs +++ b/Assets/PatchKit Patcher/Scripts/AppData/Local/Pack1Unarchiver.cs @@ -9,11 +9,10 @@ using PatchKit.Unity.Patcher.Data; using PatchKit.Unity.Patcher.Debug; using PatchKit.Unity.Utilities; -using SharpCompress.Compressors.LZMA; using SharpCompress.Compressors.Xz; using SharpRaven; using SharpRaven.Data; -using SharpRaven.Utilities; +using FileMode = System.IO.FileMode; namespace PatchKit.Unity.Patcher.AppData.Local { @@ -41,7 +40,7 @@ public class Pack1Unarchiver : IUnarchiver /// private readonly BytesRange _range; - private MapHashExtractedFiles _mapHashExtractedFiles; + private volatile MapHashExtractedFiles _mapHashExtractedFiles; public event UnarchiveProgressChangedHandler UnarchiveProgressChanged; @@ -113,7 +112,7 @@ public void Unarchive(CancellationToken cancellationToken) Unpack(file, progress => { OnUnarchiveProgressChanged(currentFile.Name, currentFile.Type == Pack1Meta.RegularFileType, currentEntry, _metaData.Files.Length, progress); - }, cancellationToken); + }, cancellationToken, false); } else { @@ -124,6 +123,8 @@ public void Unarchive(CancellationToken cancellationToken) entry++; } + + ThreadingPool.WaitOne(cancellationToken); DebugLogger.Log("Unpacking finished succesfully!"); } @@ -136,7 +137,7 @@ public void UnarchiveSingleFile(Pack1Meta.FileEntry file, CancellationToken canc throw new ArgumentOutOfRangeException("file", file, null); } - Unpack(file, progress => OnUnarchiveProgressChanged(file.Name, file.Type == Pack1Meta.RegularFileType, 1, 1, progress), cancellationToken, destinationDirPath); + Unpack(file, progress => OnUnarchiveProgressChanged(file.Name, file.Type == Pack1Meta.RegularFileType, 1, 1, progress), cancellationToken, true, destinationDirPath); OnUnarchiveProgressChanged(file.Name, file.Type == Pack1Meta.RegularFileType, 0, 1, 1.0); } @@ -156,14 +157,24 @@ private bool CanUnpack(Pack1Meta.FileEntry file) return file.Offset >= _range.Start && file.Offset + file.Size <= _range.End; } - private void Unpack(Pack1Meta.FileEntry file, Action progress, CancellationToken cancellationToken, string destinationDirPath = null) + private void Unpack(Pack1Meta.FileEntry file, Action progress, CancellationToken cancellationToken, bool canUseThreadPool, string destinationDirPath = null) { switch (file.Type) { case Pack1Meta.RegularFileType: try { - UnpackRegularFile(file, progress, cancellationToken, destinationDirPath); + progress(0.0); + if (file.Size.Value < 524288 && !canUseThreadPool) + { + ThreadingPool.ThreadingPoolExecute(cancellationToken, + () => UnpackRegularFile(file, cancellationToken, destinationDirPath)); + } + else + { + UnpackRegularFile(file, cancellationToken, destinationDirPath); + } + progress(1.0); } catch (Ionic.Zlib.ZlibException e) { @@ -232,9 +243,15 @@ private DecompressorCreator ResolveDecompressor(Pack1Meta meta) } } - private void UnpackRegularFile(Pack1Meta.FileEntry file, Action onProgress, CancellationToken cancellationToken, string destinationDirPath = null) + private void UnpackRegularFile(Pack1Meta.FileEntry file, CancellationToken cancellationToken, string destinationDirPath = null) { - string destPath = Path.Combine(destinationDirPath == null ? _destinationDirPath : destinationDirPath, _mapHashExtractedFiles.Add(file.Name) + _suffix); + string fileRealName; + lock (_mapHashExtractedFiles) + { + fileRealName = _mapHashExtractedFiles.Add(file.Name) + _suffix; + } + + string destPath = Path.Combine(destinationDirPath == null ? _destinationDirPath : destinationDirPath, fileRealName); DebugLogger.LogFormat("Unpacking regular file {0} to {1}", file, destPath); @@ -269,7 +286,7 @@ private void UnpackRegularFile(Pack1Meta.FileEntry file, Action onProgre DecompressorCreator decompressorCreator = ResolveDecompressor(_metaData); - using (var fs = new FileStream(_packagePath, FileMode.Open)) + using (var fs = new FileStream(_packagePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { fs.Seek(file.Offset.Value - _range.Start, SeekOrigin.Begin); @@ -279,7 +296,7 @@ private void UnpackRegularFile(Pack1Meta.FileEntry file, Action onProgre { using (var target = new FileStream(destPath, FileMode.Create)) { - ExtractFileFromStream(limitedStream, target, file.Size.Value, decryptor, decompressorCreator, onProgress, cancellationToken); + ExtractFileFromStream(limitedStream, target, decryptor, decompressorCreator, cancellationToken); DebugTestCorruption(target); } } @@ -338,10 +355,8 @@ private Stream CreateGzipDecompressor(Stream source) private void ExtractFileFromStream( Stream sourceStream, Stream targetStream, - long fileSize, ICryptoTransform decryptor, DecompressorCreator createDecompressor, - Action onProgress, CancellationToken cancellationToken) { using (var cryptoStream = new CryptoStream(sourceStream, decryptor, CryptoStreamMode.Read)) @@ -364,9 +379,6 @@ private void ExtractFileFromStream( { cancellationToken.ThrowIfCancellationRequested(); targetStream.Write(buffer, 0, count); - - long bytesProcessed = sourceStream.Position; - onProgress(bytesProcessed / (double) fileSize); } } catch (OperationCanceledException) diff --git a/Assets/PatchKit Patcher/Scripts/Utilities/ThreadingPool.cs b/Assets/PatchKit Patcher/Scripts/Utilities/ThreadingPool.cs new file mode 100644 index 00000000..6f185a6d --- /dev/null +++ b/Assets/PatchKit Patcher/Scripts/Utilities/ThreadingPool.cs @@ -0,0 +1,53 @@ +using System; +using System.Threading; +using PatchKit.Unity.Patcher.Cancellation; +using PatchKit.Unity.Patcher.Debug; + +namespace PatchKit.Unity.Utilities +{ + public static class ThreadingPool + { + private static readonly DebugLogger DebugLogger = new DebugLogger(typeof(ThreadingPool)); + + private static Semaphore _pool = new Semaphore(16, 17); + private static ManualResetEvent _awaiter = new ManualResetEvent(false); + + public static void ThreadingPoolExecute(CancellationToken cancellationToken, Action action) + { + _pool.WaitOne(); + ThreadPool.QueueUserWorkItem(state => ThreadingPoolProc(cancellationToken, action)); + } + + private static void ThreadingPoolProc(CancellationToken cancellationToken, Action action) + { + try + { + action(); + } + catch (Exception e) + { + DebugLogger.LogError(e.ToString()); + throw; + } + finally + { + int release = _pool.Release(); + if (release == 16 || cancellationToken.IsCancelled) + { + _awaiter.Set(); + } + } + } + + public static void WaitOne(CancellationToken cancellationToken) + { + var release = _pool.Release(); + if (release == 16 || cancellationToken.IsCancelled) + { + _awaiter.Set(); + } + + _awaiter.WaitOne(); + } + } +} \ No newline at end of file diff --git a/Assets/PatchKit Patcher/Scripts/Utilities/ThreadingPool.cs.meta b/Assets/PatchKit Patcher/Scripts/Utilities/ThreadingPool.cs.meta new file mode 100644 index 00000000..ceea43d7 --- /dev/null +++ b/Assets/PatchKit Patcher/Scripts/Utilities/ThreadingPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 54f8f0c8ae07164488ddf2191d3a3977 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: