Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Additional debug code for #2163
  • Loading branch information
dmoagx committed Oct 4, 2015
1 parent 670758d commit 80f8cae
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 25 deletions.
3 changes: 3 additions & 0 deletions Source/SPDataStorage.h
Expand Up @@ -47,6 +47,9 @@

NSUInteger numberOfColumns;
NSUInteger editedRowCount;

NSString *_debugInfo;
uint64_t _debugTime;
}

/* Setting result store */
Expand Down
121 changes: 96 additions & 25 deletions Source/SPDataStorage.m
Expand Up @@ -32,13 +32,18 @@
#import "SPObjectAdditions.h"
#import <SPMySQL/SPMySQLStreamingResultStore.h>
#include <stdlib.h>
#include <mach/mach_time.h>

@interface SPDataStorage (Private_API)

- (void) _checkNewRow:(NSMutableArray *)aRow;
- (void)_recordClearingUnloadedColumnsAt:(uint64_t)now from:(NSArray *)callStack;
- (void)_assesUnloadedColumnsIsSet;

@end

static uint64_t _elapsedMilliSecondsSinceAbsoluteTime(uint64_t comparisonTime);

@implementation SPDataStorage

static inline NSMutableArray* SPDataStorageGetEditedRow(NSPointerArray* rowStore, NSUInteger rowIndex)
Expand All @@ -60,7 +65,13 @@ - (void) setDataStorage:(SPMySQLStreamingResultStore *)newDataStorage updatingEx
NSUInteger i;
editedRowCount = 0;
SPClear(editedRows);
if (unloadedColumns) free(unloadedColumns), unloadedColumns = NULL;
@synchronized(self) {
if (unloadedColumns) {
[self _recordClearingUnloadedColumnsAt:mach_absolute_time() from:[NSThread callStackSymbols]];
free(unloadedColumns), unloadedColumns = NULL;
}
}


if (dataStorage) {

Expand All @@ -81,9 +92,11 @@ - (void) setDataStorage:(SPMySQLStreamingResultStore *)newDataStorage updatingEx
[self resultStoreDidFinishLoadingData:dataStorage];
}

unloadedColumns = calloc(numberOfColumns, sizeof(BOOL));
for (i = 0; i < numberOfColumns; i++) {
unloadedColumns[i] = NO;
@synchronized(self) {
unloadedColumns = calloc(numberOfColumns, sizeof(BOOL));
for (i = 0; i < numberOfColumns; i++) {
unloadedColumns[i] = NO;
}
}
}

Expand All @@ -110,10 +123,12 @@ - (NSMutableArray *) rowContentsAtIndex:(NSUInteger)anIndex
NSMutableArray *dataArray = SPMySQLResultStoreGetRow(dataStorage, anIndex);

// Modify unloaded cells as appropriate
for (NSUInteger i = 0; i < numberOfColumns; i++) {
NSAssert(unloadedColumns != NULL, @"unloadedColumns not loaded!");
if (unloadedColumns[i]) {
CFArraySetValueAtIndex((CFMutableArrayRef)dataArray, i, [SPNotLoaded notLoaded]);
@synchronized(self) {
[self _assesUnloadedColumnsIsSet];
for (NSUInteger i = 0; i < numberOfColumns; i++) {
if (unloadedColumns[i]) {
CFArraySetValueAtIndex((CFMutableArrayRef)dataArray, i, [SPNotLoaded notLoaded]);
}
}
}

Expand All @@ -140,9 +155,11 @@ - (id) cellDataAtRow:(NSUInteger)rowIndex column:(NSUInteger)columnIndex
}

// If the specified column is not loaded, return a SPNotLoaded reference
NSAssert(unloadedColumns != NULL, @"unloadedColumns not loaded!");
if (unloadedColumns[columnIndex]) {
return [SPNotLoaded notLoaded];
@synchronized(self) {
[self _assesUnloadedColumnsIsSet];
if (unloadedColumns[columnIndex]) {
return [SPNotLoaded notLoaded];
}
}

// Return the content
Expand Down Expand Up @@ -175,9 +192,11 @@ - (id) cellPreviewAtRow:(NSUInteger)rowIndex column:(NSUInteger)columnIndex prev
}

// If the specified column is not loaded, return a SPNotLoaded reference
NSAssert(unloadedColumns != NULL, @"unloadedColumns not loaded!");
if (unloadedColumns[columnIndex]) {
return [SPNotLoaded notLoaded];
@synchronized(self) {
[self _assesUnloadedColumnsIsSet];
if (unloadedColumns[columnIndex]) {
return [SPNotLoaded notLoaded];
}
}

// Return the content
Expand All @@ -203,9 +222,11 @@ - (BOOL) cellIsNullOrUnloadedAtRow:(NSUInteger)rowIndex column:(NSUInteger)colum
[NSException raise:NSRangeException format:@"Requested storage column (col %llu) beyond bounds (%llu)", (unsigned long long)columnIndex, (unsigned long long)numberOfColumns];
}

NSAssert(unloadedColumns != NULL, @"unloadedColumns not loaded!");
if (unloadedColumns[columnIndex]) {
return YES;
@synchronized(self) {
[self _assesUnloadedColumnsIsSet];
if (unloadedColumns[columnIndex]) {
return YES;
}
}

return [dataStorage cellIsNullAtRow:rowIndex column:columnIndex];
Expand Down Expand Up @@ -236,10 +257,12 @@ - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state object
targetRow = SPMySQLResultStoreGetRow(dataStorage, state->state);

// Modify unloaded cells as appropriate
for (NSUInteger i = 0; i < numberOfColumns; i++) {
NSAssert(unloadedColumns != NULL, @"unloadedColumns not loaded!");
if (unloadedColumns[i]) {
CFArraySetValueAtIndex((CFMutableArrayRef)targetRow, i, [SPNotLoaded notLoaded]);
@synchronized(self) {
[self _assesUnloadedColumnsIsSet];
for (NSUInteger i = 0; i < numberOfColumns; i++) {
if (unloadedColumns[i]) {
CFArraySetValueAtIndex((CFMutableArrayRef)targetRow, i, [SPNotLoaded notLoaded]);
}
}
}
}
Expand Down Expand Up @@ -397,8 +420,10 @@ - (void) setColumnAsUnloaded:(NSUInteger)columnIndex
if (columnIndex >= numberOfColumns) {
[NSException raise:NSRangeException format:@"Invalid column set as unloaded; requested column index (%llu) beyond bounds (%llu)", (unsigned long long)columnIndex, (unsigned long long)numberOfColumns];
}
NSAssert(unloadedColumns != NULL, @"unloadedColumns not loaded!");
unloadedColumns[columnIndex] = YES;
@synchronized(self) {
[self _assesUnloadedColumnsIsSet];
unloadedColumns[columnIndex] = YES;
}
}

#pragma mark - Basic information
Expand Down Expand Up @@ -451,15 +476,29 @@ - (id) init {

numberOfColumns = 0;
editedRowCount = 0;

_debugInfo = nil;
_debugTime = mach_absolute_time();
}
return self;
}

- (void) dealloc {
SPClear(dataStorage);
SPClear(editedRows);
if (unloadedColumns) free(unloadedColumns), unloadedColumns = NULL;

@synchronized(self) {
if (unloadedColumns) {
[self _recordClearingUnloadedColumnsAt:mach_absolute_time() from:[NSThread callStackSymbols]];
free(unloadedColumns), unloadedColumns = NULL;
}
}
// this is very very unlikely, but if another thread had been waiting on the lock
// right before we free'd unloadedColumns, it should get it before we can release
// _debugInfo, too.
@synchronized(self) {
SPClear(_debugInfo);
}

[super dealloc];
}

Expand All @@ -474,5 +513,37 @@ - (void) _checkNewRow:(NSMutableArray *)aRow
}
}

// DO NOT CALL THIS METHOD UNLESS YOU CURRENTLY HAVE A LOCK ON SELF!!!
- (void)_recordClearingUnloadedColumnsAt:(uint64_t)now from:(NSArray *)callStack
{
_debugTime = now;
SPClear(_debugInfo);
_debugInfo = [[NSString alloc] initWithFormat:@"Thread: %@, Stack: %@",[NSThread currentThread],callStack];
}

// DO NOT CALL THIS METHOD UNLESS YOU CURRENTLY HAVE A LOCK ON SELF!!!
- (void)_assesUnloadedColumnsIsSet
{
if(unloadedColumns != NULL)
return;

uint64_t timeDiff = _elapsedMilliSecondsSinceAbsoluteTime(_debugTime);

NSString *msg;
if(!_debugInfo)
msg = [NSString stringWithFormat:@"unloadedColumns is not set and never has been since the object was created %llums ago.",timeDiff];
else
msg = [NSString stringWithFormat:@"unloadedColumns was last cleared %llums ago at %@",timeDiff,_debugInfo];

@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:msg userInfo:nil];
}

@end

static uint64_t _elapsedMilliSecondsSinceAbsoluteTime(uint64_t comparisonTime)
{
uint64_t elapsedTime_t = mach_absolute_time() - comparisonTime;
Nanoseconds elapsedTime = AbsoluteToNanoseconds(*(AbsoluteTime *)&(elapsedTime_t));

return (UnsignedWideToUInt64(elapsedTime) / 1000000ULL);
}

0 comments on commit 80f8cae

Please sign in to comment.