Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(400)

Unified Diff: sync/internal_api/attachments/attachment_uploader_impl.cc

Issue 556083002: Eliminate use of 'delete self' pattern in AttachmentUploaderImpl. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@persistentuploads-retry
Patch Set: Merge with master. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | sync/internal_api/public/attachments/attachment_uploader_impl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sync/internal_api/attachments/attachment_uploader_impl.cc
diff --git a/sync/internal_api/attachments/attachment_uploader_impl.cc b/sync/internal_api/attachments/attachment_uploader_impl.cc
index 59885b76d8854aa2ae967cd33ae060cda3f34b86..5ca330435b7a3c53422f1106edb400b0b69674b5 100644
--- a/sync/internal_api/attachments/attachment_uploader_impl.cc
+++ b/sync/internal_api/attachments/attachment_uploader_impl.cc
@@ -5,6 +5,7 @@
#include "sync/internal_api/public/attachments/attachment_uploader_impl.h"
#include "base/bind.h"
+#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/threading/non_thread_safe.h"
#include "google_apis/gaia/gaia_constants.h"
@@ -31,8 +32,12 @@ class AttachmentUploaderImpl::UploadState : public net::URLFetcherDelegate,
public:
// Construct an UploadState.
//
- // |owner| is a pointer to the object that will own (and must outlive!) this
- // |UploadState.
+ // UploadState encapsulates the state associated with a single upload. When
+ // the upload completes, the UploadState object becomes "stopped".
+ //
+ // |owner| is a pointer to the object that owns this UploadState. Upon
+ // completion this object will PostTask to owner's OnUploadStateStopped
+ // method.
UploadState(
const GURL& upload_url,
const scoped_refptr<net::URLRequestContextGetter>&
@@ -42,12 +47,19 @@ class AttachmentUploaderImpl::UploadState : public net::URLFetcherDelegate,
const std::string& account_id,
const OAuth2TokenService::ScopeSet& scopes,
OAuth2TokenServiceRequest::TokenServiceProvider* token_service_provider,
- AttachmentUploaderImpl* owner);
+ const base::WeakPtr<AttachmentUploaderImpl>& owner);
virtual ~UploadState();
+ // Returns true if this object is stopped. Once stopped, this object is
+ // effectively dead and can be destroyed.
+ bool IsStopped() const;
+
// Add |user_callback| to the list of callbacks to be invoked when this upload
// completed.
+ //
+ // It is an error to call |AddUserCallback| on a stopped UploadState (see
+ // |IsStopped|).
void AddUserCallback(const UploadCallback& user_callback);
// Return the Attachment this object is uploading.
@@ -68,9 +80,10 @@ class AttachmentUploaderImpl::UploadState : public net::URLFetcherDelegate,
void GetToken();
- void ReportResult(const UploadResult& result,
- const AttachmentId& attachment_id);
+ void StopAndReportResult(const UploadResult& result,
+ const AttachmentId& attachment_id);
+ bool is_stopped_;
GURL upload_url_;
const scoped_refptr<net::URLRequestContextGetter>&
url_request_context_getter_;
@@ -82,7 +95,7 @@ class AttachmentUploaderImpl::UploadState : public net::URLFetcherDelegate,
std::string access_token_;
OAuth2TokenServiceRequest::TokenServiceProvider* token_service_provider_;
// Pointer to the AttachmentUploaderImpl that owns this object.
- AttachmentUploaderImpl* owner_;
+ base::WeakPtr<AttachmentUploaderImpl> owner_;
scoped_ptr<OAuth2TokenServiceRequest> access_token_request_;
DISALLOW_COPY_AND_ASSIGN(UploadState);
@@ -97,8 +110,9 @@ AttachmentUploaderImpl::UploadState::UploadState(
const std::string& account_id,
const OAuth2TokenService::ScopeSet& scopes,
OAuth2TokenServiceRequest::TokenServiceProvider* token_service_provider,
- AttachmentUploaderImpl* owner)
+ const base::WeakPtr<AttachmentUploaderImpl>& owner)
: OAuth2TokenService::Consumer("attachment-uploader-impl"),
+ is_stopped_(false),
upload_url_(upload_url),
url_request_context_getter_(url_request_context_getter),
attachment_(attachment),
@@ -112,16 +126,21 @@ AttachmentUploaderImpl::UploadState::UploadState(
DCHECK(!account_id_.empty());
DCHECK(!scopes_.empty());
DCHECK(token_service_provider_);
- DCHECK(owner_);
GetToken();
}
AttachmentUploaderImpl::UploadState::~UploadState() {
}
+bool AttachmentUploaderImpl::UploadState::IsStopped() const {
+ DCHECK(CalledOnValidThread());
+ return is_stopped_;
+}
+
void AttachmentUploaderImpl::UploadState::AddUserCallback(
const UploadCallback& user_callback) {
DCHECK(CalledOnValidThread());
+ DCHECK(!is_stopped_);
user_callbacks_.push_back(user_callback);
}
@@ -133,6 +152,10 @@ const Attachment& AttachmentUploaderImpl::UploadState::GetAttachment() {
void AttachmentUploaderImpl::UploadState::OnURLFetchComplete(
const net::URLFetcher* source) {
DCHECK(CalledOnValidThread());
+ if (is_stopped_) {
+ return;
+ }
+
UploadResult result = UPLOAD_TRANSIENT_ERROR;
AttachmentId attachment_id = attachment_.GetId();
const int response_code = source->GetResponseCode();
@@ -150,13 +173,18 @@ void AttachmentUploaderImpl::UploadState::OnURLFetchComplete(
} else if (response_code == net::URLFetcher::RESPONSE_CODE_INVALID) {
result = UPLOAD_TRANSIENT_ERROR;
}
- ReportResult(result, attachment_id);
+ StopAndReportResult(result, attachment_id);
}
void AttachmentUploaderImpl::UploadState::OnGetTokenSuccess(
const OAuth2TokenService::Request* request,
const std::string& access_token,
const base::Time& expiration_time) {
+ DCHECK(CalledOnValidThread());
+ if (is_stopped_) {
+ return;
+ }
+
DCHECK_EQ(access_token_request_.get(), request);
access_token_request_.reset();
access_token_ = access_token;
@@ -185,13 +213,18 @@ void AttachmentUploaderImpl::UploadState::OnGetTokenSuccess(
void AttachmentUploaderImpl::UploadState::OnGetTokenFailure(
const OAuth2TokenService::Request* request,
const GoogleServiceAuthError& error) {
+ DCHECK(CalledOnValidThread());
+ if (is_stopped_) {
+ return;
+ }
+
DCHECK_EQ(access_token_request_.get(), request);
access_token_request_.reset();
// TODO(maniscalco): We treat this as a transient error, but it may in fact be
// a very long lived error and require user action. Consider differentiating
// between the causes of GetToken failure and act accordingly. Think about
// the causes of GetToken failure. Are there (bug 412802).
- ReportResult(UPLOAD_TRANSIENT_ERROR, attachment_.GetId());
+ StopAndReportResult(UPLOAD_TRANSIENT_ERROR, attachment_.GetId());
}
void AttachmentUploaderImpl::UploadState::GetToken() {
@@ -199,18 +232,22 @@ void AttachmentUploaderImpl::UploadState::GetToken() {
token_service_provider_, account_id_, scopes_, this);
}
-void AttachmentUploaderImpl::UploadState::ReportResult(
+void AttachmentUploaderImpl::UploadState::StopAndReportResult(
const UploadResult& result,
const AttachmentId& attachment_id) {
+ DCHECK(!is_stopped_);
+ is_stopped_ = true;
UploadCallbackList::const_iterator iter = user_callbacks_.begin();
UploadCallbackList::const_iterator end = user_callbacks_.end();
for (; iter != end; ++iter) {
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(*iter, result, attachment_id));
}
- // Destroy this object and return immediately.
- owner_->DeleteUploadStateFor(attachment_.GetId().GetProto().unique_id());
- return;
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&AttachmentUploaderImpl::OnUploadStateStopped,
+ owner_,
+ attachment_id.GetProto().unique_id()));
}
AttachmentUploaderImpl::AttachmentUploaderImpl(
@@ -225,7 +262,8 @@ AttachmentUploaderImpl::AttachmentUploaderImpl(
url_request_context_getter_(url_request_context_getter),
account_id_(account_id),
scopes_(scopes),
- token_service_provider_(token_service_provider) {
+ token_service_provider_(token_service_provider),
+ weak_ptr_factory_(this) {
DCHECK(CalledOnValidThread());
DCHECK(!account_id.empty());
DCHECK(!scopes.empty());
@@ -243,24 +281,31 @@ void AttachmentUploaderImpl::UploadAttachment(const Attachment& attachment,
const std::string unique_id = attachment_id.GetProto().unique_id();
DCHECK(!unique_id.empty());
StateMap::iterator iter = state_map_.find(unique_id);
- if (iter == state_map_.end()) {
- const GURL url = GetURLForAttachmentId(sync_service_url_, attachment_id);
- scoped_ptr<UploadState> upload_state(
- new UploadState(url,
- url_request_context_getter_,
- attachment,
- callback,
- account_id_,
- scopes_,
- token_service_provider_.get(),
- this));
- state_map_.add(unique_id, upload_state.Pass());
- } else {
- DCHECK(
- attachment.GetData()->Equals(iter->second->GetAttachment().GetData()));
- // We already have an upload for this attachment. "Join" it.
- iter->second->AddUserCallback(callback);
+ if (iter != state_map_.end()) {
+ // We have an old upload request for this attachment...
+ if (!iter->second->IsStopped()) {
+ // "join" to it.
+ DCHECK(attachment.GetData()
+ ->Equals(iter->second->GetAttachment().GetData()));
+ iter->second->AddUserCallback(callback);
+ return;
+ } else {
+ // It's stopped so we can't use it. Delete it.
+ state_map_.erase(iter);
+ }
}
+
+ const GURL url = GetURLForAttachmentId(sync_service_url_, attachment_id);
+ scoped_ptr<UploadState> upload_state(
+ new UploadState(url,
+ url_request_context_getter_,
+ attachment,
+ callback,
+ account_id_,
+ scopes_,
+ token_service_provider_.get(),
+ weak_ptr_factory_.GetWeakPtr()));
+ state_map_.add(unique_id, upload_state.Pass());
}
// Static.
@@ -278,8 +323,15 @@ GURL AttachmentUploaderImpl::GetURLForAttachmentId(
return sync_service_url.ReplaceComponents(replacements);
}
-void AttachmentUploaderImpl::DeleteUploadStateFor(const UniqueId& unique_id) {
- state_map_.erase(unique_id);
+void AttachmentUploaderImpl::OnUploadStateStopped(const UniqueId& unique_id) {
+ StateMap::iterator iter = state_map_.find(unique_id);
+ // Only erase if stopped. Because this method is called asynchronously, it's
+ // possible that a new request for this same id arrived after the UploadState
+ // stopped, but before this method was invoked. In that case the UploadState
+ // in the map might be a new one.
+ if (iter != state_map_.end() && iter->second->IsStopped()) {
+ state_map_.erase(iter);
+ }
}
} // namespace syncer
« no previous file with comments | « no previous file | sync/internal_api/public/attachments/attachment_uploader_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698