Cocos 更新时反复杀进程,导致差异更新失效的Bug
2017-08-14 21:15
369 查看
Cocos 更新时反复杀进程时,差异更新失效的问题:
问题复现步骤:
1、在project.manifest.temp 文件下载成功后,下载Assets资源的时候杀掉进程
2、重启游戏,继续更新时会使用上次下载成功的project.manifest.temp文件,这个时候因为没有将文件下载状态保存,而更新的时候又判断没有下再成功就去下载,就导致将所有文件都下载了。
下载流程分析
1、 project.manifest.temp 文件下载成功之前如果kill进程,下次进入就会删除这个文件,重新下载;PS:调用update
接口开始更新时kill进程,再次启动都会引起project.manifest.temp的重新下载,这也是导致bug的原因之一。
// 这个方法会在更新之前调用 void AssetsManagerEx::initManifests(const std::string& manifestUrl) { _inited = true; // Init and load local manifest _localManifest = new (std::nothrow) Manifest(); if (_localManifest) { loadLocalManifest(manifestUrl); // Init and load temporary manifest _tempManifest = new (std::nothrow) Manifest(); if (_tempManifest) { _tempManifest->parse(_tempManifestPath); // 这里判断如果文件不是完整的,并且存在就删除它; if (!_tempManifest->isLoaded() && _fileUtils->isFileExist(_tempManifestPath)) _fileUtils->removeFile(_tempManifestPath); } else { _inited = false; } // Init remote manifest for future usage _remoteManifest = new (std::nothrow) Manifest(); if (!_remoteManifest) { _inited = false; } } else { _inited = false; } if (!_inited) { CC_SAFE_DELETE(_localManifest); CC_SAFE_DELETE(_tempManifest); CC_SAFE_DELETE(_remoteManifest); } }
2、开始下载根据project.manifest.temp 临时文件是否完整存在来决定是恢复之前的下载状态,还是根据重新下载回来的manifest文件与本地文件对比差异度,决定下载那些。
void AssetsManagerEx::startUpdate() { if (_updateState != State::NEED_UPDATE) return; _updateState = State::UPDATING; // Clean up before update _failedUnits.clear(); _downloadUnits.clear(); _compressedFiles.clear(); _totalWaitToDownload = _totalToDownload = 0; _percent = _percentByFile = _sizeCollected = _totalSize = 0; _downloadedSize.clear(); _totalEnabled = false; // Temporary manifest exists, resuming previous download if (_tempManifest->isLoaded() && _tempManifest->versionEquals(_remoteManifest)) { // 文件是完整的,直接从文件恢复下载,并且从文件中读取下载状态,来判断是否需要下载 // 更新完成之前kill进程和每次启动程序下载project.manifest.temp文件都会导致下载状态被清空 // 恢复下载是根据manifest临时文件中保存的下载状态来决定,详细见3 _tempManifest->genResumeAssetsList(&_downloadUnits); _totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size(); this->batchDownload(); std::string msg = StringUtils::format("Resuming from previous unfinished update, %d files remains to be finished.", _totalToDownload); CCLOG(msg); // this time , the remoteManifest(has no DownloadState) file overwrite tempManifest file. when we kill process, and restart, it will uses error file. // 为了避免被重新下载的manifest文件覆盖掉下载状态,我们这里需要将当前状态再次写入文件备份 _tempManifest->saveToFile(_tempManifestPath); dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, "", msg); } // Check difference else { // Temporary manifest not exists or out of date, // it will be used to register the download states of each asset, // in this case, it equals remote manifest. _tempManifest->release(); _tempManifest = _remoteManifest; std::unordered_map<std::string, Manifest::AssetDiff> diff_map = _localManifest->genDiff(_remoteManifest); std::string log = StringUtils::format("AssetsManagerEx : Diff file size %d", diff_map.size()); CCLOG(log); if (diff_map.size() == 0) { CCLOG("AssetsManagerEx updateSucceed"); updateSucceed(); } else { // Generate download units for all assets that need to be updated or added std::string packageUrl = _remoteManifest->getPackageUrl(); for (auto it = diff_map.begin(); it != diff_map.end(); ++it) { Manifest::AssetDiff diff = it->second; if (diff.type == Manifest::DiffType::DELETED) { CCLOG("AssetsManagerEx DELETED " + diff.asset.path); _fileUtils->removeFile(_storagePath + diff.asset.path); } else { std::string path = diff.asset.path; CCLOG("AssetsManagerEx " + diff.asset.path + " type "+ diff.type); // Create path _fileUtils->createDirectory(basename(_storagePath + path)); DownloadUnit unit; unit.customId = it->first; unit.srcUrl = packageUrl + path; unit.storagePath = _storagePath + path; _downloadUnits.emplace(unit.customId, unit); } } // Set other assets' downloadState to SUCCESSED auto &assets = _remoteManifest->getAssets(); for (auto it = assets.cbegin(); it != assets.cend(); ++it) { const std::string &key = it->first; auto diffIt = diff_map.find(key); if (diffIt == diff_map.end()) { // 根据文件对比,将不需要下载的文件的状态设置为下载成功 _tempManifest->setAssetDownloadState(key, Manifest::DownloadState::SUCCESSED); } } _totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size(); this->batchDownload(); std::string msg = StringUtils::format("Start to update %d files from remote package.", _totalToDownload); // 为了避免进程在更新完成之前被kill导致下载状态丢失,这里先保存文件,备份一次 _tempManifest->saveToFile(_tempManifestPath); dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, "", msg); } } }
3、恢复下载是,需要根据之前保存在临时文件中的下载状态来决定下载那些文件
void Manifest::genResumeAssetsList(DownloadUnits *units) const { for (auto it = _assets.begin(); it != _assets.end(); ++it) { Asset asset = it->second; if (asset.downloadState != DownloadState::SUCCESSED) { DownloadUnit unit; unit.customId = it->first; unit.srcUrl = _packageUrl + asset.path; unit.storagePath = _manifestRoot + asset.path; units->emplace(unit.customId, unit); } } }
相关文章推荐
- Oracle-07445[kgghash]:Oracle BUG导致更新LOB字段时进程被KILL掉
- react native 由于平台差异导致ios平台上无缘无故出现背景色bug解决方案
- 触发了MySQL一个bug导致进程不断crash重启
- centos 7.2系统bug导致HGDB后台进程崩溃,数据库无法访问
- Windows XP自动更新导致svchost.exe进程CPU占用率100%解决方案
- 解决APP进程被杀掉之后,导致fragment失效或者错乱的办法
- 接近传感器 距离传感器 结构差异 硬件差异 导致 失效 ltr558 al3006
- app进程被系统回收导致AlarmManager失效解决办法
- BootStrap Validator 版本差异问题导致的submitHandler失效问题的解决方法
- Asp.net Membership的BUG:存储过程错误导致无法更新用户最近活动时间
- iis网站的web园的最大工作进程设置后导致session失灵,当进程数大于1,session就失效的解决办法
- 追踪导致 WebBrowser控件 编辑模式下 Ctrl + Z 失效的原因 【求大侠佐证,这算不算是微软的Bug呢?】
- BootStrap Validator 版本差异问题导致的submitHandler失效问题的解决方法
- BootStrap Validator 版本差异问题导致的submitHandler失效问题的解决方法
- Unity4.6.9 Bug导致在Android 6.0设备上黑屏,更新Unity4.7解决问题
- 针对使用python psutil库来kill进程而导致任务栏,小图标仍然显示的bug
- [AspNetPager 4.3.3]DataGrid url分页的小Bug导致更新过程无法取得编辑文本框数据
- ios模拟器和真机的差异-浮点数精度导致的bug
- win7 X64 进程名称不一致,导致杀进程失效!
- solaris系统下使用asm的bug (solaris系统248天未重启导致asm进程异常)