diff options
Diffstat (limited to 'Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.m')
-rw-r--r-- | Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.m | 243 |
1 files changed, 121 insertions, 122 deletions
diff --git a/Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.m b/Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.m index 1a0b6b25..fdabe2e2 100644 --- a/Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.m +++ b/Frameworks/SPMySQLFramework/Source/SPMySQLStreamingResultStore.m @@ -672,148 +672,147 @@ static inline void SPMySQLStreamingResultStoreFreeRowData(SPMySQLStreamingResult */ - (void)_downloadAllData { - NSAutoreleasePool *downloadPool = [[NSAutoreleasePool alloc] init]; - MYSQL_ROW theRow; - unsigned long *fieldLengths; - NSUInteger i, dataCopiedLength, rowDataLength; - SPMySQLStreamingResultStoreRowData *newRowStore; - - [[NSThread currentThread] setName:@"SPMySQLStreamingResultStore data download thread"]; - - size_t sizeOfMetadata, lengthOfMetadata; - size_t lengthOfNullRecords = (size_t)(sizeof(BOOL) * numberOfFields); - size_t sizeOfChar = sizeof(char); - - // Loop through the rows until the end of the data is reached - indicated via a NULL - while ( - (*isConnectedPtr)(parentConnection, isConnectedSelector) - && (theRow = mysql_fetch_row(resultSet)) - ) { - // If the load has been cancelled, skip any processing - we're only interested - // in ensuring that mysql_fetch_row is called for all rows. - if (loadCancelled) { - continue; - } + @autoreleasepool { + MYSQL_ROW theRow; + unsigned long *fieldLengths; + NSUInteger i, dataCopiedLength, rowDataLength; + SPMySQLStreamingResultStoreRowData *newRowStore; + + [[NSThread currentThread] setName:@"SPMySQLStreamingResultStore data download thread"]; + + size_t sizeOfMetadata, lengthOfMetadata; + size_t lengthOfNullRecords = (size_t)(sizeof(BOOL) * numberOfFields); + size_t sizeOfChar = sizeof(char); + + // Loop through the rows until the end of the data is reached - indicated via a NULL + while ( + (*isConnectedPtr)(parentConnection, isConnectedSelector) + && (theRow = mysql_fetch_row(resultSet)) + ) { + // If the load has been cancelled, skip any processing - we're only interested + // in ensuring that mysql_fetch_row is called for all rows. + if (loadCancelled) { + continue; + } - // The row store is a single block of memory. It's made up of four blocks of data: - // Firstly, a single char containing the type of data used to store positions. - // Secondly, a series of those types recording the *end position* of each field - // Thirdly, a series of BOOLs recording whether the fields are NULLS - which can't just be from length - // Finally, a char sequence comprising the actual cell data, which can be looked up by position/length. - - // Retrieve the lengths of the returned data, and calculate the overall length of data - fieldLengths = mysql_fetch_lengths(resultSet); - rowDataLength = 0; - for (i = 0; i < numberOfFields; i++) { - rowDataLength += fieldLengths[i]; - } + // The row store is a single block of memory. It's made up of four blocks of data: + // Firstly, a single char containing the type of data used to store positions. + // Secondly, a series of those types recording the *end position* of each field + // Thirdly, a series of BOOLs recording whether the fields are NULLS - which can't just be from length + // Finally, a char sequence comprising the actual cell data, which can be looked up by position/length. - // Depending on the length of the row, vary the metadata size appropriately. This - // makes defining the data processing much lengthier, but is worth it to reduce the - // overhead for small rows. - if (rowDataLength <= UCHAR_MAX) { - sizeOfMetadata = SPMySQLStoreMetadataAsChar; - } else if (rowDataLength <= USHRT_MAX) { - sizeOfMetadata = SPMySQLStoreMetadataAsShort; - } else { - sizeOfMetadata = SPMySQLStoreMetadataAsLong; - } - lengthOfMetadata = sizeOfMetadata * numberOfFields; + // Retrieve the lengths of the returned data, and calculate the overall length of data + fieldLengths = mysql_fetch_lengths(resultSet); + rowDataLength = 0; + for (i = 0; i < numberOfFields; i++) { + rowDataLength += fieldLengths[i]; + } - // Allocate the memory for the row and set the type marker - newRowStore = malloc_zone_malloc(storageMallocZone, 1 + lengthOfMetadata + lengthOfNullRecords + (rowDataLength * sizeOfChar)); - newRowStore[0] = sizeOfMetadata; + // Depending on the length of the row, vary the metadata size appropriately. This + // makes defining the data processing much lengthier, but is worth it to reduce the + // overhead for small rows. + if (rowDataLength <= UCHAR_MAX) { + sizeOfMetadata = SPMySQLStoreMetadataAsChar; + } else if (rowDataLength <= USHRT_MAX) { + sizeOfMetadata = SPMySQLStoreMetadataAsShort; + } else { + sizeOfMetadata = SPMySQLStoreMetadataAsLong; + } + lengthOfMetadata = sizeOfMetadata * numberOfFields; + + // Allocate the memory for the row and set the type marker + newRowStore = malloc_zone_malloc(storageMallocZone, 1 + lengthOfMetadata + lengthOfNullRecords + (rowDataLength * sizeOfChar)); + newRowStore[0] = sizeOfMetadata; + + // Set the data end positions. Manually unroll the logic for the different cases; messy + // but again worth the large memory savings for smaller rows + rowDataLength = 0; + switch (sizeOfMetadata) { + case SPMySQLStoreMetadataAsLong: + for (i = 0; i < numberOfFields; i++) { + rowDataLength += fieldLengths[i]; + ((unsigned long *)(newRowStore + 1))[i] = rowDataLength; + ((BOOL *)(newRowStore + 1 + lengthOfMetadata))[i] = (theRow[i] == NULL); + } + break; + case SPMySQLStoreMetadataAsShort: + for (i = 0; i < numberOfFields; i++) { + rowDataLength += fieldLengths[i]; + ((unsigned short *)(newRowStore + 1))[i] = rowDataLength; + ((BOOL *)(newRowStore + 1 + lengthOfMetadata))[i] = (theRow[i] == NULL); + } + break; + case SPMySQLStoreMetadataAsChar: + for (i = 0; i < numberOfFields; i++) { + rowDataLength += fieldLengths[i]; + ((unsigned char *)(newRowStore + 1))[i] = rowDataLength; + ((BOOL *)(newRowStore + 1 + lengthOfMetadata))[i] = (theRow[i] == NULL); + } + break; + } - // Set the data end positions. Manually unroll the logic for the different cases; messy - // but again worth the large memory savings for smaller rows - rowDataLength = 0; - switch (sizeOfMetadata) { - case SPMySQLStoreMetadataAsLong: - for (i = 0; i < numberOfFields; i++) { - rowDataLength += fieldLengths[i]; - ((unsigned long *)(newRowStore + 1))[i] = rowDataLength; - ((BOOL *)(newRowStore + 1 + lengthOfMetadata))[i] = (theRow[i] == NULL); - } - break; - case SPMySQLStoreMetadataAsShort: - for (i = 0; i < numberOfFields; i++) { - rowDataLength += fieldLengths[i]; - ((unsigned short *)(newRowStore + 1))[i] = rowDataLength; - ((BOOL *)(newRowStore + 1 + lengthOfMetadata))[i] = (theRow[i] == NULL); - } - break; - case SPMySQLStoreMetadataAsChar: + // If the row has content, copy it in + if (rowDataLength) { + dataCopiedLength = 1 + lengthOfMetadata + lengthOfNullRecords; for (i = 0; i < numberOfFields; i++) { - rowDataLength += fieldLengths[i]; - ((unsigned char *)(newRowStore + 1))[i] = rowDataLength; - ((BOOL *)(newRowStore + 1 + lengthOfMetadata))[i] = (theRow[i] == NULL); - } - break; - } - - // If the row has content, copy it in - if (rowDataLength) { - dataCopiedLength = 1 + lengthOfMetadata + lengthOfNullRecords; - for (i = 0; i < numberOfFields; i++) { - if (theRow[i] != NULL) { - memcpy(newRowStore + dataCopiedLength, theRow[i], fieldLengths[i]); - dataCopiedLength += fieldLengths[i]; + if (theRow[i] != NULL) { + memcpy(newRowStore + dataCopiedLength, theRow[i], fieldLengths[i]); + dataCopiedLength += fieldLengths[i]; + } } } - } - // Lock the data mutex - pthread_mutex_lock(&dataLock); + // Lock the data mutex + pthread_mutex_lock(&dataLock); - // Ensure that sufficient capacity is available - SPMySQLStreamingResultStoreEnsureCapacityForAdditionalRowCount(self, 1); + // Ensure that sufficient capacity is available + SPMySQLStreamingResultStoreEnsureCapacityForAdditionalRowCount(self, 1); - // Add the newly allocated row to the storage - if (rowDownloadIterator < numberOfRows) { - SPMySQLStreamingResultStoreFreeRowData(dataStorage[rowDownloadIterator]); - } - dataStorage[rowDownloadIterator] = newRowStore; - rowDownloadIterator++; + // Add the newly allocated row to the storage + if (rowDownloadIterator < numberOfRows) { + SPMySQLStreamingResultStoreFreeRowData(dataStorage[rowDownloadIterator]); + } + dataStorage[rowDownloadIterator] = newRowStore; + rowDownloadIterator++; - // Update the total row count if exceeded - if (rowDownloadIterator > numberOfRows) { - numberOfRows++; - } + // Update the total row count if exceeded + if (rowDownloadIterator > numberOfRows) { + numberOfRows++; + } - // Unlock the mutex - pthread_mutex_unlock(&dataLock); - } + // Unlock the mutex + pthread_mutex_unlock(&dataLock); + } - // Update the total number of rows in the result set now download - // is complete, freeing extra rows from a previous result set - if (numberOfRows > rowDownloadIterator) { - pthread_mutex_lock(&dataLock); - while (numberOfRows > rowDownloadIterator) { - SPMySQLStreamingResultStoreFreeRowData(dataStorage[--numberOfRows]); + // Update the total number of rows in the result set now download + // is complete, freeing extra rows from a previous result set + if (numberOfRows > rowDownloadIterator) { + pthread_mutex_lock(&dataLock); + while (numberOfRows > rowDownloadIterator) { + SPMySQLStreamingResultStoreFreeRowData(dataStorage[--numberOfRows]); + } + pthread_mutex_unlock(&dataLock); } - pthread_mutex_unlock(&dataLock); - } - // Update the connection's error statuses to reflect any errors during the content download - [parentConnection _updateLastErrorInfos]; + // Update the connection's error statuses to reflect any errors during the content download + [parentConnection _updateLastErrorInfos]; - // Unlock the parent connection now all data has been retrieved - [parentConnection _unlockConnection]; - connectionUnlocked = YES; + // Unlock the parent connection now all data has been retrieved + [parentConnection _unlockConnection]; + connectionUnlocked = YES; - // If the connection query may have been cancelled with a query kill, double-check connection - if ([parentConnection lastQueryWasCancelled] && [parentConnection serverMajorVersion] < 5) { - [parentConnection checkConnection]; - } + // If the connection query may have been cancelled with a query kill, double-check connection + if ([parentConnection lastQueryWasCancelled] && [parentConnection serverMajorVersion] < 5) { + [parentConnection checkConnection]; + } - dataDownloaded = YES; + dataDownloaded = YES; - // Inform the delegate the download was completed - if ([delegate respondsToSelector:@selector(resultStoreDidFinishLoadingData:)]) { - [delegate resultStoreDidFinishLoadingData:self]; + // Inform the delegate the download was completed + if ([delegate respondsToSelector:@selector(resultStoreDidFinishLoadingData:)]) { + [delegate resultStoreDidFinishLoadingData:self]; + } } - - [downloadPool drain]; } /** |