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