VerifyCacheFilesOperation.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Threading;
  6. namespace YooAsset
  7. {
  8. internal abstract class VerifyCacheFilesOperation : AsyncOperationBase
  9. {
  10. public static VerifyCacheFilesOperation CreateOperation(CacheManager cache, List<VerifyCacheFileElement> elements)
  11. {
  12. #if UNITY_WEBGL
  13. var operation = new VerifyCacheFilesWithoutThreadOperation(cache, elements);
  14. #else
  15. var operation = new VerifyCacheFilesWithThreadOperation(cache, elements);
  16. #endif
  17. return operation;
  18. }
  19. }
  20. /// <summary>
  21. /// 本地缓存文件验证(线程版)
  22. /// </summary>
  23. internal class VerifyCacheFilesWithThreadOperation : VerifyCacheFilesOperation
  24. {
  25. private enum ESteps
  26. {
  27. None,
  28. InitVerify,
  29. UpdateVerify,
  30. Done,
  31. }
  32. private readonly ThreadSyncContext _syncContext = new ThreadSyncContext();
  33. private readonly CacheManager _cache;
  34. private List<VerifyCacheFileElement> _waitingList;
  35. private List<VerifyCacheFileElement> _verifyingList;
  36. private int _verifyMaxNum;
  37. private int _verifyTotalCount;
  38. private float _verifyStartTime;
  39. private int _succeedCount;
  40. private int _failedCount;
  41. private ESteps _steps = ESteps.None;
  42. public VerifyCacheFilesWithThreadOperation(CacheManager cache, List<VerifyCacheFileElement> elements)
  43. {
  44. _cache = cache;
  45. _waitingList = elements;
  46. }
  47. internal override void InternalOnStart()
  48. {
  49. _steps = ESteps.InitVerify;
  50. _verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
  51. }
  52. internal override void InternalOnUpdate()
  53. {
  54. if (_steps == ESteps.None || _steps == ESteps.Done)
  55. return;
  56. if (_steps == ESteps.InitVerify)
  57. {
  58. int fileCount = _waitingList.Count;
  59. // 设置同时验证的最大数
  60. ThreadPool.GetMaxThreads(out int workerThreads, out int ioThreads);
  61. YooLogger.Log($"Work threads : {workerThreads}, IO threads : {ioThreads}");
  62. _verifyMaxNum = Math.Min(workerThreads, ioThreads);
  63. _verifyTotalCount = fileCount;
  64. if (_verifyMaxNum < 1)
  65. _verifyMaxNum = 1;
  66. _verifyingList = new List<VerifyCacheFileElement>(_verifyMaxNum);
  67. _steps = ESteps.UpdateVerify;
  68. }
  69. if (_steps == ESteps.UpdateVerify)
  70. {
  71. _syncContext.Update();
  72. Progress = GetProgress();
  73. if (_waitingList.Count == 0 && _verifyingList.Count == 0)
  74. {
  75. _steps = ESteps.Done;
  76. Status = EOperationStatus.Succeed;
  77. float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
  78. YooLogger.Log($"Verify cache files elapsed time {costTime:f1} seconds");
  79. }
  80. for (int i = _waitingList.Count - 1; i >= 0; i--)
  81. {
  82. if (OperationSystem.IsBusy)
  83. break;
  84. if (_verifyingList.Count >= _verifyMaxNum)
  85. break;
  86. var element = _waitingList[i];
  87. if (BeginVerifyFileWithThread(element))
  88. {
  89. _waitingList.RemoveAt(i);
  90. _verifyingList.Add(element);
  91. }
  92. else
  93. {
  94. YooLogger.Warning("The thread pool is failed queued.");
  95. break;
  96. }
  97. }
  98. }
  99. }
  100. private float GetProgress()
  101. {
  102. if (_verifyTotalCount == 0)
  103. return 1f;
  104. return (float)(_succeedCount + _failedCount) / _verifyTotalCount;
  105. }
  106. private bool BeginVerifyFileWithThread(VerifyCacheFileElement element)
  107. {
  108. return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), element);
  109. }
  110. private void VerifyInThread(object obj)
  111. {
  112. VerifyCacheFileElement element = (VerifyCacheFileElement)obj;
  113. element.Result = CacheHelper.VerifyingCacheFile(element, _cache.BootVerifyLevel);
  114. _syncContext.Post(VerifyCallback, element);
  115. }
  116. private void VerifyCallback(object obj)
  117. {
  118. VerifyCacheFileElement element = (VerifyCacheFileElement)obj;
  119. _verifyingList.Remove(element);
  120. if (element.Result == EVerifyResult.Succeed)
  121. {
  122. _succeedCount++;
  123. var wrapper = new CacheManager.RecordWrapper(element.InfoFilePath, element.DataFilePath, element.DataFileCRC, element.DataFileSize);
  124. _cache.Record(element.CacheGUID, wrapper);
  125. }
  126. else
  127. {
  128. _failedCount++;
  129. YooLogger.Warning($"Failed verify file and delete files : {element.FileRootPath}");
  130. element.DeleteFiles();
  131. }
  132. }
  133. }
  134. /// <summary>
  135. /// 本地缓存文件验证(非线程版)
  136. /// </summary>
  137. internal class VerifyCacheFilesWithoutThreadOperation : VerifyCacheFilesOperation
  138. {
  139. private enum ESteps
  140. {
  141. None,
  142. InitVerify,
  143. UpdateVerify,
  144. Done,
  145. }
  146. private readonly CacheManager _cache;
  147. private List<VerifyCacheFileElement> _waitingList;
  148. private List<VerifyCacheFileElement> _verifyingList;
  149. private int _verifyMaxNum;
  150. private int _verifyTotalCount;
  151. private float _verifyStartTime;
  152. private int _succeedCount;
  153. private int _failedCount;
  154. private ESteps _steps = ESteps.None;
  155. public VerifyCacheFilesWithoutThreadOperation(CacheManager cache, List<VerifyCacheFileElement> elements)
  156. {
  157. _cache = cache;
  158. _waitingList = elements;
  159. }
  160. internal override void InternalOnStart()
  161. {
  162. _steps = ESteps.InitVerify;
  163. _verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
  164. }
  165. internal override void InternalOnUpdate()
  166. {
  167. if (_steps == ESteps.None || _steps == ESteps.Done)
  168. return;
  169. if (_steps == ESteps.InitVerify)
  170. {
  171. int fileCount = _waitingList.Count;
  172. // 设置同时验证的最大数
  173. _verifyMaxNum = fileCount;
  174. _verifyTotalCount = fileCount;
  175. _verifyingList = new List<VerifyCacheFileElement>(_verifyMaxNum);
  176. _steps = ESteps.UpdateVerify;
  177. }
  178. if (_steps == ESteps.UpdateVerify)
  179. {
  180. Progress = GetProgress();
  181. if (_waitingList.Count == 0 && _verifyingList.Count == 0)
  182. {
  183. _steps = ESteps.Done;
  184. Status = EOperationStatus.Succeed;
  185. float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
  186. YooLogger.Log($"Package verify elapsed time {costTime:f1} seconds");
  187. }
  188. for (int i = _waitingList.Count - 1; i >= 0; i--)
  189. {
  190. if (OperationSystem.IsBusy)
  191. break;
  192. if (_verifyingList.Count >= _verifyMaxNum)
  193. break;
  194. var element = _waitingList[i];
  195. BeginVerifyFileWithoutThread(element);
  196. _waitingList.RemoveAt(i);
  197. _verifyingList.Add(element);
  198. }
  199. // 主线程内验证,可以清空列表
  200. _verifyingList.Clear();
  201. }
  202. }
  203. private float GetProgress()
  204. {
  205. if (_verifyTotalCount == 0)
  206. return 1f;
  207. return (float)(_succeedCount + _failedCount) / _verifyTotalCount;
  208. }
  209. private void BeginVerifyFileWithoutThread(VerifyCacheFileElement element)
  210. {
  211. element.Result = CacheHelper.VerifyingCacheFile(element, _cache.BootVerifyLevel);
  212. if (element.Result == EVerifyResult.Succeed)
  213. {
  214. _succeedCount++;
  215. var wrapper = new CacheManager.RecordWrapper(element.InfoFilePath, element.DataFilePath, element.DataFileCRC, element.DataFileSize);
  216. _cache.Record(element.CacheGUID, wrapper);
  217. }
  218. else
  219. {
  220. _failedCount++;
  221. YooLogger.Warning($"Failed verify file and delete files : {element.FileRootPath}");
  222. element.DeleteFiles();
  223. }
  224. }
  225. }
  226. }