Home | History | Annotate | Download | only in drive_backend
      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