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)
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <algorithm>
87d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <iterator>
97d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/base64.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/trace_event.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
14010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "sync/internal_api/public/base/attachment_id_proto.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "sync/internal_api/public/base/unique_position.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/util/unrecoverable_error_handler.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/entry.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/entry_kernel.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/in_memory_directory_backing_store.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/on_disk_directory_backing_store.h"
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "sync/syncable/scoped_kernel_lock.h"
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "sync/syncable/scoped_parent_child_index_updater.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/syncable-inl.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/syncable/syncable_base_transaction.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/syncable_changes_version.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/syncable/syncable_read_transaction.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/syncable_util.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sync/syncable/syncable_write_transaction.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::string;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace syncer {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace syncable {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::CharType Directory::kSyncDatabaseFilename[] =
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FILE_PATH_LITERAL("SyncData.sqlite3");
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Directory::PersistedKernelInfo::PersistedKernelInfo()
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : next_id(0) {
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ModelTypeSet protocol_types = ProtocolTypes();
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good();
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       iter.Inc()) {
44a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    ResetDownloadProgress(iter.Get());
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    transaction_version[iter.Get()] = 0;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Directory::PersistedKernelInfo::~PersistedKernelInfo() {}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid Directory::PersistedKernelInfo::ResetDownloadProgress(
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelType model_type) {
53a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Clear everything except the data type id field.
54a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  download_progress[model_type].Clear();
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  download_progress[model_type].set_data_type_id(
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetSpecificsFieldNumberFromModelType(model_type));
57a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
58a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Explicitly set an empty token field to denote no progress.
59a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  download_progress[model_type].set_token("");
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool Directory::PersistedKernelInfo::HasEmptyDownloadProgress(
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ModelType model_type) {
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const sync_pb::DataTypeProgressMarker& progress_marker =
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      download_progress[model_type];
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return progress_marker.token().empty();
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Directory::SaveChangesSnapshot::SaveChangesSnapshot()
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : kernel_info_status(KERNEL_SHARE_INFO_INVALID) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Directory::SaveChangesSnapshot::~SaveChangesSnapshot() {
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STLDeleteElements(&dirty_metas);
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STLDeleteElements(&delete_journals);
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Directory::Kernel::Kernel(
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& name,
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const KernelLoadInfo& info, DirectoryChangeDelegate* delegate,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WeakHandle<TransactionObserver>& transaction_observer)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : next_write_transaction_id(0),
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name(name),
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info_status(Directory::KERNEL_SHARE_INFO_VALID),
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      persisted_info(info.kernel_info),
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cache_guid(info.cache_guid),
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      next_metahandle(info.max_metahandle + 1),
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate(delegate),
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      transaction_observer(transaction_observer) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(delegate);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(transaction_observer.IsInitialized());
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Directory::Kernel::~Kernel() {
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  STLDeleteContainerPairSecondPointers(metahandles_map.begin(),
96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                       metahandles_map.end());
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Directory::Directory(
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DirectoryBackingStore* store,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UnrecoverableErrorHandler* unrecoverable_error_handler,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReportUnrecoverableErrorFunction report_unrecoverable_error_function,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NigoriHandler* nigori_handler,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Cryptographer* cryptographer)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : kernel_(NULL),
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      store_(store),
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unrecoverable_error_handler_(unrecoverable_error_handler),
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      report_unrecoverable_error_function_(
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          report_unrecoverable_error_function),
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      unrecoverable_error_set_(false),
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      nigori_handler_(nigori_handler),
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cryptographer_(cryptographer),
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      invariant_check_level_(VERIFY_CHANGES) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Directory::~Directory() {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Close();
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirOpenResult Directory::Open(
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const string& name,
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DirectoryChangeDelegate* delegate,
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WeakHandle<TransactionObserver>& transaction_observer) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACE_EVENT0("sync", "SyncDatabaseOpen");
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const DirOpenResult result =
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OpenImpl(name, delegate, transaction_observer);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (OPENED != result)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Close();
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Directory::InitializeIndices(MetahandlesMap* handles_map) {
135010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  ScopedKernelLock lock(this);
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  kernel_->metahandles_map.swap(*handles_map);
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (MetahandlesMap::const_iterator it = kernel_->metahandles_map.begin();
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       it != kernel_->metahandles_map.end(); ++it) {
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EntryKernel* entry = it->second;
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (ParentChildIndex::ShouldInclude(entry))
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->parent_child_index.Insert(entry);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int64 metahandle = entry->ref(META_HANDLE);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (entry->ref(IS_UNSYNCED))
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->unsynced_metahandles.insert(metahandle);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (entry->ref(IS_UNAPPLIED_UPDATE)) {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const ModelType type = entry->GetServerModelType();
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kernel_->unapplied_update_metahandles[type].insert(metahandle);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!entry->ref(UNIQUE_SERVER_TAG).empty()) {
150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      DCHECK(kernel_->server_tags_map.find(entry->ref(UNIQUE_SERVER_TAG)) ==
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)             kernel_->server_tags_map.end())
152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          << "Unexpected duplicate use of client tag";
153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->server_tags_map[entry->ref(UNIQUE_SERVER_TAG)] = entry;
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!entry->ref(UNIQUE_CLIENT_TAG).empty()) {
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      DCHECK(kernel_->server_tags_map.find(entry->ref(UNIQUE_SERVER_TAG)) ==
157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)             kernel_->server_tags_map.end())
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          << "Unexpected duplicate use of server tag";
159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->client_tags_map[entry->ref(UNIQUE_CLIENT_TAG)] = entry;
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK(kernel_->ids_map.find(entry->ref(ID).value()) ==
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)           kernel_->ids_map.end()) << "Unexpected duplicate use of ID";
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    kernel_->ids_map[entry->ref(ID).value()] = entry;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!entry->is_dirty());
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    AddToAttachmentIndex(lock, metahandle, entry->ref(ATTACHMENT_METADATA));
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirOpenResult Directory::OpenImpl(
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const string& name,
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DirectoryChangeDelegate* delegate,
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WeakHandle<TransactionObserver>&
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        transaction_observer) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  KernelLoadInfo info;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Temporary indices before kernel_ initialized in case Load fails. We 0(1)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // swap these later.
177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Directory::MetahandlesMap tmp_handles_map;
178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Avoids mem leaks on failure.  Harmlessly deletes the empty hash map after
180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // the swap in the success case.
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  STLValueDeleter<Directory::MetahandlesMap> deleter(&tmp_handles_map);
182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  JournalIndex delete_journals;
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DirOpenResult result =
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      store_->Load(&tmp_handles_map, &delete_journals, &info);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (OPENED != result)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_ = new Kernel(name, info, delegate, transaction_observer);
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete_journal_.reset(new DeleteJournal(&delete_journals));
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  InitializeIndices(&tmp_handles_map);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Write back the share info to reserve some space in 'next_id'.  This will
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // prevent local ID reuse in the case of an early crash.  See the comments in
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TakeSnapshotForSaveChanges() or crbug.com/142987 for more information.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SaveChanges())
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FAILED_INITIAL_WRITE;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return OPENED;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DeleteJournal* Directory::delete_journal() {
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(delete_journal_.get());
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return delete_journal_.get();
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::Close() {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  store_.reset();
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kernel_) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete kernel_;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kernel_ = NULL;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::OnUnrecoverableError(const BaseTransaction* trans,
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const tracked_objects::Location& location,
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const std::string & message) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(trans != NULL);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unrecoverable_error_set_ = true;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unrecoverable_error_handler_->OnUnrecoverableError(location,
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     message);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EntryKernel* Directory::GetEntryById(const Id& id) {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return GetEntryById(lock, id);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciEntryKernel* Directory::GetEntryById(const ScopedKernelLock& lock,
2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                     const Id& id) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(kernel_);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find it in the in memory ID index.
235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  IdsMap::iterator id_found = kernel_->ids_map.find(id.value());
236868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (id_found != kernel_->ids_map.end()) {
237868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return id_found->second;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EntryKernel* Directory::GetEntryByClientTag(const string& tag) {
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(kernel_);
245868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  TagsMap::iterator it = kernel_->client_tags_map.find(tag);
247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (it != kernel_->client_tags_map.end()) {
248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return it->second;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EntryKernel* Directory::GetEntryByServerTag(const string& tag) {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(kernel_);
256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  TagsMap::iterator it = kernel_->server_tags_map.find(tag);
257868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (it != kernel_->server_tags_map.end()) {
258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return it->second;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)EntryKernel* Directory::GetEntryByHandle(int64 metahandle) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
2651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return GetEntryByHandle(lock, metahandle);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciEntryKernel* Directory::GetEntryByHandle(const ScopedKernelLock& lock,
2691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                         int64 metahandle) {
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Look up in memory
271868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  MetahandlesMap::iterator found =
272868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->metahandles_map.find(metahandle);
273868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (found != kernel_->metahandles_map.end()) {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Found it in memory.  Easy.
275868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return found->second;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::GetChildHandlesById(
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BaseTransaction* trans, const Id& parent_id,
282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    Directory::Metahandles* result) {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SyncAssert(this == trans->directory(), FROM_HERE,
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  "Directories don't match", trans))
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->clear();
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AppendChildHandles(lock, parent_id, result);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
293868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)int Directory::GetTotalNodeCount(
294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    BaseTransaction* trans,
295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EntryKernel* kernel) const {
296868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!SyncAssert(this == trans->directory(), FROM_HERE,
297868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  "Directories don't match", trans))
298868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return false;
299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int count = 1;
301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::deque<const OrderedChildSet*> child_sets;
302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
303868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  GetChildSetForKernel(trans, kernel, &child_sets);
304868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  while (!child_sets.empty()) {
305868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const OrderedChildSet* set = child_sets.front();
306868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    child_sets.pop_front();
307868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for (OrderedChildSet::const_iterator it = set->begin();
308868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)         it != set->end(); ++it) {
309868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      count++;
310868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      GetChildSetForKernel(trans, *it, &child_sets);
311868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
312868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
313868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
314868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return count;
315868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
316868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
317868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Directory::GetChildSetForKernel(
318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    BaseTransaction* trans,
319868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EntryKernel* kernel,
320868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    std::deque<const OrderedChildSet*>* child_sets) const {
321868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!kernel->ref(IS_DIR))
322868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;  // Not a directory => no children.
323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
324868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const OrderedChildSet* descendants =
325868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->parent_child_index.GetChildren(kernel->ref(ID));
326868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!descendants)
327868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;  // This directory has no children.
328868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Add our children to the list of items to be traversed.
330868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  child_sets->push_back(descendants);
331868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
332868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)int Directory::GetPositionIndex(
3347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    BaseTransaction* trans,
3357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    EntryKernel* kernel) const {
3367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const OrderedChildSet* siblings =
3377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      kernel_->parent_child_index.GetChildren(kernel->ref(PARENT_ID));
3387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  OrderedChildSet::const_iterator it = siblings->find(kernel);
3407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return std::distance(siblings->begin(), it);
3417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
3427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool Directory::InsertEntry(BaseWriteTransaction* trans, EntryKernel* entry) {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
3451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return InsertEntry(lock, trans, entry);
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool Directory::InsertEntry(const ScopedKernelLock& lock,
3491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            BaseWriteTransaction* trans,
3501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            EntryKernel* entry) {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SyncAssert(NULL != entry, FROM_HERE, "Entry is null", trans))
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char error[] = "Entry already in memory index.";
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
356868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!SyncAssert(
357868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          kernel_->metahandles_map.insert(
358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              std::make_pair(entry->ref(META_HANDLE), entry)).second,
359868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          FROM_HERE,
360868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          error,
361868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          trans)) {
362868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return false;
363868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
364868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!SyncAssert(
365868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          kernel_->ids_map.insert(
366868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              std::make_pair(entry->ref(ID).value(), entry)).second,
367868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          FROM_HERE,
368868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          error,
369868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          trans)) {
370868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return false;
371868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (ParentChildIndex::ShouldInclude(entry)) {
373868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!SyncAssert(kernel_->parent_child_index.Insert(entry),
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    FROM_HERE,
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    error,
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    trans)) {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
380010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  AddToAttachmentIndex(
3811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      lock, entry->ref(META_HANDLE), entry->ref(ATTACHMENT_METADATA));
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
383868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Should NEVER be created with a client tag or server tag.
384868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!SyncAssert(entry->ref(UNIQUE_SERVER_TAG).empty(), FROM_HERE,
385868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  "Server tag should be empty", trans)) {
386868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return false;
387868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SyncAssert(entry->ref(UNIQUE_CLIENT_TAG).empty(), FROM_HERE,
389868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                  "Client tag should be empty", trans))
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool Directory::ReindexId(BaseWriteTransaction* trans,
3964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                          EntryKernel* const entry,
3974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                          const Id& new_id) {
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
3991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (NULL != GetEntryById(lock, new_id))
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the indices that depend on the ID field.
404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ScopedParentChildIndexUpdater updater_b(lock, entry,
405868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        &kernel_->parent_child_index);
406868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    size_t num_erased = kernel_->ids_map.erase(entry->ref(ID).value());
407868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK_EQ(1U, num_erased);
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entry->put(ID, new_id);
409868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    kernel_->ids_map[entry->ref(ID).value()] = entry;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool Directory::ReindexParentId(BaseWriteTransaction* trans,
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                EntryKernel* const entry,
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const Id& new_parent_id) {
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the indices that depend on the PARENT_ID field.
421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ScopedParentChildIndexUpdater index_updater(lock, entry,
422868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        &kernel_->parent_child_index);
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entry->put(PARENT_ID, new_parent_id);
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
428010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void Directory::RemoveFromAttachmentIndex(
4291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const ScopedKernelLock& lock,
430010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const int64 metahandle,
4311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const sync_pb::AttachmentMetadata& attachment_metadata) {
432010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (int i = 0; i < attachment_metadata.record_size(); ++i) {
433010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    AttachmentIdUniqueId unique_id =
434010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        attachment_metadata.record(i).id().unique_id();
435010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    IndexByAttachmentId::iterator iter =
436010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        kernel_->index_by_attachment_id.find(unique_id);
437010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (iter != kernel_->index_by_attachment_id.end()) {
438010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      iter->second.erase(metahandle);
439010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      if (iter->second.empty()) {
440010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        kernel_->index_by_attachment_id.erase(iter);
441010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      }
442010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
443010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
444010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
445010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
446010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void Directory::AddToAttachmentIndex(
4471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const ScopedKernelLock& lock,
448010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const int64 metahandle,
4491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const sync_pb::AttachmentMetadata& attachment_metadata) {
450010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (int i = 0; i < attachment_metadata.record_size(); ++i) {
451010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    AttachmentIdUniqueId unique_id =
452010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        attachment_metadata.record(i).id().unique_id();
453010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    IndexByAttachmentId::iterator iter =
454010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        kernel_->index_by_attachment_id.find(unique_id);
455010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (iter == kernel_->index_by_attachment_id.end()) {
456010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      iter = kernel_->index_by_attachment_id.insert(std::make_pair(
457010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                                        unique_id,
458010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                                        MetahandleSet())).first;
459010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
460010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    iter->second.insert(metahandle);
461010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
462010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
463010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
464010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void Directory::UpdateAttachmentIndex(
465010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const int64 metahandle,
466010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const sync_pb::AttachmentMetadata& old_metadata,
467010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const sync_pb::AttachmentMetadata& new_metadata) {
468010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  ScopedKernelLock lock(this);
4691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  RemoveFromAttachmentIndex(lock, metahandle, old_metadata);
4701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AddToAttachmentIndex(lock, metahandle, new_metadata);
471010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
472010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
473cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void Directory::GetMetahandlesByAttachmentId(
474cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    BaseTransaction* trans,
475cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const sync_pb::AttachmentIdProto& attachment_id_proto,
476cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Metahandles* result) {
477cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(result);
478cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  result->clear();
479cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ScopedKernelLock lock(this);
480cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  IndexByAttachmentId::const_iterator index_iter =
481cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      kernel_->index_by_attachment_id.find(attachment_id_proto.unique_id());
482cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (index_iter == kernel_->index_by_attachment_id.end())
483cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
484cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const MetahandleSet& metahandle_set = index_iter->second;
485cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::copy(
486cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      metahandle_set.begin(), metahandle_set.end(), back_inserter(*result));
487cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
488cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::unrecoverable_error_set(const BaseTransaction* trans) const {
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(trans != NULL);
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return unrecoverable_error_set_;
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid Directory::ClearDirtyMetahandles(const ScopedKernelLock& lock) {
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->transaction_mutex.AssertAcquired();
496868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  kernel_->dirty_metahandles.clear();
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::SafeToPurgeFromMemory(WriteTransaction* trans,
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const EntryKernel* const entry) const {
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool safe = entry->ref(IS_DEL) && !entry->is_dirty() &&
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !entry->ref(SYNCING) && !entry->ref(IS_UNAPPLIED_UPDATE) &&
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !entry->ref(IS_UNSYNCED);
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (safe) {
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 handle = entry->ref(META_HANDLE);
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ModelType type = entry->GetServerModelType();
508868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!SyncAssert(kernel_->dirty_metahandles.count(handle) == 0U,
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    FROM_HERE,
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "Dirty metahandles should be empty", trans))
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(tim): Bug 49278.
513868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!SyncAssert(!kernel_->unsynced_metahandles.count(handle),
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    FROM_HERE,
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "Unsynced handles should be empty",
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    trans))
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!SyncAssert(!kernel_->unapplied_update_metahandles[type].count(handle),
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    FROM_HERE,
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "Unapplied metahandles should be empty",
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    trans))
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return safe;
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::TakeSnapshotForSaveChanges(SaveChangesSnapshot* snapshot) {
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReadTransaction trans(FROM_HERE, this);
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there is an unrecoverable error then just bail out.
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (unrecoverable_error_set(&trans))
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Deep copy dirty entries from kernel_->metahandles_index into snapshot and
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // clear dirty flags.
538868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (MetahandleSet::const_iterator i = kernel_->dirty_metahandles.begin();
539868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       i != kernel_->dirty_metahandles.end(); ++i) {
5401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    EntryKernel* entry = GetEntryByHandle(lock, *i);
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!entry)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Skip over false positives; it happens relatively infrequently.
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!entry->is_dirty())
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    snapshot->dirty_metas.insert(snapshot->dirty_metas.end(),
5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 new EntryKernel(*entry));
548868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK_EQ(1U, kernel_->dirty_metahandles.count(*i));
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't bother removing from the index here as we blow the entire thing
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // in a moment, and it unnecessarily complicates iteration.
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entry->clear_dirty(NULL);
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ClearDirtyMetahandles(lock);
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set purged handles.
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(snapshot->metahandles_to_purge.empty());
557868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  snapshot->metahandles_to_purge.swap(kernel_->metahandles_to_purge);
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fill kernel_info_status and kernel_info.
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  snapshot->kernel_info = kernel_->persisted_info;
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // To avoid duplicates when the process crashes, we record the next_id to be
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // greater magnitude than could possibly be reached before the next save
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // changes.  In other words, it's effectively impossible for the user to
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // generate 65536 new bookmarks in 3 seconds.
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  snapshot->kernel_info.next_id -= 65536;
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  snapshot->kernel_info_status = kernel_->info_status;
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This one we reset on failure.
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->info_status = KERNEL_SHARE_INFO_VALID;
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete_journal_->TakeSnapshotAndClear(
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &trans, &snapshot->delete_journals, &snapshot->delete_journals_to_purge);
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::SaveChanges() {
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = false;
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock scoped_lock(kernel_->save_changes_mutex);
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Snapshot and save.
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveChangesSnapshot snapshot;
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TakeSnapshotForSaveChanges(&snapshot);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  success = store_->SaveChanges(snapshot);
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Handle success or failure.
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (success)
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    success = VacuumAfterSaveChanges(snapshot);
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandleSaveChangesFailure(snapshot);
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return success;
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::VacuumAfterSaveChanges(const SaveChangesSnapshot& snapshot) {
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (snapshot.dirty_metas.empty())
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Need a write transaction as we are about to permanently purge entries.
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WriteTransaction trans(FROM_HERE, VACUUM_AFTER_SAVE, this);
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now drop everything we can out of memory.
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (EntryKernelSet::const_iterator i = snapshot.dirty_metas.begin();
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != snapshot.dirty_metas.end(); ++i) {
602868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    MetahandlesMap::iterator found =
603868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        kernel_->metahandles_map.find((*i)->ref(META_HANDLE));
604868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EntryKernel* entry = (found == kernel_->metahandles_map.end() ?
605868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                          NULL : found->second);
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (entry && SafeToPurgeFromMemory(&trans, entry)) {
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We now drop deleted metahandles that are up to date on both the client
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // and the server.
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_t num_erased = 0;
610868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      num_erased = kernel_->metahandles_map.erase(entry->ref(META_HANDLE));
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_EQ(1u, num_erased);
612868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      num_erased = kernel_->ids_map.erase(entry->ref(ID).value());
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_EQ(1u, num_erased);
614868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (!entry->ref(UNIQUE_SERVER_TAG).empty()) {
615868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        num_erased =
616868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            kernel_->server_tags_map.erase(entry->ref(UNIQUE_SERVER_TAG));
617868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        DCHECK_EQ(1u, num_erased);
618868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
619868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (!entry->ref(UNIQUE_CLIENT_TAG).empty()) {
620868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        num_erased =
621868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            kernel_->client_tags_map.erase(entry->ref(UNIQUE_CLIENT_TAG));
622868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        DCHECK_EQ(1u, num_erased);
623868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
624868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (!SyncAssert(!kernel_->parent_child_index.Contains(entry),
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      FROM_HERE,
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "Deleted entry still present",
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      (&trans)))
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
629010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      RemoveFromAttachmentIndex(
6301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          lock, entry->ref(META_HANDLE), entry->ref(ATTACHMENT_METADATA));
631010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete entry;
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (trans.unrecoverable_error_set())
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
640868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void Directory::UnapplyEntry(EntryKernel* entry) {
641868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int64 handle = entry->ref(META_HANDLE);
642868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ModelType server_type = GetModelTypeFromSpecifics(
643868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      entry->ref(SERVER_SPECIFICS));
644868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
645868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Clear enough so that on the next sync cycle all local data will
646868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // be overwritten.
647868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Note: do not modify the root node in order to preserve the
648868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // initial sync ended bit for this type (else on the next restart
649868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // this type will be treated as disabled and therefore fully purged).
650868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (IsRealDataType(server_type) &&
651868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      ModelTypeToRootTag(server_type) == entry->ref(UNIQUE_SERVER_TAG)) {
652868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
653868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
654868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
655868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Set the unapplied bit if this item has server data.
656868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (IsRealDataType(server_type) && !entry->ref(IS_UNAPPLIED_UPDATE)) {
657868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry->put(IS_UNAPPLIED_UPDATE, true);
658868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    kernel_->unapplied_update_metahandles[server_type].insert(handle);
659868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry->mark_dirty(&kernel_->dirty_metahandles);
660868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
661868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
662868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Unset the unsynced bit.
663868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (entry->ref(IS_UNSYNCED)) {
664868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    kernel_->unsynced_metahandles.erase(handle);
665868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry->put(IS_UNSYNCED, false);
666868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry->mark_dirty(&kernel_->dirty_metahandles);
667868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
668868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
669868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Mark the item as locally deleted. No deleted items are allowed in the
670868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // parent child index.
671868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!entry->ref(IS_DEL)) {
672868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    kernel_->parent_child_index.Remove(entry);
673868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry->put(IS_DEL, true);
674868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry->mark_dirty(&kernel_->dirty_metahandles);
675868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
676868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
677868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Set the version to the "newly created" version.
678868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (entry->ref(BASE_VERSION) != CHANGES_VERSION) {
679868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry->put(BASE_VERSION, CHANGES_VERSION);
680868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entry->mark_dirty(&kernel_->dirty_metahandles);
681868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
682868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
683868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // At this point locally created items that aren't synced will become locally
684868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // deleted items, and purged on the next snapshot. All other items will match
685868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // the state they would have had if they were just created via a server
686868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // update. See MutableEntry::MutableEntry(.., CreateNewUpdateItem, ..).
687868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
688868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
6891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid Directory::DeleteEntry(const ScopedKernelLock& lock,
6901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            bool save_to_journal,
691868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                            EntryKernel* entry,
6921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            EntryKernelSet* entries_to_journal) {
693868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int64 handle = entry->ref(META_HANDLE);
694868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ModelType server_type = GetModelTypeFromSpecifics(
695868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      entry->ref(SERVER_SPECIFICS));
696868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
697868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  kernel_->metahandles_to_purge.insert(handle);
698868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
699868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  size_t num_erased = 0;
700868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  num_erased = kernel_->metahandles_map.erase(entry->ref(META_HANDLE));
701868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK_EQ(1u, num_erased);
702868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  num_erased = kernel_->ids_map.erase(entry->ref(ID).value());
703868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK_EQ(1u, num_erased);
704868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  num_erased = kernel_->unsynced_metahandles.erase(handle);
705868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK_EQ(entry->ref(IS_UNSYNCED), num_erased > 0);
706868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  num_erased =
707868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->unapplied_update_metahandles[server_type].erase(handle);
708868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK_EQ(entry->ref(IS_UNAPPLIED_UPDATE), num_erased > 0);
709868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (kernel_->parent_child_index.Contains(entry))
710868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    kernel_->parent_child_index.Remove(entry);
711868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
712868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!entry->ref(UNIQUE_CLIENT_TAG).empty()) {
713868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    num_erased =
714868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        kernel_->client_tags_map.erase(entry->ref(UNIQUE_CLIENT_TAG));
715868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK_EQ(1u, num_erased);
716868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
717868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!entry->ref(UNIQUE_SERVER_TAG).empty()) {
718868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    num_erased =
719868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        kernel_->server_tags_map.erase(entry->ref(UNIQUE_SERVER_TAG));
720868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK_EQ(1u, num_erased);
721868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
7221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  RemoveFromAttachmentIndex(lock, handle, entry->ref(ATTACHMENT_METADATA));
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
724868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (save_to_journal) {
725868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    entries_to_journal->insert(entry);
726868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  } else {
727868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    delete entry;
728868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
729868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
730868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
731868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool Directory::PurgeEntriesWithTypeIn(ModelTypeSet disabled_types,
732868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                       ModelTypeSet types_to_journal,
733868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                       ModelTypeSet types_to_unapply) {
734868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  disabled_types.RemoveAll(ProxyTypes());
735868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
736868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (disabled_types.Empty())
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WriteTransaction trans(FROM_HERE, PURGE_ENTRIES, this);
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EntryKernelSet entries_to_journal;
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    STLElementDeleter<EntryKernelSet> journal_deleter(&entries_to_journal);
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ScopedKernelLock lock(this);
747868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
7485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      bool found_progress = false;
7495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      for (ModelTypeSet::Iterator iter = disabled_types.First(); iter.Good();
7505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)           iter.Inc()) {
7515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (!kernel_->persisted_info.HasEmptyDownloadProgress(iter.Get()))
7525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          found_progress = true;
7535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
7545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // If none of the disabled types have progress markers, there's nothing to
7565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // purge.
7575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (!found_progress)
7585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return true;
7595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
760868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // We iterate in two passes to avoid a bug in STLport (which is used in
761868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // the Android build).  There are some versions of that library where a
762868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // hash_map's iterators can be invalidated when an item is erased from the
763868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // hash_map.
764868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // See http://sourceforge.net/p/stlport/bugs/239/.
765868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
766868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      std::set<EntryKernel*> to_purge;
767868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (MetahandlesMap::iterator it = kernel_->metahandles_map.begin();
768868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)           it != kernel_->metahandles_map.end(); ++it) {
769868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        const sync_pb::EntitySpecifics& local_specifics =
770868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            it->second->ref(SPECIFICS);
771868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        const sync_pb::EntitySpecifics& server_specifics =
772868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            it->second->ref(SERVER_SPECIFICS);
773868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        ModelType local_type = GetModelTypeFromSpecifics(local_specifics);
774868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        ModelType server_type = GetModelTypeFromSpecifics(server_specifics);
775868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
776868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        if ((IsRealDataType(local_type) && disabled_types.Has(local_type)) ||
777868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            (IsRealDataType(server_type) && disabled_types.Has(server_type))) {
778868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          to_purge.insert(it->second);
779868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        }
780868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      }
781868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
782868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (std::set<EntryKernel*>::iterator it = to_purge.begin();
783868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)           it != to_purge.end(); ++it) {
784868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        EntryKernel* entry = *it;
785868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
786868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        const sync_pb::EntitySpecifics& local_specifics =
787868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            (*it)->ref(SPECIFICS);
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const sync_pb::EntitySpecifics& server_specifics =
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            (*it)->ref(SERVER_SPECIFICS);
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ModelType local_type = GetModelTypeFromSpecifics(local_specifics);
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ModelType server_type = GetModelTypeFromSpecifics(server_specifics);
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
793868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        if (types_to_unapply.Has(local_type) ||
794868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            types_to_unapply.Has(server_type)) {
795868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          UnapplyEntry(entry);
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
797868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          bool save_to_journal =
798868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              (types_to_journal.Has(local_type) ||
799868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)               types_to_journal.Has(server_type)) &&
800868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              (delete_journal_->IsDeleteJournalEnabled(local_type) ||
801868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)               delete_journal_->IsDeleteJournalEnabled(server_type));
8021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          DeleteEntry(lock, save_to_journal, entry, &entries_to_journal);
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      delete_journal_->AddJournalBatch(&trans, entries_to_journal);
8072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
808868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // Ensure meta tracking for these data types reflects the purged state.
809868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      for (ModelTypeSet::Iterator it = disabled_types.First();
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           it.Good(); it.Inc()) {
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kernel_->persisted_info.transaction_version[it.Get()] = 0;
812868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
813a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        // Don't discard progress markers or context for unapplied types.
814a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        if (!types_to_unapply.Has(it.Get())) {
815a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          kernel_->persisted_info.ResetDownloadProgress(it.Get());
816a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          kernel_->persisted_info.datatype_context[it.Get()].Clear();
817a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        }
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
819a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
820a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
826c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool Directory::ResetVersionsForType(BaseWriteTransaction* trans,
827c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                     ModelType type) {
828c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!ProtocolTypes().Has(type))
829c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return false;
830c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK_NE(type, BOOKMARKS) << "Only non-hierarchical types are supported";
831c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
832c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EntryKernel* type_root = GetEntryByServerTag(ModelTypeToRootTag(type));
833c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!type_root)
834c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return false;
835c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
836c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ScopedKernelLock lock(this);
837c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const Id& type_root_id = type_root->ref(ID);
838c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  Directory::Metahandles children;
839c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  AppendChildHandles(lock, type_root_id, &children);
840c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
841c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  for (Metahandles::iterator it = children.begin(); it != children.end();
842c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch       ++it) {
8431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    EntryKernel* entry = GetEntryByHandle(lock, *it);
844c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (!entry)
845c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      continue;
846c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (entry->ref(BASE_VERSION) > 1)
847c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      entry->put(BASE_VERSION, 1);
848c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (entry->ref(SERVER_VERSION) > 1)
849c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      entry->put(SERVER_VERSION, 1);
850c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
851c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // Note that we do not unset IS_UNSYNCED or IS_UNAPPLIED_UPDATE in order
852c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // to ensure no in-transit data is lost.
853c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
854c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    entry->mark_dirty(&kernel_->dirty_metahandles);
855c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
856c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
857c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return true;
858c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
859c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
860010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool Directory::IsAttachmentLinked(
861010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const sync_pb::AttachmentIdProto& attachment_id_proto) const {
862010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  ScopedKernelLock lock(this);
863010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  IndexByAttachmentId::const_iterator iter =
864010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      kernel_->index_by_attachment_id.find(attachment_id_proto.unique_id());
865010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (iter != kernel_->index_by_attachment_id.end() && !iter->second.empty()) {
866010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return true;
867010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
868010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return false;
869010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
870010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::HandleSaveChangesFailure(const SaveChangesSnapshot& snapshot) {
8722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WriteTransaction trans(FROM_HERE, HANDLE_SAVE_FAILURE, this);
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Because we optimistically cleared the dirty bit on the real entries when
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // taking the snapshot, we must restore it on failure.  Not doing this could
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cause lost data, if no other changes are made to the in-memory entries
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that would cause the dirty bit to get set again. Setting the bit ensures
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that SaveChanges will at least try again later.
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (EntryKernelSet::const_iterator i = snapshot.dirty_metas.begin();
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != snapshot.dirty_metas.end(); ++i) {
883868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    MetahandlesMap::iterator found =
884868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        kernel_->metahandles_map.find((*i)->ref(META_HANDLE));
885868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (found != kernel_->metahandles_map.end()) {
886868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      found->second->mark_dirty(&kernel_->dirty_metahandles);
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
890868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  kernel_->metahandles_to_purge.insert(snapshot.metahandles_to_purge.begin(),
891868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                       snapshot.metahandles_to_purge.end());
8922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Restore delete journals.
8942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete_journal_->AddJournalBatch(&trans, snapshot.delete_journals);
8952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete_journal_->PurgeDeleteJournals(&trans,
8962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       snapshot.delete_journals_to_purge);
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::GetDownloadProgress(
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelType model_type,
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_pb::DataTypeProgressMarker* value_out) const {
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return value_out->CopyFrom(
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kernel_->persisted_info.download_progress[model_type]);
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::GetDownloadProgressAsString(
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelType model_type,
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string* value_out) const {
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->persisted_info.download_progress[model_type].SerializeToString(
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      value_out);
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t Directory::GetEntriesCount() const {
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
917868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return kernel_->metahandles_map.size();
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::SetDownloadProgress(
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelType model_type,
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const sync_pb::DataTypeProgressMarker& new_progress) {
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->persisted_info.download_progress[model_type].CopyFrom(new_progress);
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 Directory::GetTransactionVersion(ModelType type) const {
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->transaction_mutex.AssertAcquired();
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kernel_->persisted_info.transaction_version[type];
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::IncrementTransactionVersion(ModelType type) {
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->transaction_mutex.AssertAcquired();
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->persisted_info.transaction_version[type]++;
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
938c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid Directory::GetDataTypeContext(BaseTransaction* trans,
939c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                   ModelType type,
940c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                   sync_pb::DataTypeContext* context) const {
941c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ScopedKernelLock lock(this);
942c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  context->CopyFrom(kernel_->persisted_info.datatype_context[type]);
943c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
944c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
945c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid Directory::SetDataTypeContext(
946c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    BaseWriteTransaction* trans,
947c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    ModelType type,
948c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const sync_pb::DataTypeContext& context) {
949c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ScopedKernelLock lock(this);
950c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  kernel_->persisted_info.datatype_context[type].CopyFrom(context);
951c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
952c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
953c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
9542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ModelTypeSet Directory::InitialSyncEndedTypes() {
9552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncable::ReadTransaction trans(FROM_HERE, this);
9562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ModelTypeSet protocol_types = ProtocolTypes();
9572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ModelTypeSet initial_sync_ended_types;
9582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (ModelTypeSet::Iterator i = protocol_types.First(); i.Good(); i.Inc()) {
9592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (InitialSyncEndedForType(&trans, i.Get())) {
9602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      initial_sync_ended_types.Put(i.Get());
9612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
9622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return initial_sync_ended_types;
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Directory::InitialSyncEndedForType(ModelType type) {
9672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncable::ReadTransaction trans(FROM_HERE, this);
9682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return InitialSyncEndedForType(&trans, type);
9692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Directory::InitialSyncEndedForType(
9722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BaseTransaction* trans, ModelType type) {
9732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // True iff the type's root node has been received and applied.
97446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  syncable::Entry entry(trans, syncable::GET_TYPE_ROOT, type);
975d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return entry.good() && entry.GetBaseVersion() != CHANGES_VERSION;
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string Directory::store_birthday() const {
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kernel_->persisted_info.store_birthday;
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::set_store_birthday(const string& store_birthday) {
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kernel_->persisted_info.store_birthday == store_birthday)
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->persisted_info.store_birthday = store_birthday;
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string Directory::bag_of_chips() const {
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kernel_->persisted_info.bag_of_chips;
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::set_bag_of_chips(const string& bag_of_chips) {
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kernel_->persisted_info.bag_of_chips == bag_of_chips)
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->persisted_info.bag_of_chips = bag_of_chips;
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string Directory::cache_guid() const {
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No need to lock since nothing ever writes to it after load.
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kernel_->cache_guid;
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NigoriHandler* Directory::GetNigoriHandler() {
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return nigori_handler_;
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Cryptographer* Directory::GetCryptographer(const BaseTransaction* trans) {
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(this, trans->directory());
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return cryptographer_;
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::GetAllMetaHandles(BaseTransaction* trans,
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  MetahandleSet* result) {
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->clear();
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
1023868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (MetahandlesMap::iterator i = kernel_->metahandles_map.begin();
1024868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       i != kernel_->metahandles_map.end(); ++i) {
1025868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    result->insert(i->first);
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::GetUnsyncedMetaHandles(BaseTransaction* trans,
1030868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                       Metahandles* result) {
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->clear();
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
1033868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  copy(kernel_->unsynced_metahandles.begin(),
1034868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       kernel_->unsynced_metahandles.end(), back_inserter(*result));
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 Directory::unsynced_entity_count() const {
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
1039868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return kernel_->unsynced_metahandles.size();
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1042a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool Directory::TypeHasUnappliedUpdates(ModelType type) {
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
1044a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return !kernel_->unapplied_update_metahandles[type].empty();
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::GetUnappliedUpdateMetaHandles(
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BaseTransaction* trans,
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FullModelTypeSet server_types,
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<int64>* result) {
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->clear();
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = UNSPECIFIED; i < MODEL_TYPE_COUNT; ++i) {
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ModelType type = ModelTypeFromInt(i);
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (server_types.Has(type)) {
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::copy(kernel_->unapplied_update_metahandles[type].begin(),
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                kernel_->unapplied_update_metahandles[type].end(),
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                back_inserter(*result));
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1063a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void Directory::GetMetaHandlesOfType(BaseTransaction* trans,
1064a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                     ModelType type,
1065a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                     std::vector<int64>* result) {
1066a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ScopedKernelLock lock(this);
10671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GetMetaHandlesOfType(lock, trans, type, result);
10681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
10691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
10701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid Directory::GetMetaHandlesOfType(const ScopedKernelLock& lock,
10711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                     BaseTransaction* trans,
10721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                     ModelType type,
10731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                     std::vector<int64>* result) {
10741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  result->clear();
1075a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (MetahandlesMap::iterator it = kernel_->metahandles_map.begin();
1076a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       it != kernel_->metahandles_map.end(); ++it) {
1077a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    EntryKernel* entry = it->second;
1078a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const ModelType entry_type =
1079a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        GetModelTypeFromSpecifics(entry->ref(SPECIFICS));
1080a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (entry_type == type)
1081a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      result->push_back(it->first);
1082a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
1083a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
1084a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
10852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Directory::CollectMetaHandleCounts(
10862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<int>* num_entries_by_type,
10872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<int>* num_to_delete_entries_by_type) {
10882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncable::ReadTransaction trans(FROM_HERE, this);
10892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ScopedKernelLock lock(this);
10902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1091868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (MetahandlesMap::iterator it = kernel_->metahandles_map.begin();
1092868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       it != kernel_->metahandles_map.end(); ++it) {
1093868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EntryKernel* entry = it->second;
10942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ModelType type = GetModelTypeFromSpecifics(entry->ref(SPECIFICS));
10952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (*num_entries_by_type)[type]++;
1096868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (entry->ref(IS_DEL))
10972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (*num_to_delete_entries_by_type)[type]++;
10982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1101c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochscoped_ptr<base::ListValue> Directory::GetNodeDetailsForType(
1102c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    BaseTransaction* trans,
1103c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    ModelType type) {
11045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::ListValue> nodes(new base::ListValue());
11055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ScopedKernelLock lock(this);
11075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (MetahandlesMap::iterator it = kernel_->metahandles_map.begin();
11085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != kernel_->metahandles_map.end(); ++it) {
1109c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (GetModelTypeFromSpecifics(it->second->ref(SPECIFICS)) != type) {
1110c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      continue;
1111c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    }
1112c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
11135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EntryKernel* kernel = it->second;
11145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<base::DictionaryValue> node(
11155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        kernel->ToValue(GetCryptographer(trans)));
11165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Add the position index if appropriate.  This must be done here (and not
11185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // in EntryKernel) because the EntryKernel does not have access to its
11195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // siblings.
11205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (kernel->ShouldMaintainPosition() && !kernel->ref(IS_DEL)) {
11215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      node->SetInteger("positionIndex", GetPositionIndex(trans, kernel));
11225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
11235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    nodes->Append(node.release());
11255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
11265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return nodes.Pass();
11285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
11295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::CheckInvariantsOnTransactionClose(
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncable::BaseTransaction* trans,
11324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const MetahandleSet& modified_handles) {
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: The trans may be in the process of being destructed.  Be careful if
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // you wish to call any of its virtual methods.
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (invariant_check_level_) {
11364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case FULL_DB_VERIFICATION: {
11374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      MetahandleSet all_handles;
11384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      GetAllMetaHandles(trans, &all_handles);
11394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return CheckTreeInvariants(trans, all_handles);
11404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
11414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case VERIFY_CHANGES: {
11424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return CheckTreeInvariants(trans, modified_handles);
11434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
11444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    case OFF: {
11454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return true;
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  NOTREACHED();
11494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return false;
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::FullyCheckTreeInvariants(syncable::BaseTransaction* trans) {
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MetahandleSet handles;
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetAllMetaHandles(trans, &handles);
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CheckTreeInvariants(trans, handles);
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::CheckTreeInvariants(syncable::BaseTransaction* trans,
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    const MetahandleSet& handles) {
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MetahandleSet::const_iterator i;
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = handles.begin() ; i != handles.end() ; ++i) {
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 metahandle = *i;
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Entry e(trans, GET_BY_HANDLE, metahandle);
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!SyncAssert(e.good(), FROM_HERE, "Entry is bad", trans))
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1166d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    syncable::Id id = e.GetId();
1167d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    syncable::Id parentid = e.GetParentId();
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (id.IsRoot()) {
1170d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (!SyncAssert(e.GetIsDir(), FROM_HERE,
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "Entry should be a directory",
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      trans))
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!SyncAssert(parentid.IsRoot(), FROM_HERE,
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "Entry should be root",
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      trans))
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         return false;
1178d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (!SyncAssert(!e.GetIsUnsynced(), FROM_HERE,
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "Entry should be sycned",
11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      trans))
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         return false;
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (!e.GetIsDel()) {
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!SyncAssert(id != parentid, FROM_HERE,
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "Id should be different from parent id.",
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      trans))
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         return false;
1190d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (!SyncAssert(!e.GetNonUniqueName().empty(), FROM_HERE,
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "Non unique name should not be empty.",
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      trans))
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int safety_count = handles.size() + 1;
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (!parentid.IsRoot()) {
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Entry parent(trans, GET_BY_ID, parentid);
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!SyncAssert(parent.good(), FROM_HERE,
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        "Parent entry is not valid.",
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        trans))
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
1201d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (handles.end() == handles.find(parent.GetMetahandle()))
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            break; // Skip further checking if parent was unmodified.
1203d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (!SyncAssert(parent.GetIsDir(), FROM_HERE,
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        "Parent should be a directory",
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        trans))
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
1207d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (!SyncAssert(!parent.GetIsDel(), FROM_HERE,
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        "Parent should not have been marked for deletion.",
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        trans))
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
1211d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (!SyncAssert(handles.end() != handles.find(parent.GetMetahandle()),
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        FROM_HERE,
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        "Parent should be in the index.",
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        trans))
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
1216d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        parentid = parent.GetParentId();
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!SyncAssert(--safety_count > 0, FROM_HERE,
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        "Count should be greater than zero.",
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        trans))
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1223d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    int64 base_version = e.GetBaseVersion();
1224d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    int64 server_version = e.GetServerVersion();
1225d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    bool using_unique_client_tag = !e.GetUniqueClientTag().empty();
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (CHANGES_VERSION == base_version || 0 == base_version) {
1227d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      if (e.GetIsUnappliedUpdate()) {
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Must be a new item, or a de-duplicated unique client tag
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // that was created both locally and remotely.
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!using_unique_client_tag) {
1231d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          if (!SyncAssert(e.GetIsDel(), FROM_HERE,
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          "The entry should not have been deleted.",
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          trans))
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return false;
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // It came from the server, so it must have a server ID.
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!SyncAssert(id.ServerKnows(), FROM_HERE,
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        "The id should be from a server.",
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        trans))
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
1242d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (e.GetIsDir()) {
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // TODO(chron): Implement this mode if clients ever need it.
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // For now, you can't combine a client tag and a directory.
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!SyncAssert(!using_unique_client_tag, FROM_HERE,
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          "Directory cannot have a client tag.",
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          trans))
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return false;
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Should be an uncomitted item, or a successfully deleted one.
1251d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (!e.GetIsDel()) {
1252d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          if (!SyncAssert(e.GetIsUnsynced(), FROM_HERE,
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          "The item should be unsynced.",
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          trans))
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return false;
12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the next check failed, it would imply that an item exists
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // on the server, isn't waiting for application locally, but either
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // is an unsynced create or a sucessful delete in the local copy.
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Either way, that's a mismatch.
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!SyncAssert(0 == server_version, FROM_HERE,
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        "Server version should be zero.",
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        trans))
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Items that aren't using the unique client tag should have a zero
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // base version only if they have a local ID.  Items with unique client
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // tags are allowed to use the zero base version for undeletion and
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // de-duplication; the unique client tag trumps the server ID.
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!using_unique_client_tag) {
12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (!SyncAssert(!id.ServerKnows(), FROM_HERE,
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          "Should be a client only id.",
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          trans))
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return false;
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!SyncAssert(id.ServerKnows(),
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      FROM_HERE,
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      "Should be a server id.",
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      trans))
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Server-unknown items that are locally deleted should not be sent up to
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the server.  They must be !IS_UNSYNCED.
1285d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    if (!SyncAssert(!(!id.ServerKnows() && e.GetIsDel() && e.GetIsUnsynced()),
1286d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                    FROM_HERE,
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "Locally deleted item must not be unsynced.",
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    trans)) {
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::SetInvariantCheckLevel(InvariantCheckLevel check_level) {
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  invariant_check_level_ = check_level;
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 Directory::NextMetahandle() {
13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 metahandle = (kernel_->next_metahandle)++;
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return metahandle;
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Always returns a client ID that is the string representation of a negative
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// number.
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Id Directory::NextId() {
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 result;
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScopedKernelLock lock(this);
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = (kernel_->persisted_info.next_id)--;
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kernel_->info_status = KERNEL_SHARE_INFO_DIRTY;
13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LT(result, 0);
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Id::CreateFromClientString(base::Int64ToString(result));
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Directory::HasChildren(BaseTransaction* trans, const Id& id) {
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
1320868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return kernel_->parent_child_index.GetChildren(id) != NULL;
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)Id Directory::GetFirstChildId(BaseTransaction* trans,
1324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              const EntryKernel* parent) {
1325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(parent);
1326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(parent->ref(IS_DIR));
1327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
1329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const OrderedChildSet* children =
1330868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->parent_child_index.GetChildren(parent->ref(ID));
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We're expected to return root if there are no children.
1333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!children)
1334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return Id();
1335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return (*children->begin())->ref(ID);
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)syncable::Id Directory::GetPredecessorId(EntryKernel* e) {
13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(ParentChildIndex::ShouldInclude(e));
1343c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const OrderedChildSet* children =
1344868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->parent_child_index.GetChildren(e->ref(PARENT_ID));
1345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(children && !children->empty());
1346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  OrderedChildSet::const_iterator i = children->find(e);
1347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(i != children->end());
1348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (i == children->begin()) {
1350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return Id();
1351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
1352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    i--;
1353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return (*i)->ref(ID);
13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)syncable::Id Directory::GetSuccessorId(EntryKernel* e) {
13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedKernelLock lock(this);
13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(ParentChildIndex::ShouldInclude(e));
1361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const OrderedChildSet* children =
1362868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->parent_child_index.GetChildren(e->ref(PARENT_ID));
1363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(children && !children->empty());
1364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  OrderedChildSet::const_iterator i = children->find(e);
1365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(i != children->end());
1366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  i++;
1368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (i == children->end()) {
1369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return Id();
1370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
1371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return (*i)->ref(ID);
1372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// TODO(rlarocque): Remove all support for placing ShouldMaintainPosition()
1376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// items as siblings of items that do not maintain postions.  It is required
1377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// only for tests.  See crbug.com/178282.
1378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void Directory::PutPredecessor(EntryKernel* e, EntryKernel* predecessor) {
1379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!e->ref(IS_DEL));
1380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!e->ShouldMaintainPosition()) {
1381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK(!e->ref(UNIQUE_POSITION).IsValid());
1382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string suffix = e->ref(UNIQUE_BOOKMARK_TAG);
1385c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!suffix.empty());
13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Remove our item from the ParentChildIndex and remember to re-add it later.
1388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ScopedKernelLock lock(this);
1389868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ScopedParentChildIndexUpdater updater(lock, e, &kernel_->parent_child_index);
1390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Note: The ScopedParentChildIndexUpdater will update this set for us as we
1392c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // leave this function.
1393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const OrderedChildSet* siblings =
1394868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->parent_child_index.GetChildren(e->ref(PARENT_ID));
1395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!siblings) {
1397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // This parent currently has no other children.
1398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DCHECK(predecessor->ref(ID).IsRoot());
1399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UniquePosition pos = UniquePosition::InitialPosition(suffix);
1400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    e->put(UNIQUE_POSITION, pos);
1401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (predecessor->ref(ID).IsRoot()) {
1405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // We have at least one sibling, and we're inserting to the left of them.
1406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UniquePosition successor_pos = (*siblings->begin())->ref(UNIQUE_POSITION);
1407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1408c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UniquePosition pos;
1409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!successor_pos.IsValid()) {
1410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // If all our successors are of non-positionable types, just create an
1411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // initial position.  We arbitrarily choose to sort invalid positions to
1412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // the right of the valid positions.
1413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      //
1414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // We really shouldn't need to support this.  See TODO above.
1415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pos = UniquePosition::InitialPosition(suffix);
1416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else  {
1417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      DCHECK(!siblings->empty());
1418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pos = UniquePosition::Before(successor_pos, suffix);
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    e->put(UNIQUE_POSITION, pos);
1422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We can't support placing an item after an invalid position.  Fortunately,
1426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // the tests don't exercise this particular case.  We should not support
1427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // siblings with invalid positions at all.  See TODO above.
1428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(predecessor->ref(UNIQUE_POSITION).IsValid());
1429c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1430c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  OrderedChildSet::const_iterator neighbour = siblings->find(predecessor);
1431c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(neighbour != siblings->end());
1432c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ++neighbour;
1434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (neighbour == siblings->end()) {
1435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Inserting at the end of the list.
1436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UniquePosition pos = UniquePosition::After(
1437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        predecessor->ref(UNIQUE_POSITION),
1438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        suffix);
1439c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    e->put(UNIQUE_POSITION, pos);
1440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EntryKernel* successor = *neighbour;
1444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Another mixed valid and invalid position case.  This one could be supported
1446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // in theory, but we're trying to deprecate support for siblings with and
1447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // without valid positions.  See TODO above.
1448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(successor->ref(UNIQUE_POSITION).IsValid());
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Finally, the normal case: inserting between two elements.
1451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UniquePosition pos = UniquePosition::Between(
1452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      predecessor->ref(UNIQUE_POSITION),
1453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      successor->ref(UNIQUE_POSITION),
1454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      suffix);
1455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  e->put(UNIQUE_POSITION, pos);
1456c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return;
14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1459c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// TODO(rlarocque): Avoid this indirection.  Just return the set.
14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Directory::AppendChildHandles(const ScopedKernelLock& lock,
14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const Id& parent_id,
1462868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                   Directory::Metahandles* result) {
1463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const OrderedChildSet* children =
1464868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kernel_->parent_child_index.GetChildren(parent_id);
1465c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!children)
1466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
1467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1468c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (OrderedChildSet::const_iterator i = children->begin();
1469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)       i != children->end(); ++i) {
14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(parent_id, (*i)->ref(PARENT_ID));
14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result->push_back((*i)->ref(META_HANDLE));
14725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid Directory::UnmarkDirtyEntry(WriteTransaction* trans, Entry* entry) {
1476116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CHECK(trans);
1477116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  entry->kernel_->clear_dirty(&kernel_->dirty_metahandles);
1478116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
1479116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
14801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid Directory::GetAttachmentIdsToUpload(BaseTransaction* trans,
14811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                         ModelType type,
14821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                         AttachmentIdSet* id_set) {
14831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(maniscalco): Maintain an index by ModelType and rewrite this method to
14841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // use it.  The approach below is likely very expensive because it iterates
14851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // all entries (bug 415199).
14861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(trans);
14871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(id_set);
14881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  id_set->clear();
14891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AttachmentIdSet on_server_id_set;
14901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AttachmentIdSet not_on_server_id_set;
14911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::vector<int64> metahandles;
14921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  {
14931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ScopedKernelLock lock(this);
14941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    GetMetaHandlesOfType(lock, trans, type, &metahandles);
14951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    std::vector<int64>::const_iterator iter = metahandles.begin();
14961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::vector<int64>::const_iterator end = metahandles.end();
14971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // For all of this type's entries...
14981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    for (; iter != end; ++iter) {
14991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      EntryKernel* entry = GetEntryByHandle(lock, *iter);
15001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      DCHECK(entry);
15011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      const sync_pb::AttachmentMetadata metadata =
15021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          entry->ref(ATTACHMENT_METADATA);
15031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // for each of this entry's attachments...
15041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      for (int i = 0; i < metadata.record_size(); ++i) {
15051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        AttachmentId id =
15061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            AttachmentId::CreateFromProto(metadata.record(i).id());
15071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        // if this attachment is known to be on the server, remember it for
15081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        // later,
15091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        if (metadata.record(i).is_on_server()) {
15101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          on_server_id_set.insert(id);
15111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        } else {
15121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          // otherwise, add it to id_set.
15131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          not_on_server_id_set.insert(id);
15141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }
15151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      }
15161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
15171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
15181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Why did we bother keeping a set of ids known to be on the server?  The
15191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // is_on_server flag is stored denormalized so we can end up with two entries
15201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // with the same attachment id where one says it's on the server and the other
15211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // says it's not.  When this happens, we trust the one that says it's on the
15221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // server.  To avoid re-uploading the same attachment mulitple times, we
15231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // remove any ids known to be on the server from the id_set we are about to
15241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // return.
15251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  //
15261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(maniscalco): Eliminate redundant metadata storage (bug 415203).
15271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::set_difference(not_on_server_id_set.begin(),
15281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      not_on_server_id_set.end(),
15291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      on_server_id_set.begin(),
15301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      on_server_id_set.end(),
15311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      std::inserter(*id_set, id_set->end()));
15321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
15331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
15345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace syncable
15355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace syncer
1536