summaryrefslogtreecommitdiffstats
path: root/webkit/appcache/appcache_group.cc
diff options
context:
space:
mode:
authorjennb@chromium.org <jennb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-10 23:03:30 +0000
committerjennb@chromium.org <jennb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-10 23:03:30 +0000
commitdc60e95adac80ad6c9a88cde612d37d5ecba3ebd (patch)
tree7b674dda57a5c149d093ce52d1ad67910f14d9ea /webkit/appcache/appcache_group.cc
parent8f0e7700181b5b69040fdd45ab775884c954461d (diff)
downloadchromium_src-dc60e95adac80ad6c9a88cde612d37d5ecba3ebd.zip
chromium_src-dc60e95adac80ad6c9a88cde612d37d5ecba3ebd.tar.gz
chromium_src-dc60e95adac80ad6c9a88cde612d37d5ecba3ebd.tar.bz2
Queue appcache update if current update process is terminating.
TEST=update and group unittests added BUG=none Review URL: http://codereview.chromium.org/465132 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@34299 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/appcache/appcache_group.cc')
-rw-r--r--webkit/appcache/appcache_group.cc117
1 files changed, 115 insertions, 2 deletions
diff --git a/webkit/appcache/appcache_group.cc b/webkit/appcache/appcache_group.cc
index 49c8af3..a9ad808 100644
--- a/webkit/appcache/appcache_group.cc
+++ b/webkit/appcache/appcache_group.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include "base/logging.h"
+#include "base/message_loop.h"
#include "webkit/appcache/appcache.h"
#include "webkit/appcache/appcache_host.h"
#include "webkit/appcache/appcache_service.h"
@@ -15,6 +16,24 @@
namespace appcache {
+class AppCacheGroup;
+
+// Use this helper class because we cannot make AppCacheGroup a derived class
+// of AppCacheHost::Observer as it would create a circular dependency between
+// AppCacheHost and AppCacheGroup.
+class AppCacheGroup::HostObserver : public AppCacheHost::Observer {
+ public:
+ explicit HostObserver(AppCacheGroup* group) : group_(group) {}
+
+ // Methods for AppCacheHost::Observer.
+ void OnCacheSelectionComplete(AppCacheHost* host) {} // N/A
+ void OnDestructionImminent(AppCacheHost* host) {
+ group_->HostDestructionImminent(host);
+ }
+ private:
+ AppCacheGroup* group_;
+};
+
AppCacheGroup::AppCacheGroup(AppCacheService* service,
const GURL& manifest_url,
int64 group_id)
@@ -24,13 +43,17 @@ AppCacheGroup::AppCacheGroup(AppCacheService* service,
is_obsolete_(false),
newest_complete_cache_(NULL),
update_job_(NULL),
- service_(service) {
+ service_(service),
+ restart_update_task_(NULL) {
service_->storage()->working_set()->AddGroup(this);
+ host_observer_.reset(new HostObserver(this));
}
AppCacheGroup::~AppCacheGroup() {
DCHECK(old_caches_.empty());
DCHECK(!newest_complete_cache_);
+ DCHECK(!restart_update_task_);
+ DCHECK(queued_updates_.empty());
if (update_job_)
delete update_job_;
@@ -40,11 +63,18 @@ AppCacheGroup::~AppCacheGroup() {
}
void AppCacheGroup::AddUpdateObserver(UpdateObserver* observer) {
- observers_.AddObserver(observer);
+ // If observer being added is a host that has been queued for later update,
+ // add observer to a different observer list.
+ AppCacheHost* host = static_cast<AppCacheHost*>(observer);
+ if (queued_updates_.find(host) != queued_updates_.end())
+ queued_observers_.AddObserver(observer);
+ else
+ observers_.AddObserver(observer);
}
void AppCacheGroup::RemoveUpdateObserver(UpdateObserver* observer) {
observers_.RemoveObserver(observer);
+ queued_observers_.RemoveObserver(observer);
}
void AppCacheGroup::AddCache(AppCache* complete_cache) {
@@ -97,6 +127,79 @@ void AppCacheGroup::StartUpdateWithNewMasterEntry(
update_job_ = new AppCacheUpdateJob(service_, this);
update_job_->StartUpdate(host, new_master_resource);
+
+ // Run queued update immediately as an update has been started manually.
+ if (restart_update_task_) {
+ restart_update_task_->Cancel();
+ restart_update_task_ = NULL;
+ RunQueuedUpdates();
+ }
+}
+
+void AppCacheGroup::QueueUpdate(AppCacheHost* host,
+ const GURL& new_master_resource) {
+ DCHECK(update_job_ && host && !new_master_resource.is_empty());
+ queued_updates_.insert(QueuedUpdates::value_type(host, new_master_resource));
+
+ // Need to know when host is destroyed.
+ host->AddObserver(host_observer_.get());
+
+ // If host is already observing for updates, move host to queued observers
+ // list so that host is not notified when the current update completes.
+ if (FindObserver(host, observers_)) {
+ observers_.RemoveObserver(host);
+ queued_observers_.AddObserver(host);
+ }
+}
+
+void AppCacheGroup::RunQueuedUpdates() {
+ if (restart_update_task_)
+ restart_update_task_ = NULL;
+
+ if (queued_updates_.empty())
+ return;
+
+ QueuedUpdates updates_to_run;
+ queued_updates_.swap(updates_to_run);
+ DCHECK(queued_updates_.empty());
+
+ for (QueuedUpdates::iterator it = updates_to_run.begin();
+ it != updates_to_run.end(); ++it) {
+ AppCacheHost* host = it->first;
+ host->RemoveObserver(host_observer_.get());
+ if (FindObserver(host, queued_observers_)) {
+ queued_observers_.RemoveObserver(host);
+ observers_.AddObserver(host);
+ }
+ StartUpdateWithNewMasterEntry(host, it->second);
+ }
+}
+
+bool AppCacheGroup::FindObserver(UpdateObserver* find_me,
+ const ObserverList<UpdateObserver>& observer_list) {
+ ObserverList<UpdateObserver>::Iterator it(observer_list);
+ UpdateObserver* obs;
+ while ((obs = it.GetNext()) != NULL) {
+ if (obs == find_me)
+ return true;
+ }
+ return false;
+}
+
+void AppCacheGroup::ScheduleUpdateRestart(int delay_ms) {
+ DCHECK(!restart_update_task_);
+ restart_update_task_ =
+ NewRunnableMethod(this, &AppCacheGroup::RunQueuedUpdates);
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, restart_update_task_,
+ delay_ms);
+}
+
+void AppCacheGroup::HostDestructionImminent(AppCacheHost* host) {
+ queued_updates_.erase(host);
+ if (queued_updates_.empty() && restart_update_task_) {
+ restart_update_task_->Cancel();
+ restart_update_task_ = NULL;
+ }
}
void AppCacheGroup::SetUpdateStatus(UpdateStatus status) {
@@ -109,7 +212,17 @@ void AppCacheGroup::SetUpdateStatus(UpdateStatus status) {
DCHECK(update_job_);
} else {
update_job_ = NULL;
+
+ // Check member variable before notifying observers about update finishing.
+ // Observers may remove reference to group, causing group to be deleted
+ // after the notifications. If there are queued updates, then the group
+ // will continue to exist.
+ bool restart_update = !queued_updates_.empty();
+
FOR_EACH_OBSERVER(UpdateObserver, observers_, OnUpdateComplete(this));
+
+ if (restart_update)
+ ScheduleUpdateRestart(kUpdateRestartDelayMs);
}
}