Download cache: Use NSData with memory mapping

150 views
Skip to first unread message

Eric Scouten

unread,
Sep 7, 2010, 4:21:49 PM9/7/10
to ASIHTTPRequest
I am wondering if there is a clean way to modify the code in -
[ ASIHTTPRequest useDataFromCache] so that it the response data
doesn't have to use writable memory. (When dealing with larger files
on iOS, it's good to use memory mapped data as much as possible.)

In my working copy of this file, I made the following change at line
2903, where the data is brought back from cache:

< [theRequest setRawResponseData:[NSMutableData
dataWithContentsOfFile:dataPath]];
---
> [theRequest setRawResponseData:[NSData dataWithContentsOfMappedFile:dataPath]];

Given that the rawResponseData is actually declared as an
NSMutableData pointer, I know this isn't a long-term solution, but I
wanted to float the idea and see if there's a way to make a better
fix. (I'm guessing there's a fairly long thread to pull on here.)

-Eric

Ben Copsey

unread,
Sep 8, 2010, 7:26:08 AM9/8/10
to asihttp...@googlegroups.com
Hi Eric

I'm not that familiar with using memory mapped files, but what would happen if the cached response was modified after the NSData instance was created? Presumably, something bad. I suppose the cache could be modified to update cached data in a different way to avoid this problem - preserving the old file, and creating a new one. I guess I'll have to think about this.

This may not be an issue in your apps anyway, and if not, your approach sounds ok - I don't imagine casting the data to mutable to avoid any warnings would cause problems.

If I'm understanding correctly, a side benefit to using a mapped file would be a reduction in memory use in cases where the same response is pulled from the cache multiple times. Currently, this would mean a new NSData instance with the whole response in memory for each request. I guess things could be changed so that an existing NSData instance could be returned if one already exists. Maybe this is a good idea anyway, but my reading is that 10 mapped file NSData instances would be a big improvement on 10 regular ones.

The simplest approach as the code stands would be to set a downloadDestinationPath on your requests. When a cached response is used, the request will modify the downloadDestinationPath to point at the cached response. Obviously, this means you'll have slightly more work to do in your delegate, but won't have to make any changes to ASIHTTPRequest or the cache.

Since we're talking about the cache, I have been wondering if if would make sense to move the code in useDataFromCache into ASIDownloadCache. I think the benefits of this would be a) keeping as much of the cache-related code together as possible, and b) ASIDownloadCache is a much simpler class to modify/subclass than ASIHTTPRequest (and you can replace it entirely by implementing ASICacheDelegate). I'd appreciate any thoughts on this. :)

Best

Ben

Eric Scouten

unread,
Sep 8, 2010, 1:19:34 PM9/8/10
to asihttp...@googlegroups.com
Hi Ben, thanks for writing back. A few comments inline:


On Wed, Sep 8, 2010 at 04:26, Ben Copsey <b...@allseeing-i.com> wrote:

I'm not that familiar with using memory mapped files, but what would happen if the cached response was modified after the NSData instance was created? Presumably, something bad. I suppose the cache could be modified to update cached data in a different way to avoid this problem - preserving the old file, and creating a new one. I guess I'll have to think about this.

In our app, we are using the HTTP request mechanism to preload a known and stable data set onto the device, so we are using the load-only-if-not-cached policy (don't have source handy right now -- sorry if I mangled the name). It's an unusual case, I'll grant, but we know the cached data won't be changing out from under us.

For the more common case where you would check the response headers before deciding to use the cache, then I could see this being a potential race condition.

That said, it might be good to offer a version of the download cache that can take advantage of mem-mapped files. The VM system can swap out read-only pages, but not writable pages. Several speakers at WWDC encouraged app developers to use mem-mapping when reading larger data files as a way to reduce memory pressure. For smaller responses, that might not be an issue, but when you start fetching megabytes or more of data, you need to think more carefully about the memory limits of iOS devices.

It seems like this could be implemented as a configuration option or subclass of the existing ASIDownloadCache.

Related: I haven't looked, but does the timestamp of the cached file figure into the generated file name? That might be a solution for the race condition.

 
Since we're talking about the cache, I have been wondering if if would make sense to move the code in useDataFromCache into ASIDownloadCache. I think the benefits of this would be a) keeping as much of the cache-related code together as possible, and b) ASIDownloadCache is a much simpler class to modify/subclass than ASIHTTPRequest (and you can replace it entirely by implementing ASICacheDelegate). I'd appreciate any thoughts on this. :)

+1 from me!

-Eric


-- 
Eric Scouten :: software developer, photographer :: Poulsbo, WA (near Seattle)
http://ericscouten.com :: click for Flickr, Facebook, Twitter, LinkedIn links

I photoblog about where I live at :: http://thisisnorthkitsap.com

Reply all
Reply to author
Forward
0 new messages