From 1d7de2c00dae782992e1c082fbf3e98fe3666b88 Mon Sep 17 00:00:00 2001 From: rowanbeentje Date: Mon, 26 Apr 2010 23:42:32 +0000 Subject: - Improve threading of SPFileHandle to achieve much faster writing due to increased separation of the writing thread. This results in a up-to 1.2x faster MySQL dump for fast servers, and makes SPFileHandle faster than NSFileHandle for writing data (either directly or GZIP compressed). --- Source/SPFileHandle.h | 1 + Source/SPFileHandle.m | 39 ++++++++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/Source/SPFileHandle.h b/Source/SPFileHandle.h index 05a8da0e..05e05dd5 100644 --- a/Source/SPFileHandle.h +++ b/Source/SPFileHandle.h @@ -44,6 +44,7 @@ int fileMode; BOOL dataWritten; + BOOL allDataWritten; BOOL fileIsClosed; BOOL useGzip; } diff --git a/Source/SPFileHandle.m b/Source/SPFileHandle.m index e0838a6d..bceae2aa 100644 --- a/Source/SPFileHandle.m +++ b/Source/SPFileHandle.m @@ -51,6 +51,8 @@ - (id) initWithFile:(void *)theFile fromPath:(const char *)path mode:(int)mode { if (self = [super init]) { + dataWritten = NO; + allDataWritten = YES; fileIsClosed = NO; wrappedFile = theFile; @@ -216,9 +218,12 @@ if (fileIsClosed) [NSException raise:NSInternalInconsistencyException format:@"Cannot write to a file handle after it has been closed"]; // Add the data to the buffer - pthread_mutex_lock(&bufferLock); - [buffer appendData:data]; - bufferDataLength += [data length]; + if ([data length]) { + pthread_mutex_lock(&bufferLock); + [buffer appendData:data]; + allDataWritten = NO; + bufferDataLength += [data length]; + } // If the buffer is large, wait for some to be written out while (bufferDataLength > SPFH_MAX_WRITE_BUFFER_SIZE) { @@ -235,7 +240,7 @@ - (void) synchronizeFile { pthread_mutex_lock(&bufferLock); - while (bufferDataLength) { + while (!allDataWritten) { pthread_mutex_unlock(&bufferLock); usleep(100); pthread_mutex_lock(&bufferLock); @@ -302,17 +307,33 @@ continue; } + // Copy the data into a local buffer + NSData *dataToBeWritten = [NSData dataWithData:buffer]; + [buffer setLength:0]; + bufferDataLength = 0; + pthread_mutex_unlock(&bufferLock); + // Write out the data long bufferLengthWrittenOut; if (useGzip) { - bufferLengthWrittenOut = gzwrite(wrappedFile, [buffer bytes], bufferDataLength); + bufferLengthWrittenOut = gzwrite(wrappedFile, [dataToBeWritten bytes], [dataToBeWritten length]); } else { - bufferLengthWrittenOut = fwrite([buffer bytes], 1, bufferDataLength, wrappedFile); + bufferLengthWrittenOut = fwrite([dataToBeWritten bytes], 1, [dataToBeWritten length], wrappedFile); } - // Update the buffer - CFDataDeleteBytes((CFMutableDataRef)buffer, CFRangeMake(0, bufferLengthWrittenOut)); - bufferDataLength = 0; + // Restore data to the buffer if it wasn't written out + pthread_mutex_lock(&bufferLock); + if (bufferLengthWrittenOut < [dataToBeWritten length]) { + if ([buffer length]) { + long dataLengthToRestore = [dataToBeWritten length] - bufferLengthWrittenOut; + [buffer replaceBytesInRange:NSMakeRange(0, 0) withBytes:[[dataToBeWritten subdataWithRange:NSMakeRange(bufferLengthWrittenOut, dataLengthToRestore)] bytes] length:dataLengthToRestore]; + bufferDataLength += dataLengthToRestore; + } + + // Otherwise, mark all data as written if it has been - allows synching to hard disk. + } else if (![buffer length]) { + allDataWritten = YES; + } pthread_mutex_unlock(&bufferLock); } -- cgit v1.2.3