| 898 | } |
| 899 | |
| 900 | void AssetsManager::retryFailedAssets() { |
| 901 | auto guard = lock(); |
| 902 | |
| 903 | // Capture before mutating _scheduledUpdates: if a pump is already pending, we only enqueue. |
| 904 | const bool needScheduleUpdates = _pauseUpdatesCount == 0 && _scheduledUpdates.empty(); |
| 905 | |
| 906 | bool anyReset = false; |
| 907 | for (const auto& it : _assets) { |
| 908 | const auto& managedAsset = it.second; |
| 909 | if (managedAsset->getState() != AssetStateFailedRetryable) { |
| 910 | continue; |
| 911 | } |
| 912 | |
| 913 | managedAsset->setState(AssetStateInitial); |
| 914 | |
| 915 | // Consumers already received the failure and are marked notified, so re-resolving alone would |
| 916 | // leave them untouched (getNextConsumerToUpdate skips notified consumers). Reset each failed |
| 917 | // consumer to its initial, un-notified state so the re-resolve re-loads and re-notifies it, |
| 918 | // exactly as a freshly added consumer would be handled. |
| 919 | for (size_t i = 0; i < managedAsset->getConsumersSize(); i++) { |
| 920 | const auto& consumer = managedAsset->getConsumer(i); |
| 921 | if (consumer->getState() == AssetConsumerStateFailed) { |
| 922 | consumer->setState(AssetConsumerStateInitial); |
| 923 | consumer->setNotified(false); |
| 924 | } |
| 925 | } |
| 926 | |
| 927 | _scheduledUpdates.emplace_back(it.first); |
| 928 | anyReset = true; |
| 929 | } |
| 930 | |
| 931 | if (anyReset && needScheduleUpdates) { |
| 932 | if (_mainThreadManager.currentThreadIsMainThread()) { |
| 933 | performUpdates(std::move(guard)); |
| 934 | } else { |
| 935 | guard.unlock(); |
| 936 | schedulePerformUpdates(); |
| 937 | } |
| 938 | } |
| 939 | } |
| 940 | |
| 941 | void AssetsManager::performUpdates(std::unique_lock<std::recursive_mutex>&& lock) { |
no test coverage detected