Bug 113422 - Mem mapped resource data improvements
Summary: Mem mapped resource data improvements
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebKit2 (show other bugs)
Version: 528+ (Nightly build)
Hardware: Mac All
: P2 Normal
Assignee: Brady Eidson
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2013-03-27 10:40 PDT by Brady Eidson
Modified: 2013-03-27 13:36 PDT (History)
8 users (show)

See Also:


Attachments
Patch v1 (26.06 KB, patch)
2013-03-27 10:56 PDT, Brady Eidson
ap: review-
buildbot: commit-queue-
Details | Formatted Diff | Diff
Patch v2 - Fix build failure by adding a newline (!) (26.04 KB, patch)
2013-03-27 11:30 PDT, Brady Eidson
buildbot: commit-queue-
Details | Formatted Diff | Diff
Patch v3 - Much better, I think! (24.60 KB, patch)
2013-03-27 13:14 PDT, Brady Eidson
ap: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Brady Eidson 2013-03-27 10:40:34 PDT
Mem mapped resource data improvements.

These include:
-Using a notification API for a resource becoming file backed instead of using timers
-Using a much more explicit API to determine if the data for an object is mem mapped.

In radar as <rdar://problem/13196481>
Comment 1 Brady Eidson 2013-03-27 10:56:50 PDT
Created attachment 195353 [details]
Patch v1
Comment 2 Mark Rowe (bdash) 2013-03-27 11:00:47 PDT
Comment on attachment 195353 [details]
Patch v1

View in context: https://bugs.webkit.org/attachment.cgi?id=195353&action=review

> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:42
> +    static void (*softResponseSetBecameFileBackedCallBackBlock)(CFCachedURLResponseRef, CFCachedURLResponseCallBackBlock, dispatch_queue_t) = (void (*)(CFCachedURLResponseRef, CFCachedURLResponseCallBackBlock, dispatch_queue_t)) dlsym(CFNetworkLibrary(), "_CFCachedURLResponseSetBecameFileBackedCallBackBlock");

A typedef would make this a heck of a lot more readable.
Comment 3 WebKit Review Bot 2013-03-27 11:03:40 PDT
Attachment 195353 [details] did not pass style-queue:

Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'Source/WebKit2/ChangeLog', u'Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp', u'Source/WebKit2/NetworkProcess/NetworkResourceLoader.h', u'Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.h', u'Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm', u'Source/WebKit2/NetworkProcess/mac/NetworkResourceLoaderMac.mm', u'Source/WebKit2/WebKit2.xcodeproj/project.pbxproj']" exit_code: 1
Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.h:68:  Could not find a newline character at the end of the file.  [whitespace/ending_newline] [5]
Total errors found: 1 in 6 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 4 Brady Eidson 2013-03-27 11:08:26 PDT
(In reply to comment #3)
> Attachment 195353 [details] did not pass style-queue:
> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.h:68:  Could not find a newline character at the end of the file.  [whitespace/ending_newline] [5]
> Total errors found: 1 in 6 files

Fixed locally.
Comment 5 Build Bot 2013-03-27 11:27:15 PDT
Comment on attachment 195353 [details]
Patch v1

Attachment 195353 [details] did not pass mac-wk2-ews (mac-wk2):
Output: http://webkit-commit-queue.appspot.com/results/17338203
Comment 6 Brady Eidson 2013-03-27 11:29:44 PDT
Wow, a build failure due to the lack of newline.  Yikes.
Comment 7 Alexey Proskuryakov 2013-03-27 11:30:29 PDT
Comment on attachment 195353 [details]
Patch v1

View in context: https://bugs.webkit.org/attachment.cgi?id=195353&action=review

I think that I'd like to see a version of this patch with threading cleaned up a bit more. I'm not sure if I can fully understand it now.

> Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp:-211
> -    ASSERT(!isMainThread());

Should the condition be just reverted instead of removing the check?

> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.h:30
> +#include "NetworkResourceLoader.h"

Seems unneeded (and you already have a forward declaration in place).

> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:36
> +
> +
> +SOFT_LINK_FRAMEWORK(CFNetwork)

Seems like an abuse of the macro if you are only doing this to get a CFNetworkLibrary() function.

But then, you'll probably be deleting the dynamic loading code soon.

> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:52
> +static const double DiskCachingMonitorTimeout = 10;

I don;t think that starting constants with upper case is WebKit style.

> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:56
> +    static uint64_t currentID = 1;

Maybe ASSERT(isMainThread())?

> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:64
> +    DEFINE_STATIC_LOCAL(DiskCachingMonitorMap, map, ());

Maybe ASSERT(!diskCachingMonitorMapMutex().tryLock())?

> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:81
> +    OwnPtr<DiskCachingMonitor> request = adoptPtr(new DiskCachingMonitor(cachedResponse, loader));

We usually hide the constructor and expose a create function for this.

> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:93
> +    // Step 1: Set up this request's data members on the main thread.
> +    dispatch_async(dispatch_get_main_queue(), ^{

If it's dispatch_async, then it's not step 1, it's step "some time".

Also, I don't understand whether this constructor is only called on main thread anyway. Calling generateUniqueDiskCachingMonitorID() seems to require that, and all client code is main thread now.

> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:98
> +    // Step2: Set up the disk caching callback so this request can be destroyed upon successfull disk caching.

No space in "Step2".

> Source/WebKit2/NetworkProcess/mac/NetworkResourceLoaderMac.mm:83
> +    DEFINE_STATIC_LOCAL(RetainPtr<CFURLCacheRef>, cache, (AdoptCF, CFURLCacheCopySharedURLCache()));
> +    if (!cache)
> +        return;

Don't we change the cache when enabling private browsing? I'm also unsure how this will work with cache partitioning.

> Source/WebKit2/NetworkProcess/mac/NetworkResourceLoaderMac.mm:99
> +void NetworkResourceLoader::willCacheResponseAsync(WebCore::ResourceHandle*, NSCachedURLResponse* nsResponse)

Please no WebCore:: prefix. This also has a misplaced star.
Comment 8 Brady Eidson 2013-03-27 11:30:46 PDT
Created attachment 195365 [details]
Patch v2 - Fix build failure by adding a newline (!)
Comment 9 Geoffrey Garen 2013-03-27 11:44:05 PDT
View in context: https://bugs.webkit.org/attachment.cgi?id=195353&action=review

r- because I think the dispatch_async initialization may be a bug. Please consider the other stuff, too.

> Source/WebKit2/ChangeLog:17
> +        It both listens for a callback on the cached response indicating it has been cached
> +        or sets a timer so we don't keep objects alive waiting forever.

Logic: "or" should be "and".

> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.h:41
> +class DiskCachingMonitor : public CoreIPC::MessageSender<DiskCachingMonitor> {

We usually use nouns and not gerunds as class names. How about "DiskCacheMonitor", since this object monitors the disk cache? It's awkward to say "This cache monitors the disk caching".

> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.h:64
> +void monitorCachedResponse(CFCachedURLResponseRef, NetworkResourceLoader*);

This function name is a bit vague because it doesn't say what we're monitoring for. How about "monitorFileBackingStoreCreation"?

>> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:42
>> +    static void (*softResponseSetBecameFileBackedCallBackBlock)(CFCachedURLResponseRef, CFCachedURLResponseCallBackBlock, dispatch_queue_t) = (void (*)(CFCachedURLResponseRef, CFCachedURLResponseCallBackBlock, dispatch_queue_t)) dlsym(CFNetworkLibrary(), "_CFCachedURLResponseSetBecameFileBackedCallBackBlock");
> 
> A typedef would make this a heck of a lot more readable.

+1

> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:52
> +// The maximum number of seconds we'll try to wait for a resource to be disk cached before we forget the request.
> +static const double DiskCachingMonitorTimeout = 10;

This seems really low. Since the CFNetwork initial delay is 7s, this means that we'll ignore any resource that gets postponed. How about 60s?

> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:96
> +    dispatch_async(dispatch_get_main_queue(), ^{
> +        m_connectionToWebProcess = loader->connectionToWebProcess();
> +        m_resourceRequest = loader->request();
> +    });

How do we know it's valid to set up our data members asynchronously? What happens if we get a callback before our data members are set up?

> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:106
> +    // Step2: Set up the disk caching callback so this request can be destroyed upon successfull disk caching.
> +    uint64_t identifier = m_requestID;
> +    CFCachedURLResponseCallBackBlock block = ^(CFCachedURLResponseRef cachedResponse)
> +    {
> +        DiskCachingMonitor* rawRequest = 0;
> +        {
> +            MutexLocker locker(diskCachingMonitorMapMutex());
> +            rawRequest = diskCachingMonitorMap().take(identifier);
> +        }

Let's call the object "monitor" and not "request", since request sounds like you're talking about the resource request.

You can eliminate the need for all that map, UUID, and timer complexity like so:

__block DiskCachingMonitor* rawMonitor = this;

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * DiskCachingMonitorTimeout), dispatch_get_main_queue(), ^( adoptPtr(rawMonitor); rawMonitor = 0; });

CFCachedURLResponseCallBackBlock block = ^(CFCachedURLResponseRef cachedResponse)
{
    if (!rawMonitor)
        return;
    ....
    OwnPtr<DiskCachingMonitor> monitor = adoptPtr(rawMonitor);
    rawMonitor = 0;
}
Comment 10 Brady Eidson 2013-03-27 11:52:40 PDT
(In reply to comment #9)
> View in context: https://bugs.webkit.org/attachment.cgi?id=195353&action=review
> 
> r- because I think the dispatch_async initialization may be a bug. Please consider the other stuff, too.

I disagree it's a bug, you'll have to convince me.  (Further discussion below)

> > Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.h:41
> > +class DiskCachingMonitor : public CoreIPC::MessageSender<DiskCachingMonitor> {
> 
> We usually use nouns and not gerunds as class names. How about "DiskCacheMonitor", since this object monitors the disk cache? It's awkward to say "This cache monitors the disk caching".

Okay.

> >> Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:42
> >> +    static void (*softResponseSetBecameFileBackedCallBackBlock)(CFCachedURLResponseRef, CFCachedURLResponseCallBackBlock, dispatch_queue_t) = (void (*)(CFCachedURLResponseRef, CFCachedURLResponseCallBackBlock, dispatch_queue_t)) dlsym(CFNetworkLibrary(), "_CFCachedURLResponseSetBecameFileBackedCallBackBlock");
> > 
> > A typedef would make this a heck of a lot more readable.
> 
> +1

Okay.

> > Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:52
> > +// The maximum number of seconds we'll try to wait for a resource to be disk cached before we forget the request.
> > +static const double DiskCachingMonitorTimeout = 10;
> 
> This seems really low. Since the CFNetwork initial delay is 7s, this means that we'll ignore any resource that gets postponed. How about 60s?
> 
> > Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:96
> > +    dispatch_async(dispatch_get_main_queue(), ^{
> > +        m_connectionToWebProcess = loader->connectionToWebProcess();
> > +        m_resourceRequest = loader->request();
> > +    });
> 
> How do we know it's valid to set up our data members asynchronously? What happens if we get a callback before our data members are set up?

Since the dispatch_async to setup the members goes out before we even setup the callback, and since a "dispatch queue" is by definition a queue, are we not guaranteed this async dispatch is handled before any possible callback comes in?  Perhaps you're familiar with some exception to the "queue" part if dispatch_queue that I'm not familiar with.

> 
> > Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:106
> > +    // Step2: Set up the disk caching callback so this request can be destroyed upon successfull disk caching.
> > +    uint64_t identifier = m_requestID;
> > +    CFCachedURLResponseCallBackBlock block = ^(CFCachedURLResponseRef cachedResponse)
> > +    {
> > +        DiskCachingMonitor* rawRequest = 0;
> > +        {
> > +            MutexLocker locker(diskCachingMonitorMapMutex());
> > +            rawRequest = diskCachingMonitorMap().take(identifier);
> > +        }
> 
> Let's call the object "monitor" and not "request", since request sounds like you're talking about the resource request.

Originally the class was called "DiskCachingRequest", and I missed this in my rename.  Will fix.

> You can eliminate the need for all that map, UUID, and timer complexity like so:
> 
> __block DiskCachingMonitor* rawMonitor = this;
> 
> dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * DiskCachingMonitorTimeout), dispatch_get_main_queue(), ^( adoptPtr(rawMonitor); rawMonitor = 0; });
> 
> CFCachedURLResponseCallBackBlock block = ^(CFCachedURLResponseRef cachedResponse)
> {
>     if (!rawMonitor)
>         return;
>     ....
>     OwnPtr<DiskCachingMonitor> monitor = adoptPtr(rawMonitor);
>     rawMonitor = 0;
> }

That is clever.  Now You're Thinking With Closures ™
Comment 11 Build Bot 2013-03-27 11:52:55 PDT
Comment on attachment 195365 [details]
Patch v2 - Fix build failure by adding a newline (!)

Attachment 195365 [details] did not pass mac-wk2-ews (mac-wk2):
Output: http://webkit-commit-queue.appspot.com/results/17314414
Comment 12 Geoffrey Garen 2013-03-27 11:55:50 PDT
> > How do we know it's valid to set up our data members asynchronously? What happens if we get a callback before our data members are set up?

> Since the dispatch_async to setup the members goes out before we even setup the callback, and since a "dispatch queue" is by definition a queue, are we not guaranteed this async dispatch is handled before any possible callback comes in?  Perhaps you're familiar with some exception to the "queue" part if dispatch_queue that I'm not familiar with.

No, you're totally right. I missed the fact that all of these blocks are scheduled on the main queue.

Side note: This logic applies to the main queue because the main queue is a serial queue. It would not apply to a parallel queue, such as dispatch_get_global_queue(...).
Comment 13 Brady Eidson 2013-03-27 12:26:37 PDT
(In reply to comment #7)
> (From update of attachment 195353 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=195353&action=review
> 
> I think that I'd like to see a version of this patch with threading cleaned up a bit more. I'm not sure if I can fully understand it now.

Much simpler with Geoff's block improvement idea.
> 
> > Source/WebKit2/NetworkProcess/NetworkResourceLoader.cpp:-211
> > -    ASSERT(!isMainThread());
> 
> Should the condition be just reverted instead of removing the check?

Fixed

> > Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.h:30
> > +#include "NetworkResourceLoader.h"
> 
> Seems unneeded (and you already have a forward declaration in place)

Yup.

> 
> > Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:36
> > +
> > +
> > +SOFT_LINK_FRAMEWORK(CFNetwork)
> 
> Seems like an abuse of the macro if you are only doing this to get a CFNetworkLibrary() function.
> 
> But then, you'll probably be deleting the dynamic loading code soon.

It is abuse, and yes it'll be deleting soonish.

> 
> > Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:52
> > +static const double DiskCachingMonitorTimeout = 10;
> 
> I don;t think that starting constants with upper case is WebKit style.

It's not!  Style bot fail!

> 
> > Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:56
> > +    static uint64_t currentID = 1;
> 
> Maybe ASSERT(isMainThread())?
> 
> > Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:64
> > +    DEFINE_STATIC_LOCAL(DiskCachingMonitorMap, map, ());
> 
> Maybe ASSERT(!diskCachingMonitorMapMutex().tryLock())?

These are both now gone.

> 
> > Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:81
> > +    OwnPtr<DiskCachingMonitor> request = adoptPtr(new DiskCachingMonitor(cachedResponse, loader));
> 
> We usually hide the constructor and expose a create function for this.

Because of the somewhat atypical role and use of the DiskCacheMonitor object, I'm not sure we have an applicable pattern to build on.

> > Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:93
> > +    // Step 1: Set up this request's data members on the main thread.
> > +    dispatch_async(dispatch_get_main_queue(), ^{
> 
> If it's dispatch_async, then it's not step 1, it's step "some time".

It's "some time," but in a series of asynchronous queued steps, it's still step 1.  The comment pattern will hold more true in the new version of the patch.

> > Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:98
> > +    // Step2: Set up the disk caching callback so this request can be destroyed upon successfull disk caching.
> 
> No space in "Step2".

Fixed.

> 
> > Source/WebKit2/NetworkProcess/mac/NetworkResourceLoaderMac.mm:83
> > +    DEFINE_STATIC_LOCAL(RetainPtr<CFURLCacheRef>, cache, (AdoptCF, CFURLCacheCopySharedURLCache()));
> > +    if (!cache)
> > +        return;
> 
> Don't we change the cache when enabling private browsing? I'm also unsure how this will work with cache partitioning.

I can't find anyplace where we ever set a new shared cache, and that is the only context we ever have at this site.

Cache partitioning is done with a partition string as an argument to the shared cache object, which is we have to preserve the original resource request which contains this string.

> 
> > Source/WebKit2/NetworkProcess/mac/NetworkResourceLoaderMac.mm:99
> > +void NetworkResourceLoader::willCacheResponseAsync(WebCore::ResourceHandle*, NSCachedURLResponse* nsResponse)
> 
> Please no WebCore:: prefix. This also has a misplaced star.

Will fix.
Comment 14 Alexey Proskuryakov 2013-03-27 12:34:05 PDT
> I can't find anyplace where we ever set a new shared cache, and that is the only context we ever have at this site.

It would be done indirectly, via switching to a new storage session.
Comment 15 Geoffrey Garen 2013-03-27 12:56:38 PDT
/Volumes/Data/EWS/WebKit/Source/WebKit2/NetworkProcess/mac/DiskCachingMonitor.mm:115:32: error: no member named 'tryGetShareableHandleFromCFURLCachedResponse' in 'WebKit::NetworkResourceLoader'
        NetworkResourceLoader::tryGetShareableHandleFromCFURLCachedResponse(handle, cachedResponse);
        ~~~~~~~~~~~~~~~~~~~~~~~^
1 error generated.
Comment 16 Brady Eidson 2013-03-27 13:14:07 PDT
Created attachment 195384 [details]
Patch v3 - Much better, I think!
Comment 17 Alexey Proskuryakov 2013-03-27 13:25:20 PDT
Comment on attachment 195384 [details]
Patch v3 - Much better, I think!

View in context: https://bugs.webkit.org/attachment.cgi?id=195384&action=review

> Source/WebKit2/NetworkProcess/mac/DiskCacheMonitor.h:30
> +#include "NetworkResourceLoader.h"

Still here?

> Source/WebKit2/NetworkProcess/mac/DiskCacheMonitor.h:47
> +    NetworkConnectionToWebProcess* connectionToWebProcess() const { return m_connectionToWebProcess.get(); }

I don't see this used.

> Source/WebKit2/NetworkProcess/mac/DiskCacheMonitor.h:59
> +void monitorFileBackingStoreCreation(CFCachedURLResponseRef, NetworkResourceLoader*);

Why not make this a static function in the class, to avoid friending it?

> Source/WebKit2/NetworkProcess/mac/DiskCacheMonitor.h:61
> +} // namspace WebKit

namespace, if you insist on adding a comment.

> Source/WebKit2/NetworkProcess/mac/NetworkResourceLoaderMac.mm:53
> +@interface NSCachedURLResponse (NSCachedURLResponseInternals)

We now say Details, not Internals.

> Source/WebKit2/NetworkProcess/mac/NetworkResourceLoaderMac.mm:81
> +    RetainPtr<CFURLCacheRef> cache(AdoptCF, CFURLCacheCopySharedURLCache()); 

I think our preferred pattern is "= adoptCF(...)" these days.

> Source/WebKit2/NetworkProcess/mac/NetworkResourceLoaderMac.mm:99
> +void NetworkResourceLoader::willCacheResponseAsync(ResourceHandle*, NSCachedURLResponse *nsResponse)

I'd ASSERT(handle == m_handle).
Comment 18 Brady Eidson 2013-03-27 13:30:10 PDT
I'll meet Geoff partway on the delay and bump it to 20s before landing (this patch had it at 0.2 still from some debugging - yikes!)
Comment 19 Brady Eidson 2013-03-27 13:31:51 PDT
And addressed Alexey's new feedback, of course.
Comment 20 Brady Eidson 2013-03-27 13:36:52 PDT
http://trac.webkit.org/changeset/147006