| 257 | } |
| 258 | |
| 259 | static void WorkerLoop(int threadId) { |
| 260 | LOG("[CloudStorage] Background worker %d started", threadId); |
| 261 | int consecutiveFailures = 0; |
| 262 | while (g_workerRunning) { |
| 263 | WorkItem item; |
| 264 | { |
| 265 | std::unique_lock<std::mutex> lock(g_queueMutex); |
| 266 | auto eligibleNow = [](const WorkItem& q) { |
| 267 | return !g_activePaths.count(q.cloudPath) |
| 268 | && std::chrono::steady_clock::now() >= q.notBefore; |
| 269 | }; |
| 270 | auto havePending = [&]() { |
| 271 | if (!g_workerRunning) return true; |
| 272 | for (const auto& queued : g_workQueue) { |
| 273 | if (eligibleNow(queued)) return true; |
| 274 | } |
| 275 | return false; |
| 276 | }; |
| 277 | while (!havePending()) { |
| 278 | const auto kNoDeferred = |
| 279 | (std::chrono::steady_clock::time_point::max)(); |
| 280 | auto soonest = kNoDeferred; |
| 281 | for (const auto& queued : g_workQueue) { |
| 282 | if (g_activePaths.count(queued.cloudPath)) continue; |
| 283 | if (queued.notBefore < soonest) soonest = queued.notBefore; |
| 284 | } |
| 285 | if (soonest == kNoDeferred) { |
| 286 | g_queueCV.wait(lock); |
| 287 | } else { |
| 288 | g_queueCV.wait_until(lock, soonest); |
| 289 | } |
| 290 | if (!g_workerRunning && g_workQueue.empty()) break; |
| 291 | } |
| 292 | if (!g_workerRunning && g_workQueue.empty()) break; |
| 293 | |
| 294 | auto workIt = std::find_if(g_workQueue.begin(), g_workQueue.end(), |
| 295 | [&](const WorkItem& queued) { return eligibleNow(queued); }); |
| 296 | if (workIt == g_workQueue.end()) continue; |
| 297 | |
| 298 | item = std::move(*workIt); |
| 299 | if (item.type == WorkItem::Upload) { |
| 300 | g_uploadIndex.erase(item.cloudPath); |
| 301 | } |
| 302 | g_workQueue.erase(workIt); |
| 303 | ++g_activeWorkers; |
| 304 | ++g_activePaths[item.cloudPath]; |
| 305 | if (item.bestEffort) ++g_activeBestEffortPaths[item.cloudPath]; |
| 306 | if (item.type == WorkItem::Delete) ++g_activeDeletes[item.cloudPath]; |
| 307 | } |
| 308 | |
| 309 | if (!g_provider) { |
| 310 | std::lock_guard<std::mutex> lk(g_queueMutex); |
| 311 | auto it = g_activePaths.find(item.cloudPath); |
| 312 | if (it != g_activePaths.end() && --it->second <= 0) g_activePaths.erase(it); |
| 313 | if (item.bestEffort) ClearActiveBestEffortLocked(item.cloudPath); |
| 314 | if (item.type == WorkItem::Delete) ClearActiveDeleteLocked(item.cloudPath); |
| 315 | --g_activeWorkers; |
| 316 | g_drainCV.notify_all(); |
nothing calls this directly
no test coverage detected