Ben Copsey

Optimise appendPostDataFromFile: to remove temporary memory use spike

Fiddle with iPhone upload sample to demonstrate file streaming
@@ -213,18 +213,18 @@ static NSError *ASIUnableToCreateRequestError; @@ -213,18 +213,18 @@ static NSError *ASIUnableToCreateRequestError;
213 [self setupPostBody]; 213 [self setupPostBody];
214 NSInputStream *stream = [[[NSInputStream alloc] initWithFileAtPath:file] autorelease]; 214 NSInputStream *stream = [[[NSInputStream alloc] initWithFileAtPath:file] autorelease];
215 [stream open]; 215 [stream open];
216 - NSMutableData *d; 216 + int bytesRead;
217 while ([stream hasBytesAvailable]) { 217 while ([stream hasBytesAvailable]) {
218 - d = [NSMutableData dataWithLength:256*1024]; 218 +
219 - int bytesRead = [stream read:[d mutableBytes] maxLength:256*1024]; 219 + unsigned char buffer[1024*256];
  220 + bytesRead = [stream read:buffer maxLength:sizeof(buffer)];
220 if (bytesRead == 0) { 221 if (bytesRead == 0) {
221 break; 222 break;
222 } 223 }
223 - [d setLength:bytesRead];  
224 if ([self shouldStreamPostDataFromDisk]) { 224 if ([self shouldStreamPostDataFromDisk]) {
225 - [[self postBodyWriteStream] write:[d mutableBytes] maxLength:bytesRead]; 225 + [[self postBodyWriteStream] write:buffer maxLength:bytesRead];
226 } else { 226 } else {
227 - [[self postBody] appendData:[NSData dataWithBytes:[d mutableBytes] length:bytesRead]]; 227 + [[self postBody] appendData:[NSData dataWithBytes:buffer length:bytesRead]];
228 } 228 }
229 } 229 }
230 [stream close]; 230 [stream close];
@@ -30,7 +30,17 @@ @@ -30,7 +30,17 @@
30 [request setPostValue:@"test" forKey:@"value2"]; 30 [request setPostValue:@"test" forKey:@"value2"];
31 [request setPostValue:@"test" forKey:@"value3"]; 31 [request setPostValue:@"test" forKey:@"value3"];
32 [request setTimeOutSeconds:20]; 32 [request setTimeOutSeconds:20];
33 - [request setData:[NSMutableData dataWithLength:1024*1024] forKey:@"1mb-of-crap"]; 33 +
  34 + //Create a 256KB file
  35 + NSData *data = [[[NSMutableData alloc] initWithLength:256*1024] autorelease];
  36 + NSString *path = [[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"file"];
  37 + [data writeToFile:path atomically:NO];
  38 +
  39 + //Add the file 8 times to the request, for a total request size around 4MB
  40 + int i;
  41 + for (i=0; i<16; i++) {
  42 + [request setFile:path forKey:[NSString stringWithFormat:@"file-%hi",i]];
  43 + }
34 44
35 [networkQueue addOperation:request]; 45 [networkQueue addOperation:request];
36 [networkQueue go]; 46 [networkQueue go];
This diff was suppressed by a .gitattributes entry.