146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Copyright 2014 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)
546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "components/sync_driver/shared_change_processor.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
80529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "components/sync_driver/generic_change_processor.h"
9010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "components/sync_driver/generic_change_processor_factory.h"
10010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "components/sync_driver/sync_api_component_factory.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/api/sync_change.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::AutoLock;
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace browser_sync {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SharedChangeProcessor::SharedChangeProcessor()
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : disconnected_(false),
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      type_(syncer::UNSPECIFIED),
20010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      frontend_loop_(base::MessageLoopProxy::current()),
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      generic_change_processor_(NULL),
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_handler_(NULL) {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SharedChangeProcessor::~SharedChangeProcessor() {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We can either be deleted when the DTC is destroyed (on UI
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // thread), or when the syncer::SyncableService stop's syncing (datatype
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // thread).  |generic_change_processor_|, if non-NULL, must be
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // deleted on |backend_loop_|.
30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (frontend_loop_->BelongsToCurrentThread()) {
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (backend_loop_.get()) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!backend_loop_->DeleteSoon(FROM_HERE, generic_change_processor_)) {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(!generic_change_processor_);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(backend_loop_.get());
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(backend_loop_->BelongsToCurrentThread());
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete generic_change_processor_;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::WeakPtr<syncer::SyncableService> SharedChangeProcessor::Connect(
46010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    browser_sync::SyncApiComponentFactory* sync_factory,
47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    GenericChangeProcessorFactory* processor_factory,
48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    syncer::UserShare* user_share,
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DataTypeErrorHandler* error_handler,
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    syncer::ModelType type,
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::WeakPtr<syncer::SyncMergeResult>& merge_result) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(sync_factory);
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(error_handler);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(type, syncer::UNSPECIFIED);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  backend_loop_ = base::MessageLoopProxy::current();
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AutoLock lock(monitor_lock_);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (disconnected_)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return base::WeakPtr<syncer::SyncableService>();
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  type_ = type;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  error_handler_ = error_handler;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::WeakPtr<syncer::SyncableService> local_service =
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sync_factory->GetSyncableServiceForType(type);
63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!local_service.get()) {
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    LOG(WARNING) << "SyncableService destroyed before DTC was stopped.";
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    disconnected_ = true;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return base::WeakPtr<syncer::SyncableService>();
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  generic_change_processor_ =
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      processor_factory->CreateGenericChangeProcessor(user_share,
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                      error_handler,
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                      local_service,
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                      merge_result,
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                      sync_factory).release();
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return local_service;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SharedChangeProcessor::Disconnect() {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // May be called from any thread.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Disconnecting change processor.";
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AutoLock lock(monitor_lock_);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool was_connected = !disconnected_;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  disconnected_ = true;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  error_handler_ = NULL;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return was_connected;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
88010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)ChangeProcessor* SharedChangeProcessor::generic_change_processor() {
89010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return generic_change_processor_;
90010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int SharedChangeProcessor::GetSyncCount() {
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(backend_loop_.get());
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(backend_loop_->BelongsToCurrentThread());
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AutoLock lock(monitor_lock_);
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (disconnected_) {
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Change processor disconnected.";
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return generic_change_processor_->GetSyncCountForType(type_);
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)syncer::SyncError SharedChangeProcessor::ProcessSyncChanges(
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const tracked_objects::Location& from_here,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const syncer::SyncChangeList& list_of_changes) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(backend_loop_.get());
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(backend_loop_->BelongsToCurrentThread());
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AutoLock lock(monitor_lock_);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (disconnected_) {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The DTC that disconnects us must ensure it posts a StopSyncing task.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we reach this, it means it just hasn't executed yet.
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    syncer::SyncError error(FROM_HERE,
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            syncer::SyncError::DATATYPE_ERROR,
114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            "Change processor disconnected.",
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                            type_);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return error;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return generic_change_processor_->ProcessSyncChanges(
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      from_here, list_of_changes);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)syncer::SyncDataList SharedChangeProcessor::GetAllSyncData(
12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    syncer::ModelType type) const {
12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  syncer::SyncDataList data;
12558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  GetAllSyncDataReturnError(type, &data);  // Handles the disconnect case.
12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return data;
12758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
12858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
12958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)syncer::SyncError SharedChangeProcessor::GetAllSyncDataReturnError(
13058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    syncer::ModelType type,
13158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    syncer::SyncDataList* data) const {
13258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(backend_loop_.get());
13358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK(backend_loop_->BelongsToCurrentThread());
13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  AutoLock lock(monitor_lock_);
13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (disconnected_) {
13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    syncer::SyncError error(FROM_HERE,
13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            syncer::SyncError::DATATYPE_ERROR,
13858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            "Change processor disconnected.",
13958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            type_);
14058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return error;
14158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
14258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return generic_change_processor_->GetAllSyncDataReturnError(type, data);
14358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
14458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
145c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochsyncer::SyncError SharedChangeProcessor::UpdateDataTypeContext(
146c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    syncer::ModelType type,
147c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status,
148c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& context) {
149c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK(backend_loop_.get());
150c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK(backend_loop_->BelongsToCurrentThread());
151c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AutoLock lock(monitor_lock_);
152c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (disconnected_) {
153c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    syncer::SyncError error(FROM_HERE,
154c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                            syncer::SyncError::DATATYPE_ERROR,
155c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                            "Change processor disconnected.",
156c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                            type_);
157c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return error;
158c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
159c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return generic_change_processor_->UpdateDataTypeContext(
160c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      type, refresh_status, context);
161c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
162c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SharedChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(backend_loop_.get());
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(backend_loop_->BelongsToCurrentThread());
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AutoLock lock(monitor_lock_);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (disconnected_) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Change processor disconnected.";
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return generic_change_processor_->SyncModelHasUserCreatedNodes(
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      type_, has_nodes);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SharedChangeProcessor::CryptoReadyIfNecessary() {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(backend_loop_.get());
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(backend_loop_->BelongsToCurrentThread());
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AutoLock lock(monitor_lock_);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (disconnected_) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Change processor disconnected.";
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;  // Otherwise we get into infinite spin waiting.
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return generic_change_processor_->CryptoReadyIfNecessary(type_);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
186a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochbool SharedChangeProcessor::GetDataTypeContext(std::string* context) const {
187a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(backend_loop_.get());
188a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(backend_loop_->BelongsToCurrentThread());
189a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  AutoLock lock(monitor_lock_);
190a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (disconnected_) {
191a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    LOG(ERROR) << "Change processor disconnected.";
192a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    return false;
193a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
194a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return generic_change_processor_->GetDataTypeContext(type_, context);
195a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
196a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)syncer::SyncError SharedChangeProcessor::CreateAndUploadError(
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const tracked_objects::Location& location,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& message) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AutoLock lock(monitor_lock_);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!disconnected_) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return error_handler_->CreateAndUploadError(location, message, type_);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return syncer::SyncError(location,
205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                             syncer::SyncError::DATATYPE_ERROR,
206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                             message,
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                             type_);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace browser_sync
212