Bug 1029782 - Have OPEN_SECRETLY flag for opening cache entries, r=michal
authorHonza Bambas <honzab.moz@firemni.cz>
Tue, 16 Sep 2014 15:51:50 +0200
changeset 230163 5780024ea016d3e8b44dbde2c4f1d88ba2b5fb20
parent 230162 6d54ee2b5a829d1c472ef5abc8a86f4ede4a3609
child 230164 1bb80b72541fda1266d59aa94cdcb640c2a18c58
push id611
push userraliiev@mozilla.com
push dateMon, 05 Jan 2015 23:23:16 +0000
treeherdermozilla-release@345cd3b9c445 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmichal
bugs1029782
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1029782 - Have OPEN_SECRETLY flag for opening cache entries, r=michal
netwerk/cache2/CacheEntry.cpp
netwerk/cache2/CacheEntry.h
netwerk/cache2/nsICacheStorage.idl
netwerk/test/unit/test_cache2-28a-OPEN_SECRETLY.js
netwerk/test/unit/xpcshell.ini
--- a/netwerk/cache2/CacheEntry.cpp
+++ b/netwerk/cache2/CacheEntry.cpp
@@ -71,24 +71,26 @@ CacheEntryHandle::~CacheEntryHandle()
 
   MOZ_COUNT_DTOR(CacheEntryHandle);
 }
 
 // CacheEntry::Callback
 
 CacheEntry::Callback::Callback(CacheEntry* aEntry,
                                nsICacheEntryOpenCallback *aCallback,
-                               bool aReadOnly, bool aCheckOnAnyThread)
+                               bool aReadOnly, bool aCheckOnAnyThread,
+                               bool aSecret)
 : mEntry(aEntry)
 , mCallback(aCallback)
 , mTargetThread(do_GetCurrentThread())
 , mReadOnly(aReadOnly)
 , mCheckOnAnyThread(aCheckOnAnyThread)
 , mRecheckAfterWrite(false)
 , mNotWanted(false)
+, mSecret(aSecret)
 {
   MOZ_COUNT_CTOR(CacheEntry::Callback);
 
   // The counter may go from zero to non-null only under the service lock
   // but here we expect it to be already positive.
   MOZ_ASSERT(mEntry->HandlesCount());
   mEntry->AddHandleRef();
 }
@@ -96,16 +98,17 @@ CacheEntry::Callback::Callback(CacheEntr
 CacheEntry::Callback::Callback(CacheEntry::Callback const &aThat)
 : mEntry(aThat.mEntry)
 , mCallback(aThat.mCallback)
 , mTargetThread(aThat.mTargetThread)
 , mReadOnly(aThat.mReadOnly)
 , mCheckOnAnyThread(aThat.mCheckOnAnyThread)
 , mRecheckAfterWrite(aThat.mRecheckAfterWrite)
 , mNotWanted(aThat.mNotWanted)
+, mSecret(aThat.mSecret)
 {
   MOZ_COUNT_CTOR(CacheEntry::Callback);
 
   // The counter may go from zero to non-null only under the service lock
   // but here we expect it to be already positive.
   MOZ_ASSERT(mEntry->HandlesCount());
   mEntry->AddHandleRef();
 }
@@ -264,21 +267,22 @@ void CacheEntry::AsyncOpen(nsICacheEntry
   LOG(("CacheEntry::AsyncOpen [this=%p, state=%s, flags=%d, callback=%p]",
     this, StateString(mState), aFlags, aCallback));
 
   bool readonly = aFlags & nsICacheStorage::OPEN_READONLY;
   bool bypassIfBusy = aFlags & nsICacheStorage::OPEN_BYPASS_IF_BUSY;
   bool truncate = aFlags & nsICacheStorage::OPEN_TRUNCATE;
   bool priority = aFlags & nsICacheStorage::OPEN_PRIORITY;
   bool multithread = aFlags & nsICacheStorage::CHECK_MULTITHREADED;
+  bool secret = aFlags & nsICacheStorage::OPEN_SECRETLY;
 
   MOZ_ASSERT(!readonly || !truncate, "Bad flags combination");
   MOZ_ASSERT(!(truncate && mState > LOADING), "Must not call truncate on already loaded entry");
 
-  Callback callback(this, aCallback, readonly, multithread);
+  Callback callback(this, aCallback, readonly, multithread, secret);
 
   if (!Open(callback, truncate, priority, bypassIfBusy)) {
     // We get here when the callback wants to bypass cache when it's busy.
     LOG(("  writing or revalidating, callback wants to bypass cache"));
     callback.mNotWanted = true;
     InvokeAvailableCallback(callback);
   }
 }
@@ -754,30 +758,32 @@ void CacheEntry::InvokeAvailableCallback
     nsRefPtr<AvailableCallbackRunnable> event =
       new AvailableCallbackRunnable(this, aCallback);
 
     rv = aCallback.mTargetThread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL);
     LOG(("  redispatched, (rv = 0x%08x)", rv));
     return;
   }
 
-  if (NS_SUCCEEDED(mFileStatus)) {
+  if (NS_SUCCEEDED(mFileStatus) && !aCallback.mSecret) {
     // Let the last-fetched and fetch-count properties be updated.
     mFile->OnFetched();
   }
 
   if (mIsDoomed || aCallback.mNotWanted) {
     LOG(("  doomed or not wanted, notifying OCEA with NS_ERROR_CACHE_KEY_NOT_FOUND"));
     aCallback.mCallback->OnCacheEntryAvailable(
       nullptr, false, nullptr, NS_ERROR_CACHE_KEY_NOT_FOUND);
     return;
   }
 
   if (state == READY) {
     LOG(("  ready/has-meta, notifying OCEA with entry and NS_OK"));
+
+    if (!aCallback.mSecret)
     {
       mozilla::MutexAutoLock lock(mLock);
       BackgroundOp(Ops::FRECENCYUPDATE);
     }
 
     nsRefPtr<CacheEntryHandle> handle = NewHandle();
     aCallback.mCallback->OnCacheEntryAvailable(
       handle, false, nullptr, NS_OK);
@@ -817,17 +823,20 @@ CacheEntryHandle* CacheEntry::NewHandle(
 {
   return new CacheEntryHandle(this);
 }
 
 CacheEntryHandle* CacheEntry::NewWriteHandle()
 {
   mozilla::MutexAutoLock lock(mLock);
 
+  // Ignore the OPEN_SECRETLY flag on purpose here, which should actually be
+  // used only along with OPEN_READONLY, but there is no need to enforce that.
   BackgroundOp(Ops::FRECENCYUPDATE);
+
   return (mWriter = NewHandle());
 }
 
 void CacheEntry::OnHandleClosed(CacheEntryHandle const* aHandle)
 {
   LOG(("CacheEntry::OnHandleClosed [this=%p, state=%s, handle=%p]", this, StateString(mState), aHandle));
 
   nsCOMPtr<nsIOutputStream> outputStream;
--- a/netwerk/cache2/CacheEntry.h
+++ b/netwerk/cache2/CacheEntry.h
@@ -132,17 +132,17 @@ private:
   // We must monitor when a cache entry whose consumer is responsible
   // for writing it the first time gets released.  We must then invoke
   // waiting callbacks to not break the chain.
   class Callback
   {
   public:
     Callback(CacheEntry* aEntry,
              nsICacheEntryOpenCallback *aCallback,
-             bool aReadOnly, bool aCheckOnAnyThread);
+             bool aReadOnly, bool aCheckOnAnyThread, bool aSecret);
     Callback(Callback const &aThat);
     ~Callback();
 
     // Called when this callback record changes it's owning entry,
     // mainly during recreation.
     void ExchangeEntry(CacheEntry* aEntry);
 
     // We are raising reference count here to take into account the pending
@@ -150,16 +150,17 @@ private:
     // it's pointer).
     nsRefPtr<CacheEntry> mEntry;
     nsCOMPtr<nsICacheEntryOpenCallback> mCallback;
     nsCOMPtr<nsIThread> mTargetThread;
     bool mReadOnly : 1;
     bool mCheckOnAnyThread : 1;
     bool mRecheckAfterWrite : 1;
     bool mNotWanted : 1;
+    bool mSecret : 1;
 
     nsresult OnCheckThread(bool *aOnCheckThread) const;
     nsresult OnAvailThread(bool *aOnAvailThread) const;
   };
 
   // Since OnCacheEntryAvailable must be invoked on the main thread
   // we need a runnable for it...
   class AvailableCallbackRunnable : public nsRunnable
--- a/netwerk/cache2/nsICacheStorage.idl
+++ b/netwerk/cache2/nsICacheStorage.idl
@@ -47,16 +47,21 @@ interface nsICacheStorage : nsISupports
    * Perform the cache entry check (onCacheEntryCheck invocation) on any thread 
    * for optimal perfomance optimization.  If this flag is not specified it is
    * ensured that onCacheEntryCheck is called on the same thread as respective 
    * asyncOpen has been called.
    */
   const uint32_t CHECK_MULTITHREADED = 1 << 4;
 
   /**
+   * Don't automatically update any 'last used' metadata of the entry.
+   */
+  const uint32_t OPEN_SECRETLY = 1 << 5;
+
+  /**
    * Asynchronously opens a cache entry for the specified URI.
    * Result is fetched asynchronously via the callback.
    *
    * @param aURI
    *    The URI to search in cache or to open for writting.
    * @param aIdExtension
    *    Any string that will extend (distinguish) the entry.  Two entries
    *    with the same aURI but different aIdExtension will be comletely
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit/test_cache2-28a-OPEN_SECRETLY.js
@@ -0,0 +1,34 @@
+function run_test()
+{
+  do_get_profile();
+  function NowSeconds() {
+    return parseInt((new Date()).getTime() / 1000);
+  }
+  function do_check_time(a, b) {
+    do_check_true(Math.abs(a - b) < 0.5);
+  }
+
+  asyncOpenCacheEntry("http://t/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY, null,
+    new OpenCallback(NEW, "m", "d", function(entry) {
+
+      var now1 = NowSeconds();
+      do_check_eq(entry.fetchCount, 1);
+      do_check_time(entry.lastFetched, now1);
+      do_check_time(entry.lastModified, now1);
+
+      do_timeout(2000, () => {
+        asyncOpenCacheEntry("http://t/", "disk", Ci.nsICacheStorage.OPEN_SECRETLY, null,
+          new OpenCallback(NORMAL, "m", "d", function(entry) {
+            do_check_eq(entry.fetchCount, 1);
+            do_check_time(entry.lastFetched, now1);
+            do_check_time(entry.lastModified, now1);
+
+            finish_cache2_test();
+          })
+        );
+      })
+    })
+  );
+
+  do_test_pending();
+}
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -57,16 +57,19 @@ support-files =
 [test_cache2-25-chunk-memory-limit.js]
 [test_cache2-26-no-outputstream-open.js]
 # GC, that this patch is dependent on, doesn't work well on Android.
 skip-if = os == "android"
 [test_cache2-27-force-valid-for.js]
 [test_cache2-28-last-access-attrs.js]
 # This test will be fixed in bug 1067931
 skip-if = true
+[test_cache2-28a-OPEN_SECRETLY.js]
+# This test will be fixed in bug 1067931
+skip-if = true
 [test_304_responses.js]
 [test_cacheForOfflineUse_no-store.js]
 [test_307_redirect.js]
 [test_NetUtil.js]
 [test_URIs.js]
 [test_aboutblank.js]
 [test_assoc.js]
 [test_auth_jar.js]