1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/sync_file_system/drive_backend/task_dependency_manager.h" 6 7 #include <utility> 8 9 #include "base/logging.h" 10 11 namespace sync_file_system { 12 namespace drive_backend { 13 14 namespace { 15 16 // Erases all items in |item_to_erase| from |container|. 17 template <typename Container1, typename Container2> 18 void EraseContainer(const Container1& items_to_erase, Container2* container) { 19 for (typename Container1::const_iterator itr = items_to_erase.begin(); 20 itr != items_to_erase.end(); ++itr) { 21 container->erase(*itr); 22 } 23 } 24 25 // Inserts all items in |items_to_insert| to |container|, returns true if all 26 // items are inserted successfully. Otherwise, returns false and leave 27 // |container| have the original contents. 28 template <typename Container1, typename Container2> 29 bool InsertAllOrNone(const Container1& items_to_insert, Container2* container) { 30 typedef typename Container1::const_iterator iterator; 31 for (iterator itr = items_to_insert.begin(); 32 itr != items_to_insert.end(); ++itr) { 33 if (!container->insert(*itr).second) { 34 // Revert all successful insertion. 35 iterator end = itr; 36 itr = items_to_insert.begin(); 37 for (; itr != end; ++itr) 38 container->erase(*itr); 39 return false; 40 } 41 } 42 return true; 43 } 44 45 bool InsertPaths(std::vector<base::FilePath> paths_to_insert, 46 SubtreeSet* paths) { 47 typedef std::vector<base::FilePath>::const_iterator iterator; 48 for (iterator itr = paths_to_insert.begin(); 49 itr != paths_to_insert.end(); ++itr) { 50 if (!paths->insert(*itr)) { 51 iterator end = itr; 52 for (itr = paths_to_insert.begin(); itr != end; ++itr) 53 paths->erase(*itr); 54 return false; 55 } 56 } 57 return true; 58 } 59 60 } // namespace 61 62 BlockingFactor::BlockingFactor() : exclusive(false) {} 63 BlockingFactor::~BlockingFactor() {} 64 65 TaskDependencyManager::TaskDependencyManager() 66 : running_task_count_(0), 67 running_exclusive_task_(false) {} 68 69 TaskDependencyManager::~TaskDependencyManager() { 70 DCHECK(paths_by_app_id_.empty()); 71 DCHECK(file_ids_.empty()); 72 DCHECK(tracker_ids_.empty()); 73 } 74 75 bool TaskDependencyManager::Insert(const BlockingFactor* blocking_factor) { 76 if (running_exclusive_task_) 77 return false; 78 79 if (!blocking_factor) { 80 ++running_task_count_; 81 return true; 82 } 83 84 if (blocking_factor->exclusive) { 85 if (running_task_count_ || 86 !tracker_ids_.empty() || 87 !file_ids_.empty() || 88 !paths_by_app_id_.empty()) 89 return false; 90 ++running_task_count_; 91 running_exclusive_task_ = true; 92 return true; 93 } 94 95 if (!InsertAllOrNone(blocking_factor->tracker_ids, &tracker_ids_)) 96 goto fail_on_tracker_id_insertion; 97 98 if (!InsertAllOrNone(blocking_factor->file_ids, &file_ids_)) 99 goto fail_on_file_id_insertion; 100 101 if (!blocking_factor->app_id.empty() && 102 !InsertPaths(blocking_factor->paths, 103 &paths_by_app_id_[blocking_factor->app_id])) { 104 if (paths_by_app_id_[blocking_factor->app_id].empty()) 105 paths_by_app_id_.erase(blocking_factor->app_id); 106 goto fail_on_path_insertion; 107 } 108 109 ++running_task_count_; 110 return true; 111 112 fail_on_path_insertion: 113 EraseContainer(blocking_factor->file_ids, &file_ids_); 114 fail_on_file_id_insertion: 115 EraseContainer(blocking_factor->tracker_ids, &tracker_ids_); 116 fail_on_tracker_id_insertion: 117 118 return false; 119 } 120 121 void TaskDependencyManager::Erase(const BlockingFactor* blocking_factor) { 122 --running_task_count_; 123 DCHECK_LE(0, running_task_count_); 124 if (!blocking_factor) 125 return; 126 127 if (blocking_factor->exclusive) { 128 DCHECK(running_exclusive_task_); 129 DCHECK(paths_by_app_id_.empty()); 130 DCHECK(file_ids_.empty()); 131 DCHECK(tracker_ids_.empty()); 132 DCHECK_EQ(0, running_task_count_); 133 134 running_exclusive_task_ = false; 135 return; 136 } 137 138 if (!blocking_factor->app_id.empty()) { 139 EraseContainer(blocking_factor->paths, 140 &paths_by_app_id_[blocking_factor->app_id]); 141 if (paths_by_app_id_[blocking_factor->app_id].empty()) 142 paths_by_app_id_.erase(blocking_factor->app_id); 143 } 144 145 EraseContainer(blocking_factor->file_ids, &file_ids_); 146 EraseContainer(blocking_factor->tracker_ids, &tracker_ids_); 147 } 148 149 } // namespace drive_backend 150 } // namespace sync_file_system 151