15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/engine/model_safe_worker.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_writer.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace syncer {
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::DictionaryValue* ModelSafeRoutingInfoToValue(
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ModelSafeRoutingInfo& routing_info) {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin();
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != routing_info.end(); ++it) {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dict->SetString(ModelTypeToString(it->first),
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    ModelSafeGroupToString(it->second));
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string ModelSafeRoutingInfoToString(
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ModelSafeRoutingInfo& routing_info) {
27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<base::DictionaryValue> dict(
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      ModelSafeRoutingInfoToValue(routing_info));
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string json;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::JSONWriter::Write(dict.get(), &json);
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return json;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ModelTypeSet GetRoutingInfoTypes(const ModelSafeRoutingInfo& routing_info) {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ModelTypeSet types;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin();
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != routing_info.end(); ++it) {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    types.Put(it->first);
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return types;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ModelSafeGroup GetGroupForModelType(const ModelType type,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    const ModelSafeRoutingInfo& routes) {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ModelSafeRoutingInfo::const_iterator it = routes.find(type);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it == routes.end()) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (type != UNSPECIFIED && type != TOP_LEVEL_FOLDER)
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      DVLOG(1) << "Entry does not belong to active ModelSafeGroup!";
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GROUP_PASSIVE;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return it->second;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string ModelSafeGroupToString(ModelSafeGroup group) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (group) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GROUP_UI:
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return "GROUP_UI";
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GROUP_DB:
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return "GROUP_DB";
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GROUP_FILE:
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return "GROUP_FILE";
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GROUP_HISTORY:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return "GROUP_HISTORY";
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GROUP_PASSIVE:
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return "GROUP_PASSIVE";
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case GROUP_PASSWORD:
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return "GROUP_PASSWORD";
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return "INVALID";
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)ModelSafeWorker::ModelSafeWorker(WorkerLoopDestructionObserver* observer)
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    : stopped_(false),
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      work_done_or_stopped_(false, false),
77a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      observer_(observer),
785b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      working_loop_(NULL) {
795b892326406927b709cdaf6c384d4ababf456332Ben Murdoch}
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ModelSafeWorker::~ModelSafeWorker() {}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ModelSafeWorker::RequestStop() {
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::AutoLock al(stopped_lock_);
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Set stop flag but don't signal work_done_or_stopped_ to unblock sync loop
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // because the worker may be working and depending on sync command object
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // living on sync thread. his prevents any *further* tasks from being posted
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // to worker threads (see DoWorkAndWaitUntilDone below), but note that one
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // may already be posted.
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  stopped_ = true;
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)SyncerError ModelSafeWorker::DoWorkAndWaitUntilDone(const WorkCallback& work) {
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  {
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::AutoLock al(stopped_lock_);
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (stopped_)
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return CANNOT_DO_WORK;
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CHECK(!work_done_or_stopped_.IsSignaled());
10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return DoWorkAndWaitUntilDoneImpl(work);
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool ModelSafeWorker::IsStopped() {
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::AutoLock al(stopped_lock_);
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return stopped_;
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ModelSafeWorker::WillDestroyCurrentMessageLoop() {
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  {
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::AutoLock al(stopped_lock_);
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    stopped_ = true;
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Must signal to unblock syncer if it's waiting for a posted task to
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // finish. At this point, all pending tasks posted to the loop have been
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // destroyed (see MessageLoop::~MessageLoop). So syncer will be blocked
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // indefinitely without signaling here.
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    work_done_or_stopped_.Signal();
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DVLOG(1) << ModelSafeGroupToString(GetModelSafeGroup())
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        << " worker stops on destruction of its working thread.";
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  {
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    base::AutoLock l(working_loop_lock_);
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    working_loop_ = NULL;
1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (observer_)
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    observer_->OnWorkerLoopDestroyed(GetModelSafeGroup());
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
135a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void ModelSafeWorker::SetWorkingLoopToCurrent() {
1365b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  base::Callback<void(ModelSafeGroup)> unregister_done_callback;
137a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  {
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    base::AutoLock l(working_loop_lock_);
1405b892326406927b709cdaf6c384d4ababf456332Ben Murdoch    DCHECK(!working_loop_);
1415b892326406927b709cdaf6c384d4ababf456332Ben Murdoch
1425b892326406927b709cdaf6c384d4ababf456332Ben Murdoch    if (unregister_done_callback_.is_null()) {
1435b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      // Expected case - UnregisterForLoopDestruction hasn't been called yet.
1445b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      base::MessageLoop::current()->AddDestructionObserver(this);
1455b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      working_loop_ = base::MessageLoop::current();
1465b892326406927b709cdaf6c384d4ababf456332Ben Murdoch    } else {
1475b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      // Rare case which is possible when the model type thread remains
1485b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      // blocked for the entire session and UnregisterForLoopDestruction ends
1495b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      // up being called before this method. This method is posted unlike
1505b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      // UnregisterForLoopDestruction - that's why they can end up being called
1515b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      // out of order.
1525b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      // In this case we skip the destruction observer registration
1535b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      // and just invoke the callback stored at UnregisterForLoopDestruction.
1545b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      DCHECK(stopped_);
1555b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      unregister_done_callback = unregister_done_callback_;
1565b892326406927b709cdaf6c384d4ababf456332Ben Murdoch      unregister_done_callback_.Reset();
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1595b892326406927b709cdaf6c384d4ababf456332Ben Murdoch
1605b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  if (!unregister_done_callback.is_null()) {
1615b892326406927b709cdaf6c384d4ababf456332Ben Murdoch    unregister_done_callback.Run(GetModelSafeGroup());
1625b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  }
1635b892326406927b709cdaf6c384d4ababf456332Ben Murdoch}
1645b892326406927b709cdaf6c384d4ababf456332Ben Murdoch
1655b892326406927b709cdaf6c384d4ababf456332Ben Murdochvoid ModelSafeWorker::UnregisterForLoopDestruction(
1665b892326406927b709cdaf6c384d4ababf456332Ben Murdoch    base::Callback<void(ModelSafeGroup)> unregister_done_callback) {
1675b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  base::AutoLock l(working_loop_lock_);
1685b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  if (working_loop_ != NULL) {
1695b892326406927b709cdaf6c384d4ababf456332Ben Murdoch    // Normal case - observer registration has been already done.
1705b892326406927b709cdaf6c384d4ababf456332Ben Murdoch    // Delegate to the sync thread to do the actual unregistration in
1715b892326406927b709cdaf6c384d4ababf456332Ben Murdoch    // UnregisterForLoopDestructionAsync.
1725b892326406927b709cdaf6c384d4ababf456332Ben Murdoch    DCHECK_NE(base::MessageLoop::current(), working_loop_);
1735b892326406927b709cdaf6c384d4ababf456332Ben Murdoch    working_loop_->PostTask(
1745b892326406927b709cdaf6c384d4ababf456332Ben Murdoch        FROM_HERE,
1755b892326406927b709cdaf6c384d4ababf456332Ben Murdoch        base::Bind(&ModelSafeWorker::UnregisterForLoopDestructionAsync,
1765b892326406927b709cdaf6c384d4ababf456332Ben Murdoch                   this,
1775b892326406927b709cdaf6c384d4ababf456332Ben Murdoch                   unregister_done_callback));
1785b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  } else {
1795b892326406927b709cdaf6c384d4ababf456332Ben Murdoch    // The working loop is still unknown, probably because the model type
1805b892326406927b709cdaf6c384d4ababf456332Ben Murdoch    // thread is blocked. Store the callback to be called from
1815b892326406927b709cdaf6c384d4ababf456332Ben Murdoch    // SetWorkingLoopToCurrent.
1825b892326406927b709cdaf6c384d4ababf456332Ben Murdoch    unregister_done_callback_ = unregister_done_callback;
1835b892326406927b709cdaf6c384d4ababf456332Ben Murdoch  }
184a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
185a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
186a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void ModelSafeWorker::UnregisterForLoopDestructionAsync(
187a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    base::Callback<void(ModelSafeGroup)> unregister_done_callback) {
1883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  {
1893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    base::AutoLock l(working_loop_lock_);
1903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!working_loop_)
1913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return;
1923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK_EQ(base::MessageLoop::current(), working_loop_);
1933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
195a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK(stopped_);
196a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::MessageLoop::current()->RemoveDestructionObserver(this);
197a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  unregister_done_callback.Run(GetModelSafeGroup());
198a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
199a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace syncer
201