| 523 | } |
| 524 | |
| 525 | static bool RequeueFromWorker(WorkItem item) { |
| 526 | std::lock_guard<std::mutex> lock(g_queueMutex); |
| 527 | if (item.type == WorkItem::Upload) { |
| 528 | // A present index entry means a newer upload is already queued for this |
| 529 | // path, so drop the retry instead of walking the list under the lock. |
| 530 | if (g_uploadIndex.find(item.cloudPath) != g_uploadIndex.end()) { |
| 531 | LOG("[CloudStorage] Retry dropped: newer upload already queued for %s", |
| 532 | item.cloudPath.c_str()); |
| 533 | g_failedPaths.erase(item.cloudPath); |
| 534 | g_failedWorkItems.erase(item.cloudPath); |
| 535 | return false; |
| 536 | } |
| 537 | } |
| 538 | if (item.type == WorkItem::Delete) { |
| 539 | ClearRecentUploadForDeleteLocked(item.cloudPath); |
| 540 | auto indexIt = g_uploadIndex.find(item.cloudPath); |
| 541 | if (indexIt != g_uploadIndex.end()) { |
| 542 | LOG("[CloudStorage] Retry dropped: upload supersedes stale delete for %s", |
| 543 | item.cloudPath.c_str()); |
| 544 | g_failedPaths.erase(item.cloudPath); |
| 545 | g_failedWorkItems.erase(item.cloudPath); |
| 546 | return false; |
| 547 | } |
| 548 | } |
| 549 | g_failedPaths.erase(item.cloudPath); |
| 550 | g_failedWorkItems.erase(item.cloudPath); |
| 551 | g_workQueue.push_back(std::move(item)); |
| 552 | auto qit = std::prev(g_workQueue.end()); |
| 553 | if (qit->type == WorkItem::Upload) { |
| 554 | g_uploadIndex[qit->cloudPath] = qit; |
| 555 | } |
| 556 | g_queueCV.notify_one(); |
| 557 | return true; |
| 558 | } |
| 559 | |
| 560 | void DrainQueue() { |
| 561 | if (!g_provider) return; |
no test coverage detected