directory.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2013 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/syncable/directory.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
77d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <iterator>
87d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/base64.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/trace_event.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "sync/internal_api/public/base/unique_position.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/util/unrecoverable_error_handler.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/entry.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/entry_kernel.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/in_memory_directory_backing_store.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/on_disk_directory_backing_store.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "sync/syncable/scoped_kernel_lock.h"
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "sync/syncable/scoped_parent_child_index_updater.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/syncable-inl.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/syncable/syncable_base_transaction.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/syncable_changes_version.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/syncable/syncable_read_transaction.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/syncable_util.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/syncable/syncable_write_transaction.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::string;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace syncer {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace syncable {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::CharType Directory::kSyncDatabaseFilename[] =
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FILE_PATH_LITERAL("SyncData.sqlite3");
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Directory::PersistedKernelInfo::PersistedKernelInfo()
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : next_id(0) {
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ModelTypeSet protocol_types = ProtocolTypes();
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good();
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       iter.Inc()) {
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    reset_download_progress(iter.Get());
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    transaction_version[iter.Get()] = 0;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Directory::PersistedKernelInfo::~PersistedKernelInfo() {}
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::PersistedKernelInfo::reset_download_progress(
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelType model_type) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_progress[model_type].set_data_type_id(
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetSpecificsFieldNumberFromModelType(model_type));
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // An empty-string token indicates no prior knowledge.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_progress[model_type].set_token(std::string());
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Directory::SaveChangesSnapshot::SaveChangesSnapshot()
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : kernel_info_status(KERNEL_SHARE_INFO_INVALID) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Directory::SaveChangesSnapshot::~SaveChangesSnapshot() {
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STLDeleteElements(&dirty_metas);
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STLDeleteElements(&delete_journals);
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Directory::Kernel::Kernel(
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& name,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const KernelLoadInfo& info, DirectoryChangeDelegate* delegate,
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WeakHandle<TransactionObserver>& transaction_observer)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : next_write_transaction_id(0),
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name(name),
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info_status(Directory::KERNEL_SHARE_INFO_VALID),
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      persisted_info(info.kernel_info),
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cache_guid(info.cache_guid),
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_metahandle(info.max_metahandle + 1),
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate(delegate),
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      transaction_observer(transaction_observer) {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(delegate);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(transaction_observer.IsInitialized());
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Directory::Kernel::~Kernel() {
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  STLDeleteContainerPairSecondPointers(metahandles_map.begin(),
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                       metahandles_map.end());
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Directory::Directory(
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DirectoryBackingStore* store,
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UnrecoverableErrorHandler* unrecoverable_error_handler,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReportUnrecoverableErrorFunction report_unrecoverable_error_function,
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NigoriHandler* nigori_handler,
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Cryptographer* cryptographer)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : kernel_(NULL),
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      store_(store),
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unrecoverable_error_handler_(unrecoverable_error_handler),
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      report_unrecoverable_error_function_(
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          report_unrecoverable_error_function),
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unrecoverable_error_set_(false),
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      nigori_handler_(nigori_handler),
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cryptographer_(cryptographer),
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      invariant_check_level_(VERIFY_CHANGES) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Directory::~Directory() {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Close();
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirOpenResult Directory::Open(
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const string& name,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DirectoryChangeDelegate* delegate,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WeakHandle<TransactionObserver>& transaction_observer) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACE_EVENT0("sync", "SyncDatabaseOpen");
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const DirOpenResult result =
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OpenImpl(name, delegate, transaction_observer);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (OPENED != result)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Close();
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Directory::InitializeIndices(MetahandlesMap* handles_map) {
123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  kernel_->metahandles_map.swap(*handles_map);
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (MetahandlesMap::const_iterator it = kernel_->metahandles_map.begin();
125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       it != kernel_->metahandles_map.end(); ++it) {
126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EntryKernel* entry = it->second;
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (ParentChildIndex::ShouldInclude(entry))
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->parent_child_index.Insert(entry);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int64 metahandle = entry->ref(META_HANDLE);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (entry->ref(IS_UNSYNCED))
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->unsynced_metahandles.insert(metahandle);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (entry->ref(IS_UNAPPLIED_UPDATE)) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const ModelType type = entry->GetServerModelType();
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kernel_->unapplied_update_metahandles[type].insert(metahandle);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!entry->ref(UNIQUE_SERVER_TAG).empty()) {
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      DCHECK(kernel_->server_tags_map.find(entry->ref(UNIQUE_SERVER_TAG)) ==
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)             kernel_->server_tags_map.end())
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          << "Unexpected duplicate use of client tag";
140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->server_tags_map[entry->ref(UNIQUE_SERVER_TAG)] = entry;
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!entry->ref(UNIQUE_CLIENT_TAG).empty()) {
143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      DCHECK(kernel_->server_tags_map.find(entry->ref(UNIQUE_SERVER_TAG)) ==
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)             kernel_->server_tags_map.end())
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          << "Unexpected duplicate use of server tag";
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->client_tags_map[entry->ref(UNIQUE_CLIENT_TAG)] = entry;
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK(kernel_->ids_map.find(entry->ref(ID).value()) ==
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)           kernel_->ids_map.end()) << "Unexpected duplicate use of ID";
150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    kernel_->ids_map[entry->ref(ID).value()] = entry;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!entry->is_dirty());
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirOpenResult Directory::OpenImpl(
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const string& name,
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DirectoryChangeDelegate* delegate,
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WeakHandle<TransactionObserver>&
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        transaction_observer) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  KernelLoadInfo info;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Temporary indices before kernel_ initialized in case Load fails. We 0(1)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // swap these later.
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Directory::MetahandlesMap tmp_handles_map;
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  JournalIndex delete_journals;
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DirOpenResult result =
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      store_->Load(&tmp_handles_map, &delete_journals, &info);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (OPENED != result)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_ = new Kernel(name, info, delegate, transaction_observer);
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete_journal_.reset(new DeleteJournal(&delete_journals));
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  InitializeIndices(&tmp_handles_map);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Write back the share info to reserve some space in 'next_id'.  This will
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // prevent local ID reuse in the case of an early crash.  See the comments in
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TakeSnapshotForSaveChanges() or crbug.com/142987 for more information.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SaveChanges())
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FAILED_INITIAL_WRITE;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return OPENED;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DeleteJournal* Directory::delete_journal() {
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(delete_journal_.get());
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return delete_journal_.get();
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::Close() {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  store_.reset();
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kernel_) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete kernel_;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kernel_ = NULL;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::OnUnrecoverableError(const BaseTransaction* trans,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const tracked_objects::Location& location,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const std::string & message) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(trans != NULL);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unrecoverable_error_set_ = true;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unrecoverable_error_handler_->OnUnrecoverableError(location,
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     message);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EntryKernel* Directory::GetEntryById(const Id& id) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetEntryById(id, &lock);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EntryKernel* Directory::GetEntryById(const Id& id,
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     ScopedKernelLock* const lock) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(kernel_);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find it in the in memory ID index.
216868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  IdsMap::iterator id_found = kernel_->ids_map.find(id.value());
217868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (id_found != kernel_->ids_map.end()) {
218868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return id_found->second;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EntryKernel* Directory::GetEntryByClientTag(const string& tag) {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(kernel_);
226868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
227868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  TagsMap::iterator it = kernel_->client_tags_map.find(tag);
228868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (it != kernel_->client_tags_map.end()) {
229868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return it->second;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EntryKernel* Directory::GetEntryByServerTag(const string& tag) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(kernel_);
237868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  TagsMap::iterator it = kernel_->server_tags_map.find(tag);
238868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (it != kernel_->server_tags_map.end()) {
239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return it->second;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EntryKernel* Directory::GetEntryByHandle(int64 metahandle) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetEntryByHandle(metahandle, &lock);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EntryKernel* Directory::GetEntryByHandle(int64 metahandle,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         ScopedKernelLock* lock) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Look up in memory
252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  MetahandlesMap::iterator found =
253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->metahandles_map.find(metahandle);
254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (found != kernel_->metahandles_map.end()) {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Found it in memory.  Easy.
256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return found->second;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::GetChildHandlesById(
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BaseTransaction* trans, const Id& parent_id,
263868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    Directory::Metahandles* result) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SyncAssert(this == trans->directory(), FROM_HERE,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  "Directories don't match", trans))
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->clear();
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AppendChildHandles(lock, parent_id, result);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
274868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)int Directory::GetTotalNodeCount(
275868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    BaseTransaction* trans,
276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EntryKernel* kernel) const {
277868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!SyncAssert(this == trans->directory(), FROM_HERE,
278868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  "Directories don't match", trans))
279868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return false;
280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
281868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int count = 1;
282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::deque<const OrderedChildSet*> child_sets;
283868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  GetChildSetForKernel(trans, kernel, &child_sets);
285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  while (!child_sets.empty()) {
286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const OrderedChildSet* set = child_sets.front();
287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    child_sets.pop_front();
288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for (OrderedChildSet::const_iterator it = set->begin();
289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)         it != set->end(); ++it) {
290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      count++;
291868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      GetChildSetForKernel(trans, *it, &child_sets);
292868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
293868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return count;
296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
297868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
298868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Directory::GetChildSetForKernel(
299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    BaseTransaction* trans,
300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EntryKernel* kernel,
301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    std::deque<const OrderedChildSet*>* child_sets) const {
302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!kernel->ref(IS_DIR))
303868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;  // Not a directory => no children.
304868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
305868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const OrderedChildSet* descendants =
306868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->parent_child_index.GetChildren(kernel->ref(ID));
307868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!descendants)
308868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;  // This directory has no children.
309868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
310868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Add our children to the list of items to be traversed.
311868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  child_sets->push_back(descendants);
312868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
313868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)int Directory::GetPositionIndex(
3157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    BaseTransaction* trans,
3167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    EntryKernel* kernel) const {
3177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const OrderedChildSet* siblings =
3187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      kernel_->parent_child_index.GetChildren(kernel->ref(PARENT_ID));
3197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  OrderedChildSet::const_iterator it = siblings->find(kernel);
3217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return std::distance(siblings->begin(), it);
3227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
3237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EntryKernel* Directory::GetRootEntry() {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetEntryById(Id());
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool Directory::InsertEntry(BaseWriteTransaction* trans, EntryKernel* entry) {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return InsertEntry(trans, entry, &lock);
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool Directory::InsertEntry(BaseWriteTransaction* trans,
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            EntryKernel* entry,
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            ScopedKernelLock* lock) {
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(NULL != lock);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SyncAssert(NULL != entry, FROM_HERE, "Entry is null", trans))
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char error[] = "Entry already in memory index.";
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
342868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!SyncAssert(
343868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          kernel_->metahandles_map.insert(
344868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              std::make_pair(entry->ref(META_HANDLE), entry)).second,
345868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          FROM_HERE,
346868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          error,
347868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          trans)) {
348868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return false;
349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
350868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!SyncAssert(
351868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          kernel_->ids_map.insert(
352868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              std::make_pair(entry->ref(ID).value(), entry)).second,
353868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          FROM_HERE,
354868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          error,
355868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          trans)) {
356868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return false;
357868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (ParentChildIndex::ShouldInclude(entry)) {
359868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!SyncAssert(kernel_->parent_child_index.Insert(entry),
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    FROM_HERE,
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    error,
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    trans)) {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
367868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Should NEVER be created with a client tag or server tag.
368868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!SyncAssert(entry->ref(UNIQUE_SERVER_TAG).empty(), FROM_HERE,
369868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  "Server tag should be empty", trans)) {
370868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return false;
371868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SyncAssert(entry->ref(UNIQUE_CLIENT_TAG).empty(), FROM_HERE,
373868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  "Client tag should be empty", trans))
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool Directory::ReindexId(BaseWriteTransaction* trans,
3804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                          EntryKernel* const entry,
3814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                          const Id& new_id) {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NULL != GetEntryById(new_id, &lock))
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the indices that depend on the ID field.
388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ScopedParentChildIndexUpdater updater_b(lock, entry,
389868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        &kernel_->parent_child_index);
390868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    size_t num_erased = kernel_->ids_map.erase(entry->ref(ID).value());
391868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK_EQ(1U, num_erased);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entry->put(ID, new_id);
393868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    kernel_->ids_map[entry->ref(ID).value()] = entry;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool Directory::ReindexParentId(BaseWriteTransaction* trans,
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                EntryKernel* const entry,
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const Id& new_parent_id) {
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the indices that depend on the PARENT_ID field.
405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ScopedParentChildIndexUpdater index_updater(lock, entry,
406868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        &kernel_->parent_child_index);
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entry->put(PARENT_ID, new_parent_id);
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::unrecoverable_error_set(const BaseTransaction* trans) const {
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(trans != NULL);
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return unrecoverable_error_set_;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::ClearDirtyMetahandles() {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->transaction_mutex.AssertAcquired();
419868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  kernel_->dirty_metahandles.clear();
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::SafeToPurgeFromMemory(WriteTransaction* trans,
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const EntryKernel* const entry) const {
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool safe = entry->ref(IS_DEL) && !entry->is_dirty() &&
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !entry->ref(SYNCING) && !entry->ref(IS_UNAPPLIED_UPDATE) &&
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !entry->ref(IS_UNSYNCED);
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (safe) {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 handle = entry->ref(META_HANDLE);
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ModelType type = entry->GetServerModelType();
431868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!SyncAssert(kernel_->dirty_metahandles.count(handle) == 0U,
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    FROM_HERE,
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "Dirty metahandles should be empty", trans))
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(tim): Bug 49278.
436868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!SyncAssert(!kernel_->unsynced_metahandles.count(handle),
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    FROM_HERE,
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "Unsynced handles should be empty",
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    trans))
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!SyncAssert(!kernel_->unapplied_update_metahandles[type].count(handle),
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    FROM_HERE,
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "Unapplied metahandles should be empty",
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    trans))
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return safe;
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::TakeSnapshotForSaveChanges(SaveChangesSnapshot* snapshot) {
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReadTransaction trans(FROM_HERE, this);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there is an unrecoverable error then just bail out.
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (unrecoverable_error_set(&trans))
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Deep copy dirty entries from kernel_->metahandles_index into snapshot and
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // clear dirty flags.
461868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (MetahandleSet::const_iterator i = kernel_->dirty_metahandles.begin();
462868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       i != kernel_->dirty_metahandles.end(); ++i) {
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EntryKernel* entry = GetEntryByHandle(*i, &lock);
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!entry)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Skip over false positives; it happens relatively infrequently.
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!entry->is_dirty())
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    snapshot->dirty_metas.insert(snapshot->dirty_metas.end(),
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 new EntryKernel(*entry));
471868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK_EQ(1U, kernel_->dirty_metahandles.count(*i));
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't bother removing from the index here as we blow the entire thing
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // in a moment, and it unnecessarily complicates iteration.
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entry->clear_dirty(NULL);
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClearDirtyMetahandles();
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set purged handles.
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(snapshot->metahandles_to_purge.empty());
480868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  snapshot->metahandles_to_purge.swap(kernel_->metahandles_to_purge);
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fill kernel_info_status and kernel_info.
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  snapshot->kernel_info = kernel_->persisted_info;
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // To avoid duplicates when the process crashes, we record the next_id to be
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // greater magnitude than could possibly be reached before the next save
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // changes.  In other words, it's effectively impossible for the user to
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // generate 65536 new bookmarks in 3 seconds.
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  snapshot->kernel_info.next_id -= 65536;
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  snapshot->kernel_info_status = kernel_->info_status;
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This one we reset on failure.
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->info_status = KERNEL_SHARE_INFO_VALID;
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete_journal_->TakeSnapshotAndClear(
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &trans, &snapshot->delete_journals, &snapshot->delete_journals_to_purge);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::SaveChanges() {
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = false;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock scoped_lock(kernel_->save_changes_mutex);
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Snapshot and save.
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveChangesSnapshot snapshot;
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TakeSnapshotForSaveChanges(&snapshot);
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  success = store_->SaveChanges(snapshot);
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Handle success or failure.
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (success)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    success = VacuumAfterSaveChanges(snapshot);
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleSaveChangesFailure(snapshot);
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return success;
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::VacuumAfterSaveChanges(const SaveChangesSnapshot& snapshot) {
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (snapshot.dirty_metas.empty())
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Need a write transaction as we are about to permanently purge entries.
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WriteTransaction trans(FROM_HERE, VACUUM_AFTER_SAVE, this);
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now drop everything we can out of memory.
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (EntryKernelSet::const_iterator i = snapshot.dirty_metas.begin();
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != snapshot.dirty_metas.end(); ++i) {
525868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    MetahandlesMap::iterator found =
526868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        kernel_->metahandles_map.find((*i)->ref(META_HANDLE));
527868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EntryKernel* entry = (found == kernel_->metahandles_map.end() ?
528868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                          NULL : found->second);
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (entry && SafeToPurgeFromMemory(&trans, entry)) {
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We now drop deleted metahandles that are up to date on both the client
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // and the server.
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_t num_erased = 0;
533868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      num_erased = kernel_->metahandles_map.erase(entry->ref(META_HANDLE));
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_EQ(1u, num_erased);
535868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      num_erased = kernel_->ids_map.erase(entry->ref(ID).value());
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_EQ(1u, num_erased);
537868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (!entry->ref(UNIQUE_SERVER_TAG).empty()) {
538868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        num_erased =
539868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            kernel_->server_tags_map.erase(entry->ref(UNIQUE_SERVER_TAG));
540868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        DCHECK_EQ(1u, num_erased);
541868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
542868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (!entry->ref(UNIQUE_CLIENT_TAG).empty()) {
543868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        num_erased =
544868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            kernel_->client_tags_map.erase(entry->ref(UNIQUE_CLIENT_TAG));
545868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        DCHECK_EQ(1u, num_erased);
546868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
547868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (!SyncAssert(!kernel_->parent_child_index.Contains(entry),
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      FROM_HERE,
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "Deleted entry still present",
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      (&trans)))
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete entry;
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (trans.unrecoverable_error_set())
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
560868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Directory::UnapplyEntry(EntryKernel* entry) {
561868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int64 handle = entry->ref(META_HANDLE);
562868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ModelType server_type = GetModelTypeFromSpecifics(
563868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      entry->ref(SERVER_SPECIFICS));
564868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
565868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Clear enough so that on the next sync cycle all local data will
566868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // be overwritten.
567868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Note: do not modify the root node in order to preserve the
568868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // initial sync ended bit for this type (else on the next restart
569868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // this type will be treated as disabled and therefore fully purged).
570868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (IsRealDataType(server_type) &&
571868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      ModelTypeToRootTag(server_type) == entry->ref(UNIQUE_SERVER_TAG)) {
572868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
573868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
574868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
575868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Set the unapplied bit if this item has server data.
576868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (IsRealDataType(server_type) && !entry->ref(IS_UNAPPLIED_UPDATE)) {
577868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry->put(IS_UNAPPLIED_UPDATE, true);
578868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    kernel_->unapplied_update_metahandles[server_type].insert(handle);
579868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry->mark_dirty(&kernel_->dirty_metahandles);
580868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
581868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
582868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Unset the unsynced bit.
583868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (entry->ref(IS_UNSYNCED)) {
584868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    kernel_->unsynced_metahandles.erase(handle);
585868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry->put(IS_UNSYNCED, false);
586868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry->mark_dirty(&kernel_->dirty_metahandles);
587868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
588868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
589868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Mark the item as locally deleted. No deleted items are allowed in the
590868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // parent child index.
591868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!entry->ref(IS_DEL)) {
592868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    kernel_->parent_child_index.Remove(entry);
593868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry->put(IS_DEL, true);
594868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry->mark_dirty(&kernel_->dirty_metahandles);
595868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
596868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
597868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Set the version to the "newly created" version.
598868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (entry->ref(BASE_VERSION) != CHANGES_VERSION) {
599868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry->put(BASE_VERSION, CHANGES_VERSION);
600868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry->mark_dirty(&kernel_->dirty_metahandles);
601868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
602868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
603868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // At this point locally created items that aren't synced will become locally
604868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // deleted items, and purged on the next snapshot. All other items will match
605868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // the state they would have had if they were just created via a server
606868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // update. See MutableEntry::MutableEntry(.., CreateNewUpdateItem, ..).
607868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
608868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
609868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Directory::DeleteEntry(bool save_to_journal,
610868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                            EntryKernel* entry,
611868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                            EntryKernelSet* entries_to_journal) {
612868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int64 handle = entry->ref(META_HANDLE);
613868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ModelType server_type = GetModelTypeFromSpecifics(
614868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      entry->ref(SERVER_SPECIFICS));
615868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
616868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  kernel_->metahandles_to_purge.insert(handle);
617868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
618868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  size_t num_erased = 0;
619868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  num_erased = kernel_->metahandles_map.erase(entry->ref(META_HANDLE));
620868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK_EQ(1u, num_erased);
621868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  num_erased = kernel_->ids_map.erase(entry->ref(ID).value());
622868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK_EQ(1u, num_erased);
623868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  num_erased = kernel_->unsynced_metahandles.erase(handle);
624868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK_EQ(entry->ref(IS_UNSYNCED), num_erased > 0);
625868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  num_erased =
626868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->unapplied_update_metahandles[server_type].erase(handle);
627868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK_EQ(entry->ref(IS_UNAPPLIED_UPDATE), num_erased > 0);
628868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (kernel_->parent_child_index.Contains(entry))
629868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    kernel_->parent_child_index.Remove(entry);
630868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
631868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!entry->ref(UNIQUE_CLIENT_TAG).empty()) {
632868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    num_erased =
633868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        kernel_->client_tags_map.erase(entry->ref(UNIQUE_CLIENT_TAG));
634868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK_EQ(1u, num_erased);
635868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
636868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!entry->ref(UNIQUE_SERVER_TAG).empty()) {
637868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    num_erased =
638868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        kernel_->server_tags_map.erase(entry->ref(UNIQUE_SERVER_TAG));
639868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK_EQ(1u, num_erased);
640868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
642868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (save_to_journal) {
643868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entries_to_journal->insert(entry);
644868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else {
645868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    delete entry;
646868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
647868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
648868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
649868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool Directory::PurgeEntriesWithTypeIn(ModelTypeSet disabled_types,
650868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                       ModelTypeSet types_to_journal,
651868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                       ModelTypeSet types_to_unapply) {
652868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  disabled_types.RemoveAll(ProxyTypes());
653868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
654868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (disabled_types.Empty())
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WriteTransaction trans(FROM_HERE, PURGE_ENTRIES, this);
6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EntryKernelSet entries_to_journal;
6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    STLElementDeleter<EntryKernelSet> journal_deleter(&entries_to_journal);
6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ScopedKernelLock lock(this);
665868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
666868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // We iterate in two passes to avoid a bug in STLport (which is used in
667868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // the Android build).  There are some versions of that library where a
668868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // hash_map's iterators can be invalidated when an item is erased from the
669868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // hash_map.
670868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // See http://sourceforge.net/p/stlport/bugs/239/.
671868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
672868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      std::set<EntryKernel*> to_purge;
673868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (MetahandlesMap::iterator it = kernel_->metahandles_map.begin();
674868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)           it != kernel_->metahandles_map.end(); ++it) {
675868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        const sync_pb::EntitySpecifics& local_specifics =
676868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            it->second->ref(SPECIFICS);
677868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        const sync_pb::EntitySpecifics& server_specifics =
678868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            it->second->ref(SERVER_SPECIFICS);
679868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        ModelType local_type = GetModelTypeFromSpecifics(local_specifics);
680868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        ModelType server_type = GetModelTypeFromSpecifics(server_specifics);
681868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
682868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        if ((IsRealDataType(local_type) && disabled_types.Has(local_type)) ||
683868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            (IsRealDataType(server_type) && disabled_types.Has(server_type))) {
684868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          to_purge.insert(it->second);
685868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        }
686868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
687868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
688868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (std::set<EntryKernel*>::iterator it = to_purge.begin();
689868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)           it != to_purge.end(); ++it) {
690868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        EntryKernel* entry = *it;
691868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
692868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        const sync_pb::EntitySpecifics& local_specifics =
693868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            (*it)->ref(SPECIFICS);
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const sync_pb::EntitySpecifics& server_specifics =
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            (*it)->ref(SERVER_SPECIFICS);
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ModelType local_type = GetModelTypeFromSpecifics(local_specifics);
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ModelType server_type = GetModelTypeFromSpecifics(server_specifics);
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
699868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        if (types_to_unapply.Has(local_type) ||
700868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            types_to_unapply.Has(server_type)) {
701868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          UnapplyEntry(entry);
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
703868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          bool save_to_journal =
704868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              (types_to_journal.Has(local_type) ||
705868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)               types_to_journal.Has(server_type)) &&
706868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              (delete_journal_->IsDeleteJournalEnabled(local_type) ||
707868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)               delete_journal_->IsDeleteJournalEnabled(server_type));
708868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          DeleteEntry(save_to_journal, entry, &entries_to_journal);
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      delete_journal_->AddJournalBatch(&trans, entries_to_journal);
7132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
714868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // Ensure meta tracking for these data types reflects the purged state.
715868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (ModelTypeSet::Iterator it = disabled_types.First();
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           it.Good(); it.Inc()) {
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kernel_->persisted_info.transaction_version[it.Get()] = 0;
718868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
719868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        // Don't discard progress markers for unapplied types.
720868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        if (!types_to_unapply.Has(it.Get()))
721868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          kernel_->persisted_info.reset_download_progress(it.Get());
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::HandleSaveChangesFailure(const SaveChangesSnapshot& snapshot) {
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WriteTransaction trans(FROM_HERE, HANDLE_SAVE_FAILURE, this);
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Because we optimistically cleared the dirty bit on the real entries when
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // taking the snapshot, we must restore it on failure.  Not doing this could
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cause lost data, if no other changes are made to the in-memory entries
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that would cause the dirty bit to get set again. Setting the bit ensures
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that SaveChanges will at least try again later.
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (EntryKernelSet::const_iterator i = snapshot.dirty_metas.begin();
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != snapshot.dirty_metas.end(); ++i) {
740868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    MetahandlesMap::iterator found =
741868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        kernel_->metahandles_map.find((*i)->ref(META_HANDLE));
742868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (found != kernel_->metahandles_map.end()) {
743868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      found->second->mark_dirty(&kernel_->dirty_metahandles);
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
747868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  kernel_->metahandles_to_purge.insert(snapshot.metahandles_to_purge.begin(),
748868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                       snapshot.metahandles_to_purge.end());
7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Restore delete journals.
7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete_journal_->AddJournalBatch(&trans, snapshot.delete_journals);
7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete_journal_->PurgeDeleteJournals(&trans,
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       snapshot.delete_journals_to_purge);
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::GetDownloadProgress(
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelType model_type,
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_pb::DataTypeProgressMarker* value_out) const {
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return value_out->CopyFrom(
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kernel_->persisted_info.download_progress[model_type]);
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::GetDownloadProgressAsString(
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelType model_type,
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string* value_out) const {
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->persisted_info.download_progress[model_type].SerializeToString(
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      value_out);
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t Directory::GetEntriesCount() const {
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
774868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return kernel_->metahandles_map.size();
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::SetDownloadProgress(
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelType model_type,
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const sync_pb::DataTypeProgressMarker& new_progress) {
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->persisted_info.download_progress[model_type].CopyFrom(new_progress);
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 Directory::GetTransactionVersion(ModelType type) const {
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->transaction_mutex.AssertAcquired();
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kernel_->persisted_info.transaction_version[type];
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::IncrementTransactionVersion(ModelType type) {
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->transaction_mutex.AssertAcquired();
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->persisted_info.transaction_version[type]++;
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ModelTypeSet Directory::InitialSyncEndedTypes() {
7962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncable::ReadTransaction trans(FROM_HERE, this);
7972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ModelTypeSet protocol_types = ProtocolTypes();
7982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ModelTypeSet initial_sync_ended_types;
7992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (ModelTypeSet::Iterator i = protocol_types.First(); i.Good(); i.Inc()) {
8002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (InitialSyncEndedForType(&trans, i.Get())) {
8012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      initial_sync_ended_types.Put(i.Get());
8022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
8032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return initial_sync_ended_types;
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Directory::InitialSyncEndedForType(ModelType type) {
8082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncable::ReadTransaction trans(FROM_HERE, this);
8092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return InitialSyncEndedForType(&trans, type);
8102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Directory::InitialSyncEndedForType(
8132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BaseTransaction* trans, ModelType type) {
8142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // True iff the type's root node has been received and applied.
8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncable::Entry entry(trans,
8162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        syncable::GET_BY_SERVER_TAG,
8172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        ModelTypeToRootTag(type));
818d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return entry.good() && entry.GetBaseVersion() != CHANGES_VERSION;
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string Directory::store_birthday() const {
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kernel_->persisted_info.store_birthday;
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::set_store_birthday(const string& store_birthday) {
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kernel_->persisted_info.store_birthday == store_birthday)
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->persisted_info.store_birthday = store_birthday;
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string Directory::bag_of_chips() const {
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kernel_->persisted_info.bag_of_chips;
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::set_bag_of_chips(const string& bag_of_chips) {
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kernel_->persisted_info.bag_of_chips == bag_of_chips)
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->persisted_info.bag_of_chips = bag_of_chips;
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string Directory::cache_guid() const {
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No need to lock since nothing ever writes to it after load.
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kernel_->cache_guid;
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NigoriHandler* Directory::GetNigoriHandler() {
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return nigori_handler_;
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Cryptographer* Directory::GetCryptographer(const BaseTransaction* trans) {
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(this, trans->directory());
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return cryptographer_;
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::GetAllMetaHandles(BaseTransaction* trans,
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  MetahandleSet* result) {
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->clear();
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
866868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (MetahandlesMap::iterator i = kernel_->metahandles_map.begin();
867868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       i != kernel_->metahandles_map.end(); ++i) {
868868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    result->insert(i->first);
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::GetUnsyncedMetaHandles(BaseTransaction* trans,
873868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                       Metahandles* result) {
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->clear();
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
876868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  copy(kernel_->unsynced_metahandles.begin(),
877868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       kernel_->unsynced_metahandles.end(), back_inserter(*result));
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 Directory::unsynced_entity_count() const {
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
882868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return kernel_->unsynced_metahandles.size();
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool Directory::TypeHasUnappliedUpdates(ModelType type) {
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
887a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return !kernel_->unapplied_update_metahandles[type].empty();
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::GetUnappliedUpdateMetaHandles(
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BaseTransaction* trans,
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FullModelTypeSet server_types,
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<int64>* result) {
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->clear();
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = UNSPECIFIED; i < MODEL_TYPE_COUNT; ++i) {
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ModelType type = ModelTypeFromInt(i);
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (server_types.Has(type)) {
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::copy(kernel_->unapplied_update_metahandles[type].begin(),
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                kernel_->unapplied_update_metahandles[type].end(),
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                back_inserter(*result));
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Directory::CollectMetaHandleCounts(
9072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<int>* num_entries_by_type,
9082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<int>* num_to_delete_entries_by_type) {
9092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncable::ReadTransaction trans(FROM_HERE, this);
9102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScopedKernelLock lock(this);
9112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
912868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (MetahandlesMap::iterator it = kernel_->metahandles_map.begin();
913868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       it != kernel_->metahandles_map.end(); ++it) {
914868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EntryKernel* entry = it->second;
9152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ModelType type = GetModelTypeFromSpecifics(entry->ref(SPECIFICS));
9162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (*num_entries_by_type)[type]++;
917868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (entry->ref(IS_DEL))
9182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (*num_to_delete_entries_by_type)[type]++;
9192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<base::ListValue> Directory::GetAllNodeDetails(
9235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    BaseTransaction* trans) {
9245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::ListValue> nodes(new base::ListValue());
9255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ScopedKernelLock lock(this);
9275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (MetahandlesMap::iterator it = kernel_->metahandles_map.begin();
9285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != kernel_->metahandles_map.end(); ++it) {
9295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EntryKernel* kernel = it->second;
9305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<base::DictionaryValue> node(
9315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        kernel->ToValue(GetCryptographer(trans)));
9325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Add the position index if appropriate.  This must be done here (and not
9345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // in EntryKernel) because the EntryKernel does not have access to its
9355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // siblings.
9365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (kernel->ShouldMaintainPosition() && !kernel->ref(IS_DEL)) {
9375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      node->SetInteger("positionIndex", GetPositionIndex(trans, kernel));
9385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
9395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    nodes->Append(node.release());
9415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
9425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return nodes.Pass();
9445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
9455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::CheckInvariantsOnTransactionClose(
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncable::BaseTransaction* trans,
9484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const MetahandleSet& modified_handles) {
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: The trans may be in the process of being destructed.  Be careful if
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // you wish to call any of its virtual methods.
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (invariant_check_level_) {
9524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case FULL_DB_VERIFICATION: {
9534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      MetahandleSet all_handles;
9544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      GetAllMetaHandles(trans, &all_handles);
9554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return CheckTreeInvariants(trans, all_handles);
9564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
9574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case VERIFY_CHANGES: {
9584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return CheckTreeInvariants(trans, modified_handles);
9594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
9604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case OFF: {
9614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return true;
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  NOTREACHED();
9654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return false;
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::FullyCheckTreeInvariants(syncable::BaseTransaction* trans) {
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MetahandleSet handles;
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetAllMetaHandles(trans, &handles);
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CheckTreeInvariants(trans, handles);
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::CheckTreeInvariants(syncable::BaseTransaction* trans,
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    const MetahandleSet& handles) {
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MetahandleSet::const_iterator i;
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = handles.begin() ; i != handles.end() ; ++i) {
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 metahandle = *i;
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Entry e(trans, GET_BY_HANDLE, metahandle);
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!SyncAssert(e.good(), FROM_HERE, "Entry is bad", trans))
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
982d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    syncable::Id id = e.GetId();
983d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    syncable::Id parentid = e.GetParentId();
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (id.IsRoot()) {
986d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (!SyncAssert(e.GetIsDir(), FROM_HERE,
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "Entry should be a directory",
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      trans))
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!SyncAssert(parentid.IsRoot(), FROM_HERE,
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "Entry should be root",
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      trans))
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         return false;
994d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (!SyncAssert(!e.GetIsUnsynced(), FROM_HERE,
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "Entry should be sycned",
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      trans))
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         return false;
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1001d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (!e.GetIsDel()) {
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!SyncAssert(id != parentid, FROM_HERE,
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "Id should be different from parent id.",
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      trans))
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         return false;
1006d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (!SyncAssert(!e.GetNonUniqueName().empty(), FROM_HERE,
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "Non unique name should not be empty.",
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      trans))
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int safety_count = handles.size() + 1;
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (!parentid.IsRoot()) {
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Entry parent(trans, GET_BY_ID, parentid);
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!SyncAssert(parent.good(), FROM_HERE,
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        "Parent entry is not valid.",
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        trans))
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
1017d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (handles.end() == handles.find(parent.GetMetahandle()))
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            break; // Skip further checking if parent was unmodified.
1019d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (!SyncAssert(parent.GetIsDir(), FROM_HERE,
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        "Parent should be a directory",
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        trans))
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
1023d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (!SyncAssert(!parent.GetIsDel(), FROM_HERE,
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        "Parent should not have been marked for deletion.",
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        trans))
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
1027d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (!SyncAssert(handles.end() != handles.find(parent.GetMetahandle()),
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        FROM_HERE,
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        "Parent should be in the index.",
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        trans))
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
1032d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        parentid = parent.GetParentId();
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!SyncAssert(--safety_count > 0, FROM_HERE,
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        "Count should be greater than zero.",
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        trans))
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1039d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    int64 base_version = e.GetBaseVersion();
1040d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    int64 server_version = e.GetServerVersion();
1041d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    bool using_unique_client_tag = !e.GetUniqueClientTag().empty();
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (CHANGES_VERSION == base_version || 0 == base_version) {
1043d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (e.GetIsUnappliedUpdate()) {
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Must be a new item, or a de-duplicated unique client tag
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // that was created both locally and remotely.
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!using_unique_client_tag) {
1047d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          if (!SyncAssert(e.GetIsDel(), FROM_HERE,
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          "The entry should not have been deleted.",
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          trans))
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return false;
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // It came from the server, so it must have a server ID.
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!SyncAssert(id.ServerKnows(), FROM_HERE,
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        "The id should be from a server.",
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        trans))
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
1058d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (e.GetIsDir()) {
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // TODO(chron): Implement this mode if clients ever need it.
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // For now, you can't combine a client tag and a directory.
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!SyncAssert(!using_unique_client_tag, FROM_HERE,
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          "Directory cannot have a client tag.",
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          trans))
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return false;
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Should be an uncomitted item, or a successfully deleted one.
1067d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (!e.GetIsDel()) {
1068d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          if (!SyncAssert(e.GetIsUnsynced(), FROM_HERE,
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          "The item should be unsynced.",
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          trans))
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return false;
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the next check failed, it would imply that an item exists
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // on the server, isn't waiting for application locally, but either
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // is an unsynced create or a sucessful delete in the local copy.
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Either way, that's a mismatch.
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!SyncAssert(0 == server_version, FROM_HERE,
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        "Server version should be zero.",
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        trans))
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Items that aren't using the unique client tag should have a zero
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // base version only if they have a local ID.  Items with unique client
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // tags are allowed to use the zero base version for undeletion and
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // de-duplication; the unique client tag trumps the server ID.
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!using_unique_client_tag) {
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!SyncAssert(!id.ServerKnows(), FROM_HERE,
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          "Should be a client only id.",
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          trans))
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return false;
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!SyncAssert(id.ServerKnows(),
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      FROM_HERE,
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "Should be a server id.",
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      trans))
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Server-unknown items that are locally deleted should not be sent up to
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the server.  They must be !IS_UNSYNCED.
1101d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (!SyncAssert(!(!id.ServerKnows() && e.GetIsDel() && e.GetIsUnsynced()),
1102d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                    FROM_HERE,
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "Locally deleted item must not be unsynced.",
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    trans)) {
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::SetInvariantCheckLevel(InvariantCheckLevel check_level) {
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  invariant_check_level_ = check_level;
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 Directory::NextMetahandle() {
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 metahandle = (kernel_->next_metahandle)++;
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return metahandle;
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Always returns a client ID that is the string representation of a negative
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// number.
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Id Directory::NextId() {
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 result;
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScopedKernelLock lock(this);
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = (kernel_->persisted_info.next_id)--;
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LT(result, 0);
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Id::CreateFromClientString(base::Int64ToString(result));
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::HasChildren(BaseTransaction* trans, const Id& id) {
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
1136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return kernel_->parent_child_index.GetChildren(id) != NULL;
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)Id Directory::GetFirstChildId(BaseTransaction* trans,
1140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              const EntryKernel* parent) {
1141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(parent);
1142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(parent->ref(IS_DIR));
1143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
1145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const OrderedChildSet* children =
1146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->parent_child_index.GetChildren(parent->ref(ID));
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We're expected to return root if there are no children.
1149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!children)
1150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return Id();
1151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return (*children->begin())->ref(ID);
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)syncable::Id Directory::GetPredecessorId(EntryKernel* e) {
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(ParentChildIndex::ShouldInclude(e));
1159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const OrderedChildSet* children =
1160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->parent_child_index.GetChildren(e->ref(PARENT_ID));
1161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(children && !children->empty());
1162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  OrderedChildSet::const_iterator i = children->find(e);
1163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(i != children->end());
1164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (i == children->begin()) {
1166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return Id();
1167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
1168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    i--;
1169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return (*i)->ref(ID);
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)syncable::Id Directory::GetSuccessorId(EntryKernel* e) {
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(ParentChildIndex::ShouldInclude(e));
1177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const OrderedChildSet* children =
1178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->parent_child_index.GetChildren(e->ref(PARENT_ID));
1179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(children && !children->empty());
1180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  OrderedChildSet::const_iterator i = children->find(e);
1181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(i != children->end());
1182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  i++;
1184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (i == children->end()) {
1185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return Id();
1186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
1187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return (*i)->ref(ID);
1188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// TODO(rlarocque): Remove all support for placing ShouldMaintainPosition()
1192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// items as siblings of items that do not maintain postions.  It is required
1193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// only for tests.  See crbug.com/178282.
1194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void Directory::PutPredecessor(EntryKernel* e, EntryKernel* predecessor) {
1195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!e->ref(IS_DEL));
1196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!e->ShouldMaintainPosition()) {
1197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK(!e->ref(UNIQUE_POSITION).IsValid());
1198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string suffix = e->ref(UNIQUE_BOOKMARK_TAG);
1201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!suffix.empty());
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Remove our item from the ParentChildIndex and remember to re-add it later.
1204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ScopedKernelLock lock(this);
1205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ScopedParentChildIndexUpdater updater(lock, e, &kernel_->parent_child_index);
1206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Note: The ScopedParentChildIndexUpdater will update this set for us as we
1208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // leave this function.
1209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const OrderedChildSet* siblings =
1210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->parent_child_index.GetChildren(e->ref(PARENT_ID));
1211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!siblings) {
1213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // This parent currently has no other children.
1214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK(predecessor->ref(ID).IsRoot());
1215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UniquePosition pos = UniquePosition::InitialPosition(suffix);
1216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    e->put(UNIQUE_POSITION, pos);
1217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (predecessor->ref(ID).IsRoot()) {
1221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // We have at least one sibling, and we're inserting to the left of them.
1222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UniquePosition successor_pos = (*siblings->begin())->ref(UNIQUE_POSITION);
1223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UniquePosition pos;
1225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!successor_pos.IsValid()) {
1226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // If all our successors are of non-positionable types, just create an
1227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // initial position.  We arbitrarily choose to sort invalid positions to
1228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // the right of the valid positions.
1229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      //
1230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // We really shouldn't need to support this.  See TODO above.
1231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pos = UniquePosition::InitialPosition(suffix);
1232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else  {
1233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      DCHECK(!siblings->empty());
1234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pos = UniquePosition::Before(successor_pos, suffix);
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    e->put(UNIQUE_POSITION, pos);
1238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We can't support placing an item after an invalid position.  Fortunately,
1242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // the tests don't exercise this particular case.  We should not support
1243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // siblings with invalid positions at all.  See TODO above.
1244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(predecessor->ref(UNIQUE_POSITION).IsValid());
1245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  OrderedChildSet::const_iterator neighbour = siblings->find(predecessor);
1247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(neighbour != siblings->end());
1248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ++neighbour;
1250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (neighbour == siblings->end()) {
1251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Inserting at the end of the list.
1252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UniquePosition pos = UniquePosition::After(
1253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        predecessor->ref(UNIQUE_POSITION),
1254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        suffix);
1255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    e->put(UNIQUE_POSITION, pos);
1256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EntryKernel* successor = *neighbour;
1260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Another mixed valid and invalid position case.  This one could be supported
1262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // in theory, but we're trying to deprecate support for siblings with and
1263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // without valid positions.  See TODO above.
1264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(successor->ref(UNIQUE_POSITION).IsValid());
12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Finally, the normal case: inserting between two elements.
1267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UniquePosition pos = UniquePosition::Between(
1268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      predecessor->ref(UNIQUE_POSITION),
1269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      successor->ref(UNIQUE_POSITION),
1270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      suffix);
1271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  e->put(UNIQUE_POSITION, pos);
1272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return;
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// TODO(rlarocque): Avoid this indirection.  Just return the set.
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::AppendChildHandles(const ScopedKernelLock& lock,
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const Id& parent_id,
1278868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                   Directory::Metahandles* result) {
1279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const OrderedChildSet* children =
1280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->parent_child_index.GetChildren(parent_id);
1281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!children)
1282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (OrderedChildSet::const_iterator i = children->begin();
1285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       i != children->end(); ++i) {
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(parent_id, (*i)->ref(PARENT_ID));
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->push_back((*i)->ref(META_HANDLE));
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace syncable
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace syncer
1293