Changeset 64399 in webkit


Ignore:
Timestamp:
Jul 30, 2010 7:22:25 PM (14 years ago)
Author:
Joseph Pecoraro
Message:

2010-07-30 Joseph Pecoraro <Joseph Pecoraro>

Reviewed by David Kilzer.

Limit ApplicationCache Total and Per-Origin Storage Capacity (Quotas)
https://bugs.webkit.org/show_bug.cgi?id=40627

Part 3 - Refactor storeNewestCache to allow Failure Reason Output

Storing can result in an error in a number of reasons. Previously
the reasons were global and binary and could be determined by
checking ApplicationCacheStorage state. Now, with per-origin quotas
a per-origin quota can cause a failure that is not in global state.
Current failure reasons are:

OriginQuotaReached = per-origin quota reached, no storage is allowed.
TotalQuotaReached = database quota reached, no storage is allowed.
DiskOrOperationFailure = SQL error such as failed prepare or query. Not expected to happen.

This part provides an implementation of storeNewestCache for those
that care about the failure reason, and not just if it succeeded
or not. This moves the final origin quota check into the transaction.

  • loader/appcache/ApplicationCache.h: style fix for forwarding headers.
  • loader/appcache/ApplicationCacheGroup.cpp: (WebCore::ApplicationCacheGroup::checkIfLoadIsComplete): move origin quota check into storeNewestCache's SQL transaction.
  • loader/appcache/ApplicationCacheStorage.cpp: (WebCore::ApplicationCacheStorage::storeNewestCache): old implementation calls the new implementation ignoring failure reason. (WebCore::ApplicationCacheStorage::storeNewestCache): new implementation provides a failure reason in case of failure.
  • loader/appcache/ApplicationCacheStorage.h: (WebCore::ApplicationCacheStorage::): added FailureReason enum and storeNewestCache allowing it.
Location:
trunk/WebCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r64398 r64399  
     12010-07-30  Joseph Pecoraro  <joepeck@webkit.org>
     2
     3        Reviewed by David Kilzer.
     4
     5        Limit ApplicationCache Total and Per-Origin Storage Capacity (Quotas)
     6        https://bugs.webkit.org/show_bug.cgi?id=40627
     7
     8        Part 3 - Refactor storeNewestCache to allow Failure Reason Output
     9
     10        Storing can result in an error in a number of reasons. Previously
     11        the reasons were global and binary and could be determined by
     12        checking ApplicationCacheStorage state. Now, with per-origin quotas
     13        a per-origin quota can cause a failure that is not in global state.
     14        Current failure reasons are:
     15
     16          OriginQuotaReached = per-origin quota reached, no storage is allowed.
     17          TotalQuotaReached  = database quota reached, no storage is allowed.
     18          DiskOrOperationFailure = SQL error such as failed prepare or query. Not expected to happen.
     19
     20        This part provides an implementation of storeNewestCache for those
     21        that care about the failure reason, and not just if it succeeded
     22        or not. This moves the final origin quota check into the transaction.
     23
     24        * loader/appcache/ApplicationCache.h: style fix for forwarding headers.
     25        * loader/appcache/ApplicationCacheGroup.cpp:
     26        (WebCore::ApplicationCacheGroup::checkIfLoadIsComplete): move origin quota check into storeNewestCache's SQL transaction.
     27        * loader/appcache/ApplicationCacheStorage.cpp:
     28        (WebCore::ApplicationCacheStorage::storeNewestCache): old implementation calls the new implementation ignoring failure reason.
     29        (WebCore::ApplicationCacheStorage::storeNewestCache): new implementation provides a failure reason in case of failure.
     30        * loader/appcache/ApplicationCacheStorage.h:
     31        (WebCore::ApplicationCacheStorage::): added FailureReason enum and storeNewestCache allowing it.
     32
    1332010-07-30  Joseph Pecoraro  <joepeck@webkit.org>
    234
  • trunk/WebCore/loader/appcache/ApplicationCache.h

    r50625 r64399  
    4242class DocumentLoader;
    4343class KURL;
    44 
    4544class ResourceRequest;
    4645
  • trunk/WebCore/loader/appcache/ApplicationCacheGroup.cpp

    r64398 r64399  
    881881        }
    882882
     883        ApplicationCacheStorage::FailureReason failureReason;
    883884        RefPtr<ApplicationCache> oldNewestCache = (m_newestCache == m_cacheBeingUpdated) ? 0 : m_newestCache;
    884 
    885         // Check one more time, before committing to the new cache, if the cache will fit in the quota.
    886         int64_t remainingSpaceInOrigin;
    887         if (cacheStorage().remainingSizeForOriginExcludingCache(m_origin.get(), oldNewestCache.get(), remainingSpaceInOrigin)) {
    888             if (m_cacheBeingUpdated->estimatedSizeInStorage() > remainingSpaceInOrigin) {
    889                 cacheUpdateFailed();
    890                 break;
    891             }
    892         }
    893 
    894885        setNewestCache(m_cacheBeingUpdated.release());
    895         if (cacheStorage().storeNewestCache(this)) {
     886        if (cacheStorage().storeNewestCache(this, oldNewestCache.get(), failureReason)) {
    896887            // New cache stored, now remove the old cache.
    897888            if (oldNewestCache)
     
    905896            postListenerTask(isUpgradeAttempt ? ApplicationCacheHost::UPDATEREADY_EVENT : ApplicationCacheHost::CACHED_EVENT, m_associatedDocumentLoaders);
    906897        } else {
    907             if (cacheStorage().isMaximumSizeReached() && !m_calledReachedMaxAppCacheSize) {
     898            if (failureReason == ApplicationCacheStorage::OriginQuotaReached) {
     899                // We ran out of space for this origin. Roll back to previous state.
     900                if (oldNewestCache)
     901                    setNewestCache(oldNewestCache.release());
     902                cacheUpdateFailed();
     903                return;
     904            }
     905
     906            if (failureReason == ApplicationCacheStorage::TotalQuotaReached && !m_calledReachedMaxAppCacheSize) {
    908907                // We ran out of space. All the changes in the cache storage have
    909908                // been rolled back. We roll back to the previous state in here,
     
    919918                scheduleReachedMaxAppCacheSizeCallback();
    920919                return;
     920            }
     921
     922            // Run the "cache failure steps"
     923            // Fire the error events to all pending master entries, as well any other cache hosts
     924            // currently associated with a cache in this group.
     925            postListenerTask(ApplicationCacheHost::ERROR_EVENT, m_associatedDocumentLoaders);
     926            // Disassociate the pending master entries from the failed new cache. Note that
     927            // all other loaders in the m_associatedDocumentLoaders are still associated with
     928            // some other cache in this group. They are not associated with the failed new cache.
     929
     930            // Need to copy loaders, because the cache group may be destroyed at the end of iteration.
     931            Vector<DocumentLoader*> loaders;
     932            copyToVector(m_pendingMasterResourceLoaders, loaders);
     933            size_t count = loaders.size();
     934            for (size_t i = 0; i != count; ++i)
     935                disassociateDocumentLoader(loaders[i]); // This can delete this group.
     936
     937            // Reinstate the oldNewestCache, if there was one.
     938            if (oldNewestCache) {
     939                // This will discard the failed new cache.
     940                setNewestCache(oldNewestCache.release());
    921941            } else {
    922                 // Run the "cache failure steps"
    923                 // Fire the error events to all pending master entries, as well any other cache hosts
    924                 // currently associated with a cache in this group.
    925                 postListenerTask(ApplicationCacheHost::ERROR_EVENT, m_associatedDocumentLoaders);
    926                 // Disassociate the pending master entries from the failed new cache. Note that
    927                 // all other loaders in the m_associatedDocumentLoaders are still associated with
    928                 // some other cache in this group. They are not associated with the failed new cache.
    929 
    930                 // Need to copy loaders, because the cache group may be destroyed at the end of iteration.
    931                 Vector<DocumentLoader*> loaders;
    932                 copyToVector(m_pendingMasterResourceLoaders, loaders);
    933                 size_t count = loaders.size();
    934                 for (size_t i = 0; i != count; ++i)
    935                     disassociateDocumentLoader(loaders[i]); // This can delete this group.
    936 
    937                 // Reinstate the oldNewestCache, if there was one.
    938                 if (oldNewestCache) {
    939                     // This will discard the failed new cache.
    940                     setNewestCache(oldNewestCache.release());
    941                 } else {
    942                     // We must have been deleted by the last call to disassociateDocumentLoader().
    943                     return;
    944                 }
     942                // We must have been deleted by the last call to disassociateDocumentLoader().
     943                return;
    945944            }
    946945        }
  • trunk/WebCore/loader/appcache/ApplicationCacheStorage.cpp

    r64398 r64399  
    859859}
    860860
    861 bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group)
     861bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group, ApplicationCache* oldCache, FailureReason& failureReason)
    862862{
    863863    openDatabase(true);
     
    872872   
    873873    storeCacheTransaction.begin();
     874
     875    // Check if this would reach the per-origin quota.
     876    int64_t remainingSpaceInOrigin;
     877    if (remainingSizeForOriginExcludingCache(group->origin(), oldCache, remainingSpaceInOrigin)) {
     878        if (remainingSpaceInOrigin < group->newestCache()->estimatedSizeInStorage()) {
     879            failureReason = OriginQuotaReached;
     880            return false;
     881        }
     882    }
    874883
    875884    GroupStorageIDJournal groupStorageIDJournal;
     
    878887        if (!store(group, &groupStorageIDJournal)) {
    879888            checkForMaxSizeReached();
     889            failureReason = isMaximumSizeReached() ? TotalQuotaReached : DiskOrOperationFailure;
    880890            return false;
    881891        }
     
    894904    if (!store(group->newestCache(), &resourceStorageIDJournal)) {
    895905        checkForMaxSizeReached();
     906        failureReason = isMaximumSizeReached() ? TotalQuotaReached : DiskOrOperationFailure;
    896907        return false;
    897908    }
     
    900911   
    901912    SQLiteStatement statement(m_database, "UPDATE CacheGroups SET newestCache=? WHERE id=?");
    902     if (statement.prepare() != SQLResultOk)
    903         return false;
     913    if (statement.prepare() != SQLResultOk) {
     914        failureReason = DiskOrOperationFailure;
     915        return false;
     916    }
    904917   
    905918    statement.bindInt64(1, group->newestCache()->storageID());
    906919    statement.bindInt64(2, group->storageID());
    907920   
    908     if (!executeStatement(statement))
    909         return false;
     921    if (!executeStatement(statement)) {
     922        failureReason = DiskOrOperationFailure;
     923        return false;
     924    }
    910925   
    911926    groupStorageIDJournal.commit();
     
    913928    storeCacheTransaction.commit();
    914929    return true;
     930}
     931
     932bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group)
     933{
     934    // Ignore the reason for failing, just attempt the store.
     935    FailureReason ignoredFailureReason;
     936    return storeNewestCache(group, 0, ignoredFailureReason);
    915937}
    916938
  • trunk/WebCore/loader/appcache/ApplicationCacheStorage.h

    r64398 r64399  
    4848class ApplicationCacheStorage : public Noncopyable {
    4949public:
     50    enum FailureReason {
     51        OriginQuotaReached,
     52        TotalQuotaReached,
     53        DiskOrOperationFailure
     54    };
     55
    5056    void setCacheDirectory(const String&);
    5157    const String& cacheDirectory() const;
     
    6975    void cacheGroupMadeObsolete(ApplicationCacheGroup*);
    7076       
     77    bool storeNewestCache(ApplicationCacheGroup*, ApplicationCache* oldCache, FailureReason& failureReason);
    7178    bool storeNewestCache(ApplicationCacheGroup*); // Updates the cache group, but doesn't remove old cache.
    7279    bool store(ApplicationCacheResource*, ApplicationCache*);
Note: See TracChangeset for help on using the changeset viewer.