| Index: chrome/browser/sync/syncable/syncable.cc
|
| diff --git a/chrome/browser/sync/syncable/syncable.cc b/chrome/browser/sync/syncable/syncable.cc
|
| index 0e119c48ba885489e80858e46f80587d5403eeb7..039ad4102cc827d274ca3263cce78cb682c56347 100644
|
| --- a/chrome/browser/sync/syncable/syncable.cc
|
| +++ b/chrome/browser/sync/syncable/syncable.cc
|
| @@ -36,6 +36,7 @@
|
| #include "base/string_util.h"
|
| #include "base/stl_util-inl.h"
|
| #include "base/time.h"
|
| +#include "base/tracked.h"
|
| #include "base/utf_string_conversions.h"
|
| #include "base/values.h"
|
| #include "chrome/browser/sync/engine/syncer.h"
|
| @@ -43,13 +44,15 @@
|
| #include "chrome/browser/sync/protocol/proto_value_conversions.h"
|
| #include "chrome/browser/sync/protocol/service_constants.h"
|
| #include "chrome/browser/sync/syncable/directory_backing_store.h"
|
| -#include "chrome/browser/sync/syncable/directory_change_listener.h"
|
| +#include "chrome/browser/sync/syncable/directory_change_delegate.h"
|
| #include "chrome/browser/sync/syncable/directory_manager.h"
|
| #include "chrome/browser/sync/syncable/model_type.h"
|
| #include "chrome/browser/sync/syncable/syncable-inl.h"
|
| #include "chrome/browser/sync/syncable/syncable_changes_version.h"
|
| #include "chrome/browser/sync/syncable/syncable_columns.h"
|
| #include "chrome/browser/sync/syncable/syncable_enum_conversions.h"
|
| +#include "chrome/browser/sync/syncable/transaction_observer.h"
|
| +#include "chrome/browser/sync/util/logging.h"
|
| #include "chrome/common/deprecated/event_sys-inl.h"
|
| #include "net/base/escape.h"
|
|
|
| @@ -323,9 +326,10 @@ DictionaryValue* EntryKernel::ToValue() const {
|
| ///////////////////////////////////////////////////////////////////////////
|
| // Directory
|
|
|
| -void Directory::init_kernel(const std::string& name) {
|
| +void Directory::InitKernel(const std::string& name,
|
| + DirectoryChangeDelegate* delegate) {
|
| DCHECK(kernel_ == NULL);
|
| - kernel_ = new Kernel(FilePath(), name, KernelLoadInfo());
|
| + kernel_ = new Kernel(FilePath(), name, KernelLoadInfo(), delegate);
|
| }
|
|
|
| Directory::PersistedKernelInfo::PersistedKernelInfo()
|
| @@ -356,7 +360,8 @@ Directory::SaveChangesSnapshot::~SaveChangesSnapshot() {}
|
|
|
| Directory::Kernel::Kernel(const FilePath& db_path,
|
| const string& name,
|
| - const KernelLoadInfo& info)
|
| + const KernelLoadInfo& info,
|
| + DirectoryChangeDelegate* delegate)
|
| : db_path(db_path),
|
| refcount(1),
|
| name(name),
|
| @@ -372,7 +377,10 @@ Directory::Kernel::Kernel(const FilePath& db_path,
|
| info_status(Directory::KERNEL_SHARE_INFO_VALID),
|
| persisted_info(info.kernel_info),
|
| cache_guid(info.cache_guid),
|
| - next_metahandle(info.max_metahandle + 1) {
|
| + next_metahandle(info.max_metahandle + 1),
|
| + delegate(delegate),
|
| + observers(new ObserverListThreadSafe<TransactionObserver>()) {
|
| + DCHECK(delegate);
|
| }
|
|
|
| void Directory::Kernel::AddRef() {
|
| @@ -384,33 +392,6 @@ void Directory::Kernel::Release() {
|
| delete this;
|
| }
|
|
|
| -void Directory::Kernel::AddChangeListener(
|
| - DirectoryChangeListener* listener) {
|
| - base::AutoLock lock(change_listeners_lock_);
|
| - change_listeners_.AddObserver(listener);
|
| -}
|
| -
|
| -void Directory::Kernel::RemoveChangeListener(
|
| - DirectoryChangeListener* listener) {
|
| - base::AutoLock lock(change_listeners_lock_);
|
| - change_listeners_.RemoveObserver(listener);
|
| -}
|
| -
|
| -// Note: it is possible that a listener will remove itself after we
|
| -// have made a copy, but before the copy is consumed. This could
|
| -// theoretically result in accessing a garbage pointer, but can only
|
| -// occur when an about:sync window is closed in the middle of a
|
| -// notification. See crbug.com/85481.
|
| -void Directory::Kernel::CopyChangeListeners(
|
| - ObserverList<DirectoryChangeListener>* change_listeners) {
|
| - DCHECK_EQ(0U, change_listeners->size());
|
| - base::AutoLock lock(change_listeners_lock_);
|
| - ObserverListBase<DirectoryChangeListener>::Iterator it(change_listeners_);
|
| - DirectoryChangeListener* obs;
|
| - while ((obs = it.GetNext()) != NULL)
|
| - change_listeners->AddObserver(obs);
|
| -}
|
| -
|
| Directory::Kernel::~Kernel() {
|
| CHECK_EQ(0, refcount);
|
| delete channel;
|
| @@ -432,8 +413,9 @@ Directory::~Directory() {
|
| Close();
|
| }
|
|
|
| -DirOpenResult Directory::Open(const FilePath& file_path, const string& name) {
|
| - const DirOpenResult result = OpenImpl(file_path, name);
|
| +DirOpenResult Directory::Open(const FilePath& file_path, const string& name,
|
| + DirectoryChangeDelegate* delegate) {
|
| + const DirOpenResult result = OpenImpl(file_path, name, delegate);
|
| if (OPENED != result)
|
| Close();
|
| return result;
|
| @@ -461,7 +443,8 @@ DirectoryBackingStore* Directory::CreateBackingStore(
|
| }
|
|
|
| DirOpenResult Directory::OpenImpl(const FilePath& file_path,
|
| - const string& name) {
|
| + const string& name,
|
| + DirectoryChangeDelegate* delegate) {
|
| DCHECK_EQ(static_cast<DirectoryBackingStore*>(NULL), store_);
|
| FilePath db_path(file_path);
|
| file_util::AbsolutePath(&db_path);
|
| @@ -475,7 +458,7 @@ DirOpenResult Directory::OpenImpl(const FilePath& file_path,
|
| if (OPENED != result)
|
| return result;
|
|
|
| - kernel_ = new Kernel(db_path, name, info);
|
| + kernel_ = new Kernel(db_path, name, info, delegate);
|
| kernel_->metahandles_index->swap(metas_bucket);
|
| InitializeIndices();
|
| return OPENED;
|
| @@ -671,7 +654,7 @@ bool Directory::SafeToPurgeFromMemory(const EntryKernel* const entry) const {
|
| }
|
|
|
| void Directory::TakeSnapshotForSaveChanges(SaveChangesSnapshot* snapshot) {
|
| - ReadTransaction trans(this, __FILE__, __LINE__);
|
| + ReadTransaction trans(this, FROM_HERE);
|
| ScopedKernelLock lock(this);
|
| // Deep copy dirty entries from kernel_->metahandles_index into snapshot and
|
| // clear dirty flags.
|
| @@ -729,7 +712,7 @@ bool Directory::SaveChanges() {
|
|
|
| void Directory::VacuumAfterSaveChanges(const SaveChangesSnapshot& snapshot) {
|
| // Need a write transaction as we are about to permanently purge entries.
|
| - WriteTransaction trans(this, VACUUM_AFTER_SAVE, __FILE__, __LINE__);
|
| + WriteTransaction trans(this, VACUUM_AFTER_SAVE, FROM_HERE);
|
| ScopedKernelLock lock(this);
|
| kernel_->flushed_metahandles.Push(0); // Begin flush marker
|
| // Now drop everything we can out of memory.
|
| @@ -770,7 +753,7 @@ void Directory::PurgeEntriesWithTypeIn(const std::set<ModelType>& types) {
|
| return;
|
|
|
| {
|
| - WriteTransaction trans(this, PURGE_ENTRIES, __FILE__, __LINE__);
|
| + WriteTransaction trans(this, PURGE_ENTRIES, FROM_HERE);
|
| {
|
| ScopedKernelLock lock(this);
|
| MetahandlesIndex::iterator it = kernel_->metahandles_index->begin();
|
| @@ -1186,12 +1169,12 @@ void Directory::CheckTreeInvariants(syncable::BaseTransaction* trans,
|
| }
|
| }
|
|
|
| -void Directory::AddChangeListener(DirectoryChangeListener* listener) {
|
| - kernel_->AddChangeListener(listener);
|
| +void Directory::AddTransactionObserver(TransactionObserver* observer) {
|
| + kernel_->observers->AddObserver(observer);
|
| }
|
|
|
| -void Directory::RemoveChangeListener(DirectoryChangeListener* listener) {
|
| - kernel_->RemoveChangeListener(listener);
|
| +void Directory::RemoveTransactionObserver(TransactionObserver* observer) {
|
| + kernel_->observers->RemoveObserver(observer);
|
| }
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
| @@ -1204,25 +1187,6 @@ ScopedKernelLock::ScopedKernelLock(const Directory* dir)
|
| ///////////////////////////////////////////////////////////////////////////
|
| // Transactions
|
|
|
| -// Helper functions/macros to do logging with a source file/line.
|
| -
|
| -namespace {
|
| -
|
| -bool VlogIsOn(const char* source_file, int verbose_level) {
|
| - return (verbose_level <=
|
| - logging::GetVlogLevelHelper(source_file, ::strlen(source_file)));
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -#define VLOG_SRC_STREAM(source_file, line, verbose_level) \
|
| - logging::LogMessage(source_file, line, -verbose_level).stream()
|
| -
|
| -#define VLOG_SRC(source_file, line, verbose_level) \
|
| - LAZY_STREAM(VLOG_SRC_STREAM(source_file, line, verbose_level), \
|
| - VLOG_IS_ON(verbose_level) || \
|
| - VlogIsOn(source_file, verbose_level))
|
| -
|
| void BaseTransaction::Lock() {
|
| base::TimeTicks start_time = base::TimeTicks::Now();
|
|
|
| @@ -1230,31 +1194,28 @@ void BaseTransaction::Lock() {
|
|
|
| time_acquired_ = base::TimeTicks::Now();
|
| const base::TimeDelta elapsed = time_acquired_ - start_time;
|
| - VLOG_SRC(source_file_, line_, 1)
|
| + VLOG_LOC(from_here_, 1)
|
| << name_ << " transaction waited "
|
| << elapsed.InSecondsF() << " seconds.";
|
| }
|
|
|
| -BaseTransaction::BaseTransaction(Directory* directory, const char* name,
|
| - const char* source_file, int line, WriterTag writer)
|
| +BaseTransaction::BaseTransaction(
|
| + Directory* directory, const char* name,
|
| + const tracked_objects::Location& from_here, WriterTag writer)
|
| : directory_(directory), dirkernel_(directory->kernel_), name_(name),
|
| - source_file_(source_file), line_(line), writer_(writer) {
|
| + from_here_(from_here), writer_(writer) {
|
| + dirkernel_->observers->Notify(
|
| + &TransactionObserver::OnTransactionStart, from_here_, writer_);
|
| Lock();
|
| }
|
|
|
| -BaseTransaction::BaseTransaction(Directory* directory)
|
| - : directory_(directory),
|
| - dirkernel_(NULL),
|
| - name_(NULL),
|
| - source_file_(NULL),
|
| - line_(0),
|
| - writer_(INVALID) {
|
| +BaseTransaction::~BaseTransaction() {
|
| + dirkernel_->observers->Notify(
|
| + &TransactionObserver::OnTransactionEnd, from_here_, writer_);
|
| }
|
|
|
| -BaseTransaction::~BaseTransaction() {}
|
| -
|
| void BaseTransaction::UnlockAndLog(OriginalEntries* entries) {
|
| - // Work while trasnaction mutex is held
|
| + // Work while transaction mutex is held
|
| ModelTypeBitSet models_with_changes;
|
| if (!NotifyTransactionChangingAndEnding(entries, &models_with_changes))
|
| return;
|
| @@ -1270,50 +1231,32 @@ bool BaseTransaction::NotifyTransactionChangingAndEnding(
|
|
|
| scoped_ptr<OriginalEntries> originals(entries);
|
| const base::TimeDelta elapsed = base::TimeTicks::Now() - time_acquired_;
|
| - VLOG_SRC(source_file_, line_, 1)
|
| + VLOG_LOC(from_here_, 1)
|
| << name_ << " transaction completed in " << elapsed.InSecondsF()
|
| << " seconds.";
|
|
|
| - ObserverList<DirectoryChangeListener> change_listeners;
|
| - dirkernel_->CopyChangeListeners(&change_listeners);
|
| -
|
| - if (NULL == originals.get() || originals->empty() ||
|
| - (change_listeners.size() == 0)) {
|
| + if (NULL == originals.get() || originals->empty()) {
|
| dirkernel_->transaction_mutex.Release();
|
| return false;
|
| }
|
|
|
| + DirectoryChangeDelegate* const delegate = dirkernel_->delegate;
|
| if (writer_ == syncable::SYNCAPI) {
|
| - FOR_EACH_OBSERVER(DirectoryChangeListener,
|
| - change_listeners,
|
| - HandleCalculateChangesChangeEventFromSyncApi(
|
| - *originals.get(),
|
| - writer_,
|
| - this));
|
| + delegate->HandleCalculateChangesChangeEventFromSyncApi(*originals, this);
|
| } else {
|
| - FOR_EACH_OBSERVER(DirectoryChangeListener,
|
| - change_listeners,
|
| - HandleCalculateChangesChangeEventFromSyncer(
|
| - *originals.get(),
|
| - writer_,
|
| - this));
|
| + delegate->HandleCalculateChangesChangeEventFromSyncer(*originals, this);
|
| }
|
|
|
| - // Set |*models_with_changes| to the union of the return values of
|
| - // the HandleTransactionEndingChangeEvent call to each
|
| - // DirectoryChangeListener.
|
| - {
|
| - ObserverList<DirectoryChangeListener>::Iterator it(change_listeners);
|
| - DirectoryChangeListener* obs = NULL;
|
| - while ((obs = it.GetNext()) != NULL) {
|
| - *models_with_changes |= obs->HandleTransactionEndingChangeEvent(this);
|
| - }
|
| - };
|
| + *models_with_changes = delegate->HandleTransactionEndingChangeEvent(this);
|
| +
|
| + dirkernel_->observers->Notify(
|
| + &TransactionObserver::OnTransactionMutate,
|
| + from_here_, writer_, *originals, *models_with_changes);
|
|
|
| // Release the transaction. Note, once the transaction is released this thread
|
| // can be interrupted by another that was waiting for the transaction,
|
| // resulting in this code possibly being interrupted with another thread
|
| - // performing following the same code path. From this point foward, only
|
| + // performing following the same code path. From this point forward, only
|
| // local state can be touched.
|
| dirkernel_->transaction_mutex.Release();
|
| return true;
|
| @@ -1321,26 +1264,22 @@ bool BaseTransaction::NotifyTransactionChangingAndEnding(
|
|
|
| void BaseTransaction::NotifyTransactionComplete(
|
| ModelTypeBitSet models_with_changes) {
|
| - ObserverList<DirectoryChangeListener> change_listeners;
|
| - dirkernel_->CopyChangeListeners(&change_listeners);
|
| - FOR_EACH_OBSERVER(DirectoryChangeListener,
|
| - change_listeners,
|
| - HandleTransactionCompleteChangeEvent(
|
| - models_with_changes));
|
| + dirkernel_->delegate->HandleTransactionCompleteChangeEvent(
|
| + models_with_changes);
|
| }
|
|
|
| -#undef VLOG_SRC
|
| +#undef VLOG_LOC
|
|
|
| -#undef VLOG_SRC_STREAM
|
| +#undef VLOG_LOC_STREAM
|
|
|
| -ReadTransaction::ReadTransaction(Directory* directory, const char* file,
|
| - int line)
|
| - : BaseTransaction(directory, "Read", file, line, INVALID) {
|
| +ReadTransaction::ReadTransaction(Directory* directory,
|
| + const tracked_objects::Location& location)
|
| + : BaseTransaction(directory, "Read", location, INVALID) {
|
| }
|
|
|
| ReadTransaction::ReadTransaction(const ScopedDirLookup& scoped_dir,
|
| - const char* file, int line)
|
| - : BaseTransaction(scoped_dir.operator -> (), "Read", file, line, INVALID) {
|
| + const tracked_objects::Location& location)
|
| + : BaseTransaction(scoped_dir.operator -> (), "Read", location, INVALID) {
|
| }
|
|
|
| ReadTransaction::~ReadTransaction() {
|
| @@ -1348,22 +1287,18 @@ ReadTransaction::~ReadTransaction() {
|
| }
|
|
|
| WriteTransaction::WriteTransaction(Directory* directory, WriterTag writer,
|
| - const char* file, int line)
|
| - : BaseTransaction(directory, "Write", file, line, writer),
|
| + const tracked_objects::Location& location)
|
| + : BaseTransaction(directory, "Write", location, writer),
|
| originals_(new OriginalEntries) {
|
| }
|
|
|
| WriteTransaction::WriteTransaction(const ScopedDirLookup& scoped_dir,
|
| - WriterTag writer, const char* file, int line)
|
| - : BaseTransaction(scoped_dir.operator -> (), "Write", file, line, writer),
|
| + WriterTag writer,
|
| + const tracked_objects::Location& location)
|
| + : BaseTransaction(scoped_dir.operator -> (), "Write", location, writer),
|
| originals_(new OriginalEntries) {
|
| }
|
|
|
| -WriteTransaction::WriteTransaction(Directory *directory)
|
| - : BaseTransaction(directory),
|
| - originals_(new OriginalEntries) {
|
| -}
|
| -
|
| void WriteTransaction::SaveOriginal(EntryKernel* entry) {
|
| if (NULL == entry)
|
| return;
|
|
|