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

Unified Diff: chrome/browser/prerender/prerender_manager.cc

Issue 98373010: Refactor prerender pending swap logic. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: I can order correctly words Created 7 years 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 | « chrome/browser/prerender/prerender_manager.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/prerender/prerender_manager.cc
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index ec44cfdcdbde4bdd4fcf07fa5494da34c814e4e1..deba1a9e095e3d9b3c9de9abacad01f91baeeae4 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -434,102 +434,6 @@ void PrerenderManager::CancelAllPrerenders() {
}
}
-void PrerenderManager::ProcessMergeResult(
- PrerenderData* prerender_data,
- bool timed_out,
- content::SessionStorageNamespace::MergeResult result) {
- PendingSwap* pending_swap = prerender_data->pending_swap();
- DCHECK(pending_swap);
- // No pending_swap should never happen. If it does anyways (in a retail
- // build), log this and bail.
- if (!pending_swap) {
- RecordEvent(prerender_data->contents(),
- PRERENDER_EVENT_MERGE_RESULT_NO_PENDING_SWAPIN);
- return;
- }
- if (timed_out) {
- RecordEvent(prerender_data->contents(),
- PRERENDER_EVENT_MERGE_RESULT_TIMEOUT_CB);
- } else {
- RecordEvent(prerender_data->contents(),
- PRERENDER_EVENT_MERGE_RESULT_RESULT_CB);
- UMA_HISTOGRAM_TIMES("Prerender.SessionStorageNamespaceMergeTime",
- pending_swap->GetElapsedTime());
- }
-
- // Any return here must call ClearPendingSwap on |prerender_data| before
- // returning, with one exception: when the prerender was ultimately swapped
- // in. In that case, SwapInternal will take care of deleting
- // |prerender_data| and sending the appropriate notifications to the tracker.
- if (timed_out) {
- RecordEvent(prerender_data->contents(),
- PRERENDER_EVENT_MERGE_RESULT_TIMED_OUT);
- prerender_data->ClearPendingSwap();
- return;
- }
-
- RecordEvent(prerender_data->contents(),
- PRERENDER_EVENT_MERGE_RESULT_MERGE_DONE);
-
- // Log the exact merge result in a histogram.
- switch (result) {
- case content::SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_FOUND:
- RecordEvent(prerender_data->contents(),
- PRERENDER_EVENT_MERGE_RESULT_RESULT_NAMESPACE_NOT_FOUND);
- break;
- case content::SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_ALIAS:
- RecordEvent(prerender_data->contents(),
- PRERENDER_EVENT_MERGE_RESULT_RESULT_NAMESPACE_NOT_ALIAS);
- break;
- case content::SessionStorageNamespace::MERGE_RESULT_NOT_LOGGING:
- RecordEvent(prerender_data->contents(),
- PRERENDER_EVENT_MERGE_RESULT_RESULT_NOT_LOGGING);
- break;
- case content::SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS:
- RecordEvent(prerender_data->contents(),
- PRERENDER_EVENT_MERGE_RESULT_RESULT_NO_TRANSACTIONS);
- break;
- case content::SessionStorageNamespace::MERGE_RESULT_TOO_MANY_TRANSACTIONS:
- RecordEvent(prerender_data->contents(),
- PRERENDER_EVENT_MERGE_RESULT_RESULT_TOO_MANY_TRANSACTIONS);
- break;
- case content::SessionStorageNamespace::MERGE_RESULT_NOT_MERGEABLE:
- RecordEvent(prerender_data->contents(),
- PRERENDER_EVENT_MERGE_RESULT_RESULT_NOT_MERGEABLE);
- break;
- case content::SessionStorageNamespace::MERGE_RESULT_MERGEABLE:
- RecordEvent(prerender_data->contents(),
- PRERENDER_EVENT_MERGE_RESULT_RESULT_MERGEABLE);
- break;
- default:
- NOTREACHED();
- }
-
- if (result != content::SessionStorageNamespace::MERGE_RESULT_MERGEABLE &&
- result !=
- content::SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS) {
- RecordEvent(prerender_data->contents(),
- PRERENDER_EVENT_MERGE_RESULT_MERGE_FAILED);
- prerender_data->ClearPendingSwap();
- return;
- }
-
- RecordEvent(prerender_data->contents(),
- PRERENDER_EVENT_MERGE_RESULT_SWAPPING_IN);
- // Notice that SwapInInternal, on success, will delete |prerender_data|
- // and |pending_swap|. Therefore, we have to pass a new GURL object rather
- // than a reference to the one in |pending_swap|.
- content::WebContents* new_web_contents =
- SwapInternal(GURL(pending_swap->url()),
- pending_swap->target_contents(),
- prerender_data);
- if (!new_web_contents) {
- RecordEvent(prerender_data->contents(),
- PRERENDER_EVENT_MERGE_RESULT_SWAPIN_FAILED);
- prerender_data->ClearPendingSwap();
- }
-}
-
bool PrerenderManager::MaybeUsePrerenderedPage(const GURL& url,
chrome::NavigateParams* params) {
DCHECK(CalledOnValidThread());
@@ -541,37 +445,12 @@ bool PrerenderManager::MaybeUsePrerenderedPage(const GURL& url,
if (params->uses_post || !params->extra_headers.empty())
return false;
- content::WebContents* new_web_contents = SwapInternal(url, web_contents,
- NULL);
- if (!new_web_contents)
- return false;
-
- // Record the new target_contents for the callers.
- params->target_contents = new_web_contents;
- return true;
-}
-
-content::WebContents* PrerenderManager::SwapInternal(
- const GURL& url,
- content::WebContents* web_contents,
- PrerenderData* swap_candidate) {
- DCHECK(CalledOnValidThread());
- DCHECK(!IsWebContentsPrerendering(web_contents, NULL));
-
DeleteOldEntries();
to_delete_prerenders_.clear();
- // TODO(ajwong): This doesn't handle isolated apps correctly.
-
- // Only if this WebContents is used in a tabstrip may be swap.
- // We check this by examining whether its CoreTabHelper has a delegate.
- CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents);
- if (!core_tab_helper || !core_tab_helper->delegate()) {
- RecordEvent(NULL, PRERENDER_EVENT_SWAPIN_NO_DELEGATE);
- return NULL;
- }
// First, try to find prerender data with the correct session storage
// namespace.
+ // TODO(ajwong): This doesn't handle isolated apps correctly.
PrerenderData* prerender_data = FindPrerenderData(
url,
web_contents->GetController().GetDefaultSessionStorageNamespace());
@@ -587,16 +466,15 @@ content::WebContents* PrerenderManager::SwapInternal(
}
if (!prerender_data)
- return NULL;
+ return false;
RecordEvent(prerender_data->contents(), PRERENDER_EVENT_SWAPIN_CANDIDATE);
DCHECK(prerender_data->contents());
// If there is currently a merge pending for this prerender data,
// or this webcontents, do not swap in, but give the merge a chance to
// finish and swap into the intended target webcontents.
- if (prerender_data != swap_candidate && prerender_data->pending_swap()) {
- return NULL;
- }
+ if (prerender_data->pending_swap())
+ return false;
RecordEvent(prerender_data->contents(),
PRERENDER_EVENT_SWAPIN_NO_MERGE_PENDING);
@@ -611,46 +489,42 @@ content::WebContents* PrerenderManager::SwapInternal(
if (!ShouldMergeSessionStorageNamespaces()) {
RecordEvent(prerender_data->contents(),
PRERENDER_EVENT_SWAPIN_MERGING_DISABLED);
- return NULL;
+ return false;
}
RecordEvent(prerender_data->contents(),
PRERENDER_EVENT_SWAPIN_ISSUING_MERGE);
- // There should never be a |pending_swap| if we get to here:
- // Per check above, |pending_swap| may only be != NULL when
- // processing a successful merge, as indicated by |swap_candidate|
- // != NULL. But in that case, there should be no need for yet another merge.
- DCHECK(!prerender_data->pending_swap());
- if (prerender_data->pending_swap()) {
- // In retail builds, log this error and bail.
- RecordEvent(prerender_data->contents(),
- PRERENDER_EVENT_MERGE_FOR_SWAPIN_CANDIDATE);
- return NULL;
- }
- PendingSwap* pending_swap = new PendingSwap(
- prerender_tracker_,
- web_contents,
- prerender_data,
- url,
- base::Bind(&PrerenderManager::ProcessMergeResult,
- AsWeakPtr(),
- prerender_data,
- true,
- SessionStorageNamespace::MERGE_RESULT_NOT_MERGEABLE),
- base::Bind(&PrerenderManager::ProcessMergeResult,
- AsWeakPtr(),
- prerender_data,
- false));
- prerender_data->set_pending_swap(pending_swap);
- prerender_namespace->Merge(
- true,
- prerender_data->contents()->child_id(),
- target_namespace,
- pending_swap->GetMergeResultCallback());
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- pending_swap->GetTimeoutCallback(),
- base::TimeDelta::FromMilliseconds(
- kSessionStorageNamespaceMergeTimeoutMs));
+ prerender_data->set_pending_swap(new PendingSwap(
+ this, web_contents, prerender_data, url));
+ prerender_data->pending_swap()->BeginSwap();
+ // Although this returns false, creating a PendingSwap registers with
+ // PrerenderTracker to throttle MAIN_FRAME navigations while the swap is
+ // pending.
+ return false;
+ }
+
+ // No need to merge; swap synchronously.
+ WebContents* new_web_contents = SwapInternal(url, web_contents,
+ prerender_data);
+ if (!new_web_contents)
+ return false;
+
+ // Record the new target_contents for the callers.
+ params->target_contents = new_web_contents;
+ return true;
+}
+
+WebContents* PrerenderManager::SwapInternal(
+ const GURL& url,
+ WebContents* web_contents,
+ PrerenderData* prerender_data) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(!IsWebContentsPrerendering(web_contents, NULL));
+
+ // Only swap if the target WebContents has a CoreTabHelper delegate to swap
+ // out of it. For a normal WebContents, this is if it is in a TabStripModel.
+ CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents);
+ if (!core_tab_helper || !core_tab_helper->delegate()) {
+ RecordEvent(prerender_data->contents(), PRERENDER_EVENT_SWAPIN_NO_DELEGATE);
return NULL;
}
@@ -734,7 +608,7 @@ content::WebContents* PrerenderManager::SwapInternal(
// At this point, we've determined that we will use the prerender.
if (prerender_data->pending_swap())
- prerender_data->pending_swap()->SwapSuccessful();
+ prerender_data->pending_swap()->set_swap_successful(true);
ScopedVector<PrerenderData>::iterator to_erase =
FindIteratorForPrerenderContents(prerender_data->contents());
DCHECK(active_prerenders_.end() != to_erase);
@@ -851,7 +725,6 @@ void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry,
(*it)->MakeIntoMatchCompleteReplacement();
} else {
to_delete_prerenders_.push_back(*it);
- (*it)->ClearPendingSwap();
active_prerenders_.weak_erase(it);
}
@@ -1282,45 +1155,45 @@ PrerenderContents* PrerenderManager::PrerenderData::ReleaseContents() {
}
PrerenderManager::PendingSwap::PendingSwap(
- PrerenderTracker* prerender_tracker,
+ PrerenderManager* manager,
content::WebContents* target_contents,
PrerenderData* prerender_data,
- const GURL& url,
- const base::Closure& timeout_cb,
- const SessionStorageNamespace::MergeResultCallback& merge_result_cb)
+ const GURL& url)
: content::WebContentsObserver(target_contents),
- prerender_tracker_(prerender_tracker),
+ manager_(manager),
target_contents_(target_contents),
prerender_data_(prerender_data),
url_(url),
- timeout_cb_(timeout_cb),
- merge_result_cb_(merge_result_cb),
- start_time_(base::TimeTicks::Now()) {
+ start_time_(base::TimeTicks::Now()),
+ swap_successful_(false),
+ weak_factory_(this) {
RenderViewCreated(target_contents->GetRenderViewHost());
}
PrerenderManager::PendingSwap::~PendingSwap() {
- timeout_cb_.Cancel();
- merge_result_cb_.Cancel();
- for (size_t i = 0; i < rvh_ids_.size(); i++) {
- prerender_tracker_->RemovePrerenderPendingSwap(rvh_ids_[i], false);
- }
-}
-
-const base::Closure& PrerenderManager::PendingSwap::GetTimeoutCallback() {
- return timeout_cb_.callback();
-}
-
-void PrerenderManager::PendingSwap::SwapSuccessful() {
for (size_t i = 0; i < rvh_ids_.size(); i++) {
- prerender_tracker_->RemovePrerenderPendingSwap(rvh_ids_[i], true);
+ manager_->prerender_tracker()->RemovePrerenderPendingSwap(
+ rvh_ids_[i], swap_successful_);
}
- rvh_ids_.clear();
}
-const SessionStorageNamespace::MergeResultCallback&
-PrerenderManager::PendingSwap::GetMergeResultCallback() {
- return merge_result_cb_.callback();
+void PrerenderManager::PendingSwap::BeginSwap() {
+ SessionStorageNamespace* target_namespace =
+ target_contents_->GetController().GetDefaultSessionStorageNamespace();
+ SessionStorageNamespace* prerender_namespace =
+ prerender_data_->contents()->GetSessionStorageNamespace();
+
+ prerender_namespace->Merge(
+ true, prerender_data_->contents()->child_id(),
+ target_namespace,
+ base::Bind(&PrerenderManager::PendingSwap::OnMergeCompleted,
+ weak_factory_.GetWeakPtr()));
+
+ merge_timeout_.Start(
+ FROM_HERE,
+ base::TimeDelta::FromMilliseconds(
+ kSessionStorageNamespaceMergeTimeoutMs),
+ this, &PrerenderManager::PendingSwap::OnMergeTimeout);
}
void PrerenderManager::PendingSwap::ProvisionalChangeToMainFrameUrl(
@@ -1343,17 +1216,19 @@ void PrerenderManager::PendingSwap::DidCommitProvisionalLoadForFrame(
content::RenderViewHost* render_view_host){
if (!is_main_frame)
return;
- if (validated_url != url_)
- prerender_data_->ClearPendingSwap();
+ prerender_data_->ClearPendingSwap();
}
void PrerenderManager::PendingSwap::RenderViewCreated(
content::RenderViewHost* render_view_host) {
+ // Record the RVH id in the tracker to install throttles on MAIN_FRAME
+ // requests from that route.
int child_id = render_view_host->GetProcess()->GetID();
int route_id = render_view_host->GetRoutingID();
PrerenderTracker::ChildRouteIdPair child_route_id_pair(child_id, route_id);
rvh_ids_.push_back(child_route_id_pair);
- prerender_tracker_->AddPrerenderPendingSwap(child_route_id_pair, url_);
+ manager_->prerender_tracker()->AddPrerenderPendingSwap(
+ child_route_id_pair, url_);
}
void PrerenderManager::PendingSwap::DidFailProvisionalLoad(
@@ -1364,6 +1239,8 @@ void PrerenderManager::PendingSwap::DidFailProvisionalLoad(
int error_code,
const string16& error_description,
content::RenderViewHost* render_view_host) {
+ if (!is_main_frame)
+ return;
prerender_data_->ClearPendingSwap();
}
@@ -1372,8 +1249,67 @@ void PrerenderManager::PendingSwap::WebContentsDestroyed(
prerender_data_->ClearPendingSwap();
}
-base::TimeDelta PrerenderManager::PendingSwap::GetElapsedTime() {
- return base::TimeTicks::Now() - start_time_;
+void PrerenderManager::PendingSwap::RecordEvent(PrerenderEvent event) const {
+ manager_->RecordEvent(prerender_data_->contents(), event);
+}
+
+void PrerenderManager::PendingSwap::OnMergeCompleted(
+ SessionStorageNamespace::MergeResult result) {
+ UMA_HISTOGRAM_TIMES("Prerender.SessionStorageNamespaceMergeTime",
+ base::TimeTicks::Now() - start_time_);
+ RecordEvent(PRERENDER_EVENT_MERGE_RESULT_MERGE_DONE);
+
+ // Log the exact merge result in a histogram.
+ switch (result) {
+ case SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_FOUND:
+ RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_NAMESPACE_NOT_FOUND);
+ break;
+ case SessionStorageNamespace::MERGE_RESULT_NAMESPACE_NOT_ALIAS:
+ RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_NAMESPACE_NOT_ALIAS);
+ break;
+ case SessionStorageNamespace::MERGE_RESULT_NOT_LOGGING:
+ RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_NOT_LOGGING);
+ break;
+ case SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS:
+ RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_NO_TRANSACTIONS);
+ break;
+ case SessionStorageNamespace::MERGE_RESULT_TOO_MANY_TRANSACTIONS:
+ RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_TOO_MANY_TRANSACTIONS);
+ break;
+ case SessionStorageNamespace::MERGE_RESULT_NOT_MERGEABLE:
+ RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_NOT_MERGEABLE);
+ break;
+ case SessionStorageNamespace::MERGE_RESULT_MERGEABLE:
+ RecordEvent(PRERENDER_EVENT_MERGE_RESULT_RESULT_MERGEABLE);
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ if (result != SessionStorageNamespace::MERGE_RESULT_MERGEABLE &&
+ result != SessionStorageNamespace::MERGE_RESULT_NO_TRANSACTIONS) {
+ RecordEvent(PRERENDER_EVENT_MERGE_RESULT_MERGE_FAILED);
+ prerender_data_->ClearPendingSwap();
+ return;
+ }
+
+ RecordEvent(PRERENDER_EVENT_MERGE_RESULT_SWAPPING_IN);
+ // Note that SwapInternal, on success, will delete |prerender_data_| and
+ // |this|. Pass in a new GURL object rather than a reference to |url_|.
+ //
+ // TODO(davidben): See about deleting PrerenderData asynchronously so this
+ // behavior is more reasonable.
+ WebContents* new_web_contents =
+ manager_->SwapInternal(GURL(url_), target_contents_, prerender_data_);
+ if (!new_web_contents) {
+ RecordEvent(PRERENDER_EVENT_MERGE_RESULT_SWAPIN_FAILED);
+ prerender_data_->ClearPendingSwap();
+ }
+}
+
+void PrerenderManager::PendingSwap::OnMergeTimeout() {
+ RecordEvent(PRERENDER_EVENT_MERGE_RESULT_TIMED_OUT);
+ prerender_data_->ClearPendingSwap();
}
void PrerenderManager::SetPrerenderContentsFactory(
« no previous file with comments | « chrome/browser/prerender/prerender_manager.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698