From db22d5f586a31ac6bda36ded783fdc2cce8c2c87 Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Mon, 24 Jul 2017 15:56:06 +0200 Subject: [PATCH 01/21] Correcting some parameters due to a compilation Bug in LLVM CLANG ;; OTHER_CFLAGS = "-I/usr/local/include"; Correcting some Typos in program --- postgresql-kit.xcodeproj/project.pbxproj | 6 ++++-- src/Apps/Foundation/PGFoundationClient.m | 26 ++++++++++++------------ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/postgresql-kit.xcodeproj/project.pbxproj b/postgresql-kit.xcodeproj/project.pbxproj index ad99b00..c4d91cf 100644 --- a/postgresql-kit.xcodeproj/project.pbxproj +++ b/postgresql-kit.xcodeproj/project.pbxproj @@ -2839,7 +2839,8 @@ GCC_OPTIMIZATION_LEVEL = s; GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx10.9; + OTHER_CFLAGS = "-I/usr/local/include"; + SDKROOT = macosx; STRIP_INSTALLED_PRODUCT = NO; }; name = Debug; @@ -2848,7 +2849,8 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; - SDKROOT = macosx10.9; + OTHER_CFLAGS = "-I/usr/local/include"; + SDKROOT = macosx; }; name = Release; }; diff --git a/src/Apps/Foundation/PGFoundationClient.m b/src/Apps/Foundation/PGFoundationClient.m index 14eb8b1..d7313d9 100644 --- a/src/Apps/Foundation/PGFoundationClient.m +++ b/src/Apps/Foundation/PGFoundationClient.m @@ -127,7 +127,7 @@ -(void)connect:(NSURL* )url { } -(void)execute:(id)query { - [[self db] executeQuery:query whenDone:^(PGResult* result, NSError* error) { + [[self db] execute:query whenDone:^(PGResult* result, NSError* error) { if(error) { [[self term] printf:@"Error: %@ (%@/%ld)",[error localizedDescription],[error domain],[error code]]; } @@ -183,7 +183,7 @@ -(void)command:(NSString* )command args:(NSArray* )args { [[self term] printf:@"error: tables: too many arguments"]; } else { PGQueryObject* query = [PGQuery queryWithString:@"SELECT datname AS database,pid AS pid,query AS query,usename AS username,client_hostname AS remotehost,application_name,query_start,waiting FROM pg_stat_activity WHERE pid <> pg_backend_pid()"]; - [[self db] executeQuery:query whenDone:^(PGResult* result, NSError* error) { + [[self db] execute:query whenDone:^(PGResult* result, NSError* error) { if(result) { [self displayResult:result]; } @@ -218,9 +218,9 @@ -(void)command:(NSString* )command args:(NSArray* )args { [[self term] printf:@"error: table: not enough arguments"]; return; } - PGQueryObject* query = [PGQuerySelect select:[PGQuerySource sourceWithTable:tableName schema:schemaName alias:nil] options:0]; + PGQueryObject* query = [PGQuerySelect select:[PGQuerySource table:tableName schema:schemaName alias:nil] options:0]; NSParameterAssert(query); - [[self db] executeQuery:query whenDone:^(PGResult* result, NSError* error) { + [[self db] execute:query whenDone:^(PGResult* result, NSError* error) { if(result) { [self displayResult:result]; } @@ -241,7 +241,7 @@ -(void)command:(NSString* )command args:(NSArray* )args { } PGQuery* query = [PGQueryRole create:roleName options:0]; NSParameterAssert(query); - [[self db] executeQuery:query whenDone:^(PGResult* result, NSError* error) { + [[self db] execute:query whenDone:^(PGResult* result, NSError* error) { if(result) { [self displayResult:result]; } @@ -262,7 +262,7 @@ -(void)command:(NSString* )command args:(NSArray* )args { } PGQuery* query = [PGQueryRole drop:roleName options:0]; NSParameterAssert(query); - [[self db] executeQuery:query whenDone:^(PGResult* result, NSError* error) { + [[self db] execute:query whenDone:^(PGResult* result, NSError* error) { if(result) { [self displayResult:result]; } @@ -283,7 +283,7 @@ -(void)command:(NSString* )command args:(NSArray* )args { } PGQuery* query = [PGQueryDatabase create:databaseName options:0]; NSParameterAssert(query); - [[self db] executeQuery:query whenDone:^(PGResult* result, NSError* error) { + [[self db] execute:query whenDone:^(PGResult* result, NSError* error) { if(result) { [self displayResult:result]; } @@ -304,7 +304,7 @@ -(void)command:(NSString* )command args:(NSArray* )args { } PGQuery* query = [PGQueryDatabase drop:databaseName options:0]; NSParameterAssert(query); - [[self db] executeQuery:query whenDone:^(PGResult* result, NSError* error) { + [[self db] execute:query whenDone:^(PGResult* result, NSError* error) { if(result) { [self displayResult:result]; } @@ -325,7 +325,7 @@ -(void)command:(NSString* )command args:(NSArray* )args { } PGQuery* query = [PGQuerySchema create:schemaName options:0]; NSParameterAssert(query); - [[self db] executeQuery:query whenDone:^(PGResult* result, NSError* error) { + [[self db] execute:query whenDone:^(PGResult* result, NSError* error) { if(result) { [self displayResult:result]; } @@ -346,7 +346,7 @@ -(void)command:(NSString* )command args:(NSArray* )args { } PGQuery* query = [PGQuerySchema drop:schemaName options:0]; NSParameterAssert(query); - [[self db] executeQuery:query whenDone:^(PGResult* result, NSError* error) { + [[self db] execute:query whenDone:^(PGResult* result, NSError* error) { if(result) { [self displayResult:result]; } @@ -360,7 +360,7 @@ -(void)command:(NSString* )command args:(NSArray* )args { if([command isEqualToString:@"listschemas"]) { PGQuery* query = [PGQuerySchema listWithOptions:0]; NSParameterAssert(query); - [[self db] executeQuery:query whenDone:^(PGResult* result, NSError* error) { + [[self db] execute:query whenDone:^(PGResult* result, NSError* error) { if(result) { [self displayResult:result]; } @@ -374,7 +374,7 @@ -(void)command:(NSString* )command args:(NSArray* )args { if([command isEqualToString:@"listroles"]) { PGQuery* query = [PGQueryRole listWithOptions:0]; NSParameterAssert(query); - [[self db] executeQuery:query whenDone:^(PGResult* result, NSError* error) { + [[self db] execute:query whenDone:^(PGResult* result, NSError* error) { if(result) { [self displayResult:result]; } @@ -392,7 +392,7 @@ -(void)command:(NSString* )command args:(NSArray* )args { [query addColumn:@"y" alias:@"col2"]; NSParameterAssert(query); - [[self db] executeQuery:query whenDone:^(PGResult* result, NSError* error) { + [[self db] execute:query whenDone:^(PGResult* result, NSError* error) { if(result) { [self displayResult:result]; } From 35f5ffb60b811fa3289f398fc4442ed9a9ffd5ac Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Mon, 24 Jul 2017 19:28:55 +0200 Subject: [PATCH 02/21] PGConnection : 78 NSAssert bug ... TODO --- postgresql-kit.xcodeproj/project.pbxproj | 11 ++++++++--- src/Frameworks/PGClientKit/PGConnection+Execute.m | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/postgresql-kit.xcodeproj/project.pbxproj b/postgresql-kit.xcodeproj/project.pbxproj index c4d91cf..2d75454 100644 --- a/postgresql-kit.xcodeproj/project.pbxproj +++ b/postgresql-kit.xcodeproj/project.pbxproj @@ -202,7 +202,7 @@ 6E48CD7D1A73FC350060B429 /* Queries.md in CopyFiles */ = {isa = PBXBuildFile; fileRef = 6E48CD7B1A73FC2B0060B429 /* Queries.md */; }; 6E4DEC87162CC38D008B26BD /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6E8C168115F26BF20013A382 /* Foundation.framework */; }; 6E4DEC95162CC4AB008B26BD /* PGClientKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 6ED85B4916288D0200A6DC02 /* PGClientKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 6E4DEC96162CC5E6008B26BD /* PGClientKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6ED85B4616288C4800A6DC02 /* PGClientKit.framework */; }; + 6E4DEC96162CC5E6008B26BD /* PGClientKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6ED85B4616288C4800A6DC02 /* PGClientKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 6E50183B1AC9BAD000D6D967 /* PGTabView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E50183A1AC9BAD000D6D967 /* PGTabView.m */; }; 6E5018411ACA90D900D6D967 /* PGTabViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E5018401ACA90D900D6D967 /* PGTabViewCell.m */; }; 6E55A2321A618C6B00CD2B60 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6E55A2311A618C6B00CD2B60 /* main.m */; }; @@ -484,7 +484,7 @@ 6E4DEC83162CC38D008B26BD /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; + dstPath = /usr/share/man/man1; dstSubfolderSpec = 0; files = ( ); @@ -2837,7 +2837,10 @@ buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; GCC_OPTIMIZATION_LEVEL = s; - GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG2=1", + "DEBUG=1", + ); ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "-I/usr/local/include"; SDKROOT = macosx; @@ -2902,6 +2905,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; + LD_RUNPATH_SEARCH_PATHS = "${BUILT_PRODUCTS_DIR}"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -2919,6 +2923,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; + LD_RUNPATH_SEARCH_PATHS = "${BUILT_PRODUCTS_DIR}"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; diff --git a/src/Frameworks/PGClientKit/PGConnection+Execute.m b/src/Frameworks/PGClientKit/PGConnection+Execute.m index 33f6a34..9d3e2a2 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Execute.m +++ b/src/Frameworks/PGClientKit/PGConnection+Execute.m @@ -76,7 +76,7 @@ -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGR [self setState:PGConnectionStateQuery]; [self _updateStatus]; - NSParameterAssert(_callback==nil); + NSParameterAssert(_callback!=nil); _callback = (__bridge_retained void* )[callback copy]; } From f8b2819dd2bdf4d3377255dbfd5ce9c5fbd9cca6 Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Thu, 27 Jul 2017 12:48:46 +0200 Subject: [PATCH 03/21] workaround _callback to pool for concurrent operation --- postgresql-kit.xcodeproj/project.pbxproj | 21 +- .../contents.xcworkspacedata | 3 - src/Apps/Foundation/PGFoundationClient.h | 6 +- src/Apps/Foundation/PGFoundationClient.m | 20 +- .../PGClientKit/NSURL+PGAdditions.m | 21 +- src/Frameworks/PGClientKit/PGClientKit.h | 3 + .../PGClientKit/PGConnection+Callbacks.m | 148 +++++- .../PGClientKit/PGConnection+Connect.m | 7 +- .../PGClientKit/PGConnection+Errors.m | 31 +- .../PGClientKit/PGConnection+Execute.m | 46 +- src/Frameworks/PGClientKit/PGConnection.h | 18 +- src/Frameworks/PGClientKit/PGConnection.m | 481 +++++++++++------- .../PGClientKit/PGConnectionOperation.h | 51 ++ .../PGClientKit/PGConnectionOperation.m | 134 +++++ src/Frameworks/PGClientKit/PGPasswordStore.m | 8 +- src/Frameworks/PGClientKit/PGQueryObject.h | 4 + src/Frameworks/PGClientKit/PGQueryObject.m | 18 +- src/Frameworks/PGClientKit/PGQueryUpdate.m | 3 + 18 files changed, 778 insertions(+), 245 deletions(-) create mode 100644 src/Frameworks/PGClientKit/PGConnectionOperation.h create mode 100644 src/Frameworks/PGClientKit/PGConnectionOperation.m diff --git a/postgresql-kit.xcodeproj/project.pbxproj b/postgresql-kit.xcodeproj/project.pbxproj index 2d75454..62ebd16 100644 --- a/postgresql-kit.xcodeproj/project.pbxproj +++ b/postgresql-kit.xcodeproj/project.pbxproj @@ -326,6 +326,13 @@ 6EFFF2351A5F04C800CAA6E7 /* PGFoundationApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 6EFFF2311A5F044E00CAA6E7 /* PGFoundationApp.m */; }; 6EFFF23A1A5F052A00CAA6E7 /* PGFoundationApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 6EFFF2311A5F044E00CAA6E7 /* PGFoundationApp.m */; }; 6EFFF23C1A5F053000CAA6E7 /* Terminal.m in Sources */ = {isa = PBXBuildFile; fileRef = 6EFFF2391A5F051D00CAA6E7 /* Terminal.m */; }; + C6457D4E1F288DD7005F6686 /* PGConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C6457D4A1F288DD7005F6686 /* PGConnectionOperation.m */; }; + C6457D4F1F288DD7005F6686 /* PGConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C6457D4A1F288DD7005F6686 /* PGConnectionOperation.m */; }; + C6457D501F288DD7005F6686 /* PGConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C6457D4A1F288DD7005F6686 /* PGConnectionOperation.m */; }; + C6457D511F288DD7005F6686 /* PGConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C6457D4A1F288DD7005F6686 /* PGConnectionOperation.m */; }; + C6457D671F28F470005F6686 /* PGConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C6457D4A1F288DD7005F6686 /* PGConnectionOperation.m */; }; + C6457D681F28F475005F6686 /* PGConnectionOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = C6457D491F288DD7005F6686 /* PGConnectionOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C6457D691F28F478005F6686 /* PGConnectionOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = C6457D491F288DD7005F6686 /* PGConnectionOperation.h */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -846,6 +853,8 @@ 6EFFF2331A5F044E00CAA6E7 /* PGFoundationServer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PGFoundationServer.m; sourceTree = ""; }; 6EFFF2381A5F051D00CAA6E7 /* Terminal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Terminal.h; sourceTree = ""; }; 6EFFF2391A5F051D00CAA6E7 /* Terminal.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Terminal.m; sourceTree = ""; }; + C6457D491F288DD7005F6686 /* PGConnectionOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PGConnectionOperation.h; path = src/Frameworks/PGClientKit/PGConnectionOperation.h; sourceTree = SOURCE_ROOT; }; + C6457D4A1F288DD7005F6686 /* PGConnectionOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PGConnectionOperation.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1694,6 +1703,8 @@ 6ED85B3316288BEF00A6DC02 /* PGClientKit */ = { isa = PBXGroup; children = ( + C6457D491F288DD7005F6686 /* PGConnectionOperation.h */, + C6457D4A1F288DD7005F6686 /* PGConnectionOperation.m */, 1413DF1D17AD79AC009615E5 /* PGClientKit_ios.plist */, 1413DF1E17AD79AC009615E5 /* PGClientKit_mac.plist */, 6ED85B4916288D0200A6DC02 /* PGClientKit.h */, @@ -1809,6 +1820,7 @@ 6E0DDCF61AAB74B100A38F3B /* PGQueryTableView.h in Headers */, 6EC6748E1AD94FC700CAB4FF /* NSError+PGAdditions.h in Headers */, 6EC674871AD94F6100CAB4FF /* PGQueryInsert.h in Headers */, + C6457D691F28F478005F6686 /* PGConnectionOperation.h in Headers */, 1450A1681AAA18DA002D62D9 /* PGQueryPredicate.h in Headers */, 6E1548441A5819AC00556573 /* PGClientKit.h in Headers */, 1450A15F1AAA145A002D62D9 /* PGQuerySource.h in Headers */, @@ -1834,6 +1846,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + C6457D681F28F475005F6686 /* PGConnectionOperation.h in Headers */, 6E4DEC95162CC4AB008B26BD /* PGClientKit.h in Headers */, 6E0DDCE31AAB6F5200A38F3B /* PGQueryDatabase.h in Headers */, 149BA1A41AA6FB54007B86A0 /* PGQuerySelect.h in Headers */, @@ -2413,6 +2426,7 @@ 6E15484E1A5819F000556573 /* PGQuery.m in Sources */, 6EC6748F1AD94FCC00CAB4FF /* NSError+PGAdditions.m in Sources */, 6E9256BC1AA64BDA007DAD82 /* PGConnection+Execute.m in Sources */, + C6457D4E1F288DD7005F6686 /* PGConnectionOperation.m in Sources */, 6E1548581A581F2B00556573 /* SSKeychain.m in Sources */, 6E0DDCF81AAB74B100A38F3B /* PGQueryTableView.m in Sources */, ); @@ -2432,6 +2446,7 @@ files = ( 14FD07261AA711210013557E /* GBCommandLineParser.m in Sources */, 6EFFF23C1A5F053000CAA6E7 /* Terminal.m in Sources */, + C6457D501F288DD7005F6686 /* PGConnectionOperation.m in Sources */, 14FD07251AA7111E0013557E /* GBOptionsHelper.m in Sources */, 14FD07231AA711140013557E /* GBSettings.m in Sources */, 6EFFF23A1A5F052A00CAA6E7 /* PGFoundationApp.m in Sources */, @@ -2446,6 +2461,7 @@ files = ( 6E6154D01AC6F84B00541DDE /* LogController.m in Sources */, 6E55A2321A618C6B00CD2B60 /* main.m in Sources */, + C6457D511F288DD7005F6686 /* PGConnectionOperation.m in Sources */, 6E55A2341A618CD300CD2B60 /* Application.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2478,6 +2494,7 @@ 6EFFF2341A5F04C500CAA6E7 /* PGFoundationServer.m in Sources */, 14C245E51AB6C770005ED153 /* GBCommandLineParser.m in Sources */, 14C245DF1AB6C766005ED153 /* GBSettings.m in Sources */, + C6457D4F1F288DD7005F6686 /* PGConnectionOperation.m in Sources */, 14C245E31AB6C76A005ED153 /* GBPrint.m in Sources */, 6EFFF2351A5F04C800CAA6E7 /* PGFoundationApp.m in Sources */, 14C245E41AB6C76D005ED153 /* GBOptionsHelper.m in Sources */, @@ -2524,6 +2541,7 @@ 6E0DDCEB1AAB721600A38F3B /* PGQueryRole.m in Sources */, 1450A1691AAA18DA002D62D9 /* PGQueryPredicate.m in Sources */, 6E0DDCE51AAB6F5200A38F3B /* PGQueryDatabase.m in Sources */, + C6457D671F28F470005F6686 /* PGConnectionOperation.m in Sources */, 14DECDA616B56DF300178235 /* PGConverters+Data2Object.m in Sources */, 6EAA40ED17BC150E0078EB32 /* NSURL+PGAdditions.m in Sources */, 147070E31A976E230069EF9C /* NSString+PGNetworkValidationAdditions.m in Sources */, @@ -2836,7 +2854,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; - GCC_OPTIMIZATION_LEVEL = s; + GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG2=1", "DEBUG=1", @@ -2852,6 +2870,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; + GCC_OPTIMIZATION_LEVEL = 0; OTHER_CFLAGS = "-I/usr/local/include"; SDKROOT = macosx; }; diff --git a/postgresql-kit.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/postgresql-kit.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 3e4714f..94b2795 100644 --- a/postgresql-kit.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/postgresql-kit.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -1,7 +1,4 @@ - - diff --git a/src/Apps/Foundation/PGFoundationClient.h b/src/Apps/Foundation/PGFoundationClient.h index 08057d3..0451c3a 100644 --- a/src/Apps/Foundation/PGFoundationClient.h +++ b/src/Apps/Foundation/PGFoundationClient.h @@ -19,9 +19,9 @@ #import "Terminal.h" @interface PGFoundationClient : PGFoundationApp { - PGConnection* _db; - PGPasswordStore* _passwordstore; - Terminal* _term; + // PGConnection* _db; + // PGPasswordStore* _passwordstore; + // Terminal* _term; } // properties diff --git a/src/Apps/Foundation/PGFoundationClient.m b/src/Apps/Foundation/PGFoundationClient.m index d7313d9..706abc6 100644 --- a/src/Apps/Foundation/PGFoundationClient.m +++ b/src/Apps/Foundation/PGFoundationClient.m @@ -1,4 +1,4 @@ - + // Copyright 2009-2015 David Thorpe // https://github.com/djthorpe/postgresql-kit // @@ -15,7 +15,9 @@ #import "PGFoundationClient.h" @implementation PGFoundationClient - +@synthesize db = _db; +@synthesize term = _term; +@synthesize passwordstore = _passwordstore; //////////////////////////////////////////////////////////////////////////////// // constructor @@ -36,9 +38,7 @@ -(id)init { //////////////////////////////////////////////////////////////////////////////// // properties -@synthesize db = _db; -@synthesize term = _term; -@synthesize passwordstore = _passwordstore; + @dynamic url; @dynamic prompt; @@ -83,8 +83,9 @@ -(void)connection:(PGConnection* )connection willOpenWithParameters:(NSMutableDi } } --(void)connection:(PGConnection* )connection willExecute:(NSString *)query { +-(NSString* )connection:(PGConnection* )connection willExecute:(NSString *)query { [[self term] printf:query]; + return nil; } -(void)connection:(PGConnection* )connection statusChange:(PGConnectionStatus)status description:(NSString *)description { @@ -127,13 +128,18 @@ -(void)connect:(NSURL* )url { } -(void)execute:(id)query { + + +// query = [PGQuery queryWithString:@"SELECT datname FROM pg_database"]; + + [[self db] execute:query whenDone:^(PGResult* result, NSError* error) { if(error) { [[self term] printf:@"Error: %@ (%@/%ld)",[error localizedDescription],[error domain],[error code]]; } if(result) { [self displayResult:result]; - [[self term] addHistory:query]; + [[self term] addHistory: query ]; } }]; } diff --git a/src/Frameworks/PGClientKit/NSURL+PGAdditions.m b/src/Frameworks/PGClientKit/NSURL+PGAdditions.m index fa0e79f..cb3f6e6 100644 --- a/src/Frameworks/PGClientKit/NSURL+PGAdditions.m +++ b/src/Frameworks/PGClientKit/NSURL+PGAdditions.m @@ -21,7 +21,13 @@ @implementation NSURL (PGAdditions) // PRIVATE METHODS +(NSString* )_pg_urlencode:(NSString* )string { - return (NSString* )CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,(__bridge CFStringRef)string,NULL,(__bridge CFStringRef)@"!*'();:@&=+$,/?%#[]",kCFStringEncodingUTF8)); +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0 || MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_10 +// NSCharacterSet *allowedCharset = [NSCharacterSet characterSetWithCharactersInString:@"!*'();:@&=+$,/?%#[]"]; + NSCharacterSet *allowedCharset = [NSCharacterSet URLQueryAllowedCharacterSet ]; + return (NSString* ) [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharset ] ; +#else + return (NSString* )CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,(__bridge CFStringRef)string,NULL,(__bridge CFStringRef)@"!*'();:@&=+$,/?%#[]",kCFStringEncodingUTF8)); +#endif } +(NSString* )_pg_urlencode_params:(NSDictionary* )params { @@ -288,8 +294,17 @@ -(NSDictionary* )postgresqlParameters { // we require a key/value pair for any additional parameter return nil; } - NSString* theKey = [[theKeyValue objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - NSString* theValue = [[theKeyValue objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0 || MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_10 + + NSCharacterSet *allowedCharset = [NSCharacterSet URLPathAllowedCharacterSet]; + + NSString* theKey = [[theKeyValue objectAtIndex:0] stringByAddingPercentEncodingWithAllowedCharacters: allowedCharset]; + NSString* theValue = [[theKeyValue objectAtIndex:1] stringByAddingPercentEncodingWithAllowedCharacters: allowedCharset]; +#else + NSString* theKey = [[theKeyValue objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + NSString* theValue = [[theKeyValue objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; +#endif // insert into theParameters, allow override of sslmode if([theParameters objectForKey:theKey]==nil || [theKey isEqual:@"sslmode"]) { diff --git a/src/Frameworks/PGClientKit/PGClientKit.h b/src/Frameworks/PGClientKit/PGClientKit.h index d4697c4..42004d2 100644 --- a/src/Frameworks/PGClientKit/PGClientKit.h +++ b/src/Frameworks/PGClientKit/PGClientKit.h @@ -65,6 +65,9 @@ typedef enum { #import "PGConnection.h" #import "PGConnectionPool.h" +// queries callback pool +#import "PGConnectionOperation.h" + // queries #import "PGQueryObject.h" #import "PGQuery.h" diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index 9e1e558..c97835e 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -12,6 +12,16 @@ // License for the specific language governing permissions and limitations // under the License. +// ************************************* +// +// Copyright 2017 - ?? Sebastien Cotillard - Genose.org +// 07/2017 Sebastien Cotillard +// https://github.com/genose +// +// ************************************* +// ADDING Pool concurrent operation +// ************************************* + #import #import @@ -23,8 +33,16 @@ * This method is called from the run loop upon new data being available to read * on the socket, or the socket being able to write more data to the socket */ -void _socketCallback(CFSocketRef s, CFSocketCallBackType callBackType,CFDataRef address,const void* data,void* self) { - [(__bridge PGConnection* )self _socketCallback:callBackType]; +void _socketCallback(CFSocketRef s, CFSocketCallBackType callBackType,CFDataRef address,const void* data,void* __self) { +#if defined DEBUG && defined DEBUG2 + NSLog(@"%@ :: %s :::: Socket CALL ... %lu ", NSStringFromClass([((__bridge NSObject *)__self) class]), (__FUNCTION__), callBackType); +#endif + PGConnection* connection = (PGConnection* ) ((__bridge PGConnection* )__self); +// PGConnection* connection_cp = [ connection copy]; + [((PGConnection* )connection) _socketCallback:callBackType]; +#if defined DEBUG && defined DEBUG2 + NSLog(@"%@ :: %s :::: Socket CALL END .... (%lu) ", NSStringFromClass([((__bridge NSObject *)__self) class]), (__FUNCTION__), callBackType); +#endif } /** @@ -68,6 +86,9 @@ -(void)_socketConnect:(PGConnectionState)state { _runloopsource = CFSocketCreateRunLoopSource(NULL,_socket,0); NSParameterAssert(_runloopsource && CFRunLoopSourceIsValid(_runloopsource)); CFRunLoopAddSource(CFRunLoopGetCurrent(),_runloopsource,(CFStringRef)kCFRunLoopCommonModes); +#if defined DEBUG && defined DEBUG2 + NSLog(@"%@ :: %@ :::: Socket created ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); +#endif } -(void)_socketDisconnect { @@ -91,29 +112,47 @@ -(void)_socketCallbackNotification { NSParameterAssert(_connection); // consume input PQconsumeInput(_connection); + +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: loop "); +#endif + // loop for notifications PGnotify* notify = nil; while((notify = PQnotifies(_connection)) != nil) { if([[self delegate] respondsToSelector:@selector(connection:notificationOnChannel:payload:)]) { +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: call delegate (%@) (%@)", [self delegate], NSStringFromSelector(@selector(connection:notificationOnChannel:payload:))); +#endif + NSString* channel = [NSString stringWithUTF8String:notify->relname]; NSString* payload = [NSString stringWithUTF8String:notify->extra]; [[self delegate] connection:self notificationOnChannel:channel payload:payload]; } PQfreemem(notify); } +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: free "); +#endif } -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus { - NSParameterAssert(_callback); - void (^callback)(BOOL usedPassword,NSError* error) = (__bridge void (^)(BOOL,NSError* ))(_callback); +//:: NSParameterAssert(_callback!=nil); +//:: void (^callback)(BOOL usedPassword,NSError* error) = (__bridge void (^)(BOOL,NSError* ))(_callback); + + _callbackOperation = [((PGConnectionOperation*)[self currentPoolOperation]) getCallback]; + void (^callback)(BOOL usedPassword,NSError* error ) = (__bridge void (^)( BOOL,NSError* ))( _callbackOperation ); BOOL needsPassword = PQconnectionNeedsPassword(_connection) ? YES : NO; BOOL usedPassword = PQconnectionUsedPassword(_connection) ? YES : NO; - +#if defined DEBUG && defined DEBUG2 + NSLog(@"%@ (%p) :: BEGIN :: - Read::end - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); +#endif // update the status [self setState:PGConnectionStateNone]; [self _updateStatus]; // this also calls disconnect when rejected - + + // callback if(pqstatus==PGRES_POLLING_OK) { // set up notice processor, set success condition @@ -129,19 +168,29 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus // error callback - connection not made, some other kind of rejection callback(YES,[self raiseError:nil code:PGClientErrorRejected]); } - _callback = nil; + +#if defined DEBUG && defined DEBUG2 + NSLog(@"%@ (%p) :: END :: - Read::end - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); +#endif + // :: TODO :: + //:: _callback = nil; +// + [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; +// [self pushPoolOperation]; } -(void)_socketCallbackResetEndedWithStatus:(PostgresPollingStatusType)pqstatus { - NSParameterAssert(_callback); - void (^callback)(NSError* error) = (__bridge void (^)(NSError* ))(_callback); + NSParameterAssert([[self currentPoolOperation] valid]); +//:: void (^callback)(NSError* error) = (__bridge void (^)(NSError* ))(_callback); + void (^callback)(NSError* error) = (__bridge void (^)(NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); if(pqstatus==PGRES_POLLING_OK) { callback(nil); } else { callback([self raiseError:nil code:PGClientErrorRejected]); } - _callback = nil; + //:: _callback = nil; + [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; [self setState:PGConnectionStateNone]; [self _updateStatus]; // this also calls disconnect when rejected } @@ -153,7 +202,7 @@ -(void)_socketCallbackResetEndedWithStatus:(PostgresPollingStatusType)pqstatus { */ -(void)_socketCallbackConnect { // ignore this call if either connection or callback are nil - if(_connection==nil || _callback==nil) { + if(_connection==nil || ![[self currentPoolOperation] valid]) { // || (_callback==nil) // && _callbackOperation == nil) return; } @@ -208,49 +257,95 @@ -(void)_socketCallbackQueryRead { PQconsumeInput(_connection); /* it seems that we don't really need to check for busy and it seems to - * create some issues, so ignore for now + * create some issues, so ignore for now */ // check for busy, return if more to do if(PQisBusy(_connection)) { return; } - */ - + +// + NSParameterAssert([[self currentPoolOperation] valid]); +//:: void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); + void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); + #if defined DEBUG && defined DEBUG2 + NSLog(@":::: PGConnectionStateQuery(%@::%p) - Read BEGIN - Result - :: callback \n_callback :: (%@)\n ********************************* ",NSStringFromClass([self class]), self , callback ); + #endif + + // consume results PGresult* result = nil; while(1) { result = PQgetResult(_connection); if(result==nil) { +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - Read - Result nil - End"); +#endif break; } NSError* error = nil; PGResult* r = nil; + + // check for connection errors if(PQresultStatus(result)==PGRES_EMPTY_QUERY) { +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - Read - Result - Empty Query"); +#endif // callback empty query error = [self raiseError:nil code:PGClientErrorQuery reason:@"Empty query"]; PQclear(result); } else if(PQresultStatus(result)==PGRES_BAD_RESPONSE || PQresultStatus(result)==PGRES_FATAL_ERROR) { +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - Read - Result - Client Error (%s)", PQresultErrorMessage(result)); +#endif error = [self raiseError:nil code:PGClientErrorExecute reason:[NSString stringWithUTF8String:PQresultErrorMessage(result)]]; PQclear(result); } else { +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - Read - Result - READ Query RESULT" ); +#endif // TODO: allocate a different kind of class r = [[PGResult alloc] initWithResult:result format:[self tupleFormat]]; +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - Read - Result - READ END (%s)", PQresultErrorMessage(result)); +#endif +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - Read - Result - Done :: (%@)", r ); +#endif } if(r || error) { - NSParameterAssert(_callback); - void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); + +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery(%@::%p) - Read - Result - Done :: callback \n ********************************* \nresult :: (%@)\n ********************************* \nerror :: (%@) \n_callback :: (%@)\n ********************************* ",NSStringFromClass([self class]), self, r, error, callback ); +#endif + + + // queue up callback on main thread dispatch_async(dispatch_get_main_queue(),^{ +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - Read - callback %p ",callback); +#endif callback(r,error); - }); + }); + +// break; } } - +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - Read - Result - Clear " ); +#endif // all results consumed - update state [self setState:PGConnectionStateNone]; - _callback = nil; // release the callback +//:: _callback = nil; // release the callback + + [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; + [self _updateStatus]; +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - Read END - Result - Clear::End " ); +#endif } /** @@ -263,8 +358,9 @@ -(void)_socketCallbackQueryWrite { int returnCode = PQflush(_connection); if(returnCode==-1) { // callback with error - NSParameterAssert(_callback); - void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); + NSParameterAssert([[self currentPoolOperation] valid]); +//:: void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); + void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); NSError* error = [self raiseError:nil code:PGClientErrorState reason:@"Data flush failed during query"]; callback(nil,error); } @@ -299,7 +395,8 @@ -(void)_socketCallback:(CFSocketCallBackType)callBackType { break; } #endif - switch([self state]) { + PGConnectionState state_on = [self state]; + switch(state_on) { case PGConnectionStateConnect: #if defined DEBUG && defined DEBUG2 NSLog(@"PGConnectionStateConnect"); @@ -315,9 +412,14 @@ -(void)_socketCallback:(CFSocketCallBackType)callBackType { case PGConnectionStateQuery: if(callBackType==kCFSocketReadCallBack) { #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Read"); + NSLog(@"PGConnectionStateQuery - Read - _socketCallback :: _socketCallbackQueryRead :: callback (%p)",[[self currentPoolOperation] getCallback]); #endif +//:: _callback = _callbackOperation; +// _callback = [self currentPoolOperation]; [self _socketCallbackQueryRead]; +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - Read - _socketCallback :: _socketCallbackNotification :: callback (%p)", [[self currentPoolOperation] getCallback]); +#endif [self _socketCallbackNotification]; } else if(callBackType==kCFSocketWriteCallBack) { #if defined DEBUG && defined DEBUG2 diff --git a/src/Frameworks/PGClientKit/PGConnection+Connect.m b/src/Frameworks/PGClientKit/PGConnection+Connect.m index b6751ab..3e56bab 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Connect.m +++ b/src/Frameworks/PGClientKit/PGConnection+Connect.m @@ -141,8 +141,11 @@ -(void)connectWithURL:(NSURL* )url whenDone:(void(^)(BOOL usedPassword,NSError* } // set callback - NSParameterAssert(_callback==nil); - _callback = (__bridge_retained void* )[callback copy]; + NSParameterAssert(callback!=nil); + // not quite good for cascaded Operation +//:: _callback = (__bridge_retained void* )[callback copy]; + // So we do good things to deal with cascaded Operation + [self addOperation:self withCallBackWhenDone: (__bridge_retained void* )callback withCallBackWhenError: (__bridge_retained void* )callback ]; // add socket to run loop [self _socketConnect:PGConnectionStateConnect]; diff --git a/src/Frameworks/PGClientKit/PGConnection+Errors.m b/src/Frameworks/PGClientKit/PGConnection+Errors.m index a3eadd9..e4966e5 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Errors.m +++ b/src/Frameworks/PGClientKit/PGConnection+Errors.m @@ -69,8 +69,20 @@ -(void)_raiseError:(NSError* )error { NSParameterAssert(error); // perform selector if([[self delegate] respondsToSelector:@selector(connection:error:)]) { - [[self delegate] connection:self error:error]; - } +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - _raiseError :: send to delegate connection:error:" ); +#endif +// [[self delegate] connection:self error:error]; +// @{@"connection":self, @"error":error} + [NSThread detachNewThreadWithBlock:^{ + [[self delegate] connection:self error:error]; + }]; +// [NSThread detachNewThreadSelector:@selector(connection:error:) toTarget:[self delegate] withObject:nil ]; + }else{ +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - _raiseError :: no delegate respondsto connection:error:" ); +#endif + } } -(NSError* )raiseError:(NSError** )error code:(PGClientErrorDomainCode)code reason:(NSString* )format,... { @@ -89,8 +101,19 @@ -(NSError* )raiseError:(NSError** )error code:(PGClientErrorDomainCode)code reas } // raise the error with the delegate if([self delegate]) { - [self performSelectorOnMainThread:@selector(_raiseError:) withObject:theError waitUntilDone:YES]; - } +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - _raiseError :: performSelectorOnMainThread :: (%@)", theError ); +#endif + // [self performSelectorOnMainThread:@selector(_raiseError:) withObject:theError waitUntilDone:YES]; + [self _raiseError:theError]; + }else{ +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - _raiseError:code: :: no delegate avail" ); +#endif + } +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - _raiseError :: return " ); +#endif return theError; } diff --git a/src/Frameworks/PGClientKit/PGConnection+Execute.m b/src/Frameworks/PGClientKit/PGConnection+Execute.m index 9d3e2a2..ff21ae3 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Execute.m +++ b/src/Frameworks/PGClientKit/PGConnection+Execute.m @@ -12,6 +12,16 @@ // License for the specific language governing permissions and limitations // under the License. +// ************************************* +// +// Copyright 2017 - ?? Sebastien Cotillard - Genose.org +// 07/2017 Sebastien Cotillard +// https://github.com/genose +// +// ************************************* +// ADDING Pool concurrent operation +// ************************************* + #import #import @@ -22,6 +32,9 @@ @implementation PGConnection (Execute) //////////////////////////////////////////////////////////////////////////////// -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGResult* result,NSError* error)) callback { + + + NSParameterAssert(query && [query isKindOfClass:[NSString class]]); if(_connection==nil || [self state] != PGConnectionStateNone) { callback(nil,[self raiseError:nil code:PGClientErrorState]); @@ -50,6 +63,8 @@ -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGR NSLog(@"TODO: Turn %@ into arg",[obj class]); _paramSetNull(params,i); } + + // check number of parameters if(params->size > INT_MAX) { _paramFree(params); @@ -63,11 +78,26 @@ -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGR className = [[self delegate] connection:self willExecute:query]; } + NSParameterAssert(callback!=nil); + + _callbackOperation = (__bridge_retained void* )[callback copy]; + + // if([self currentPoolOperation] != nil) [[self currentPoolOperation] invalidate]; + + [self addOperation:query withCallBackWhenDone: (__bridge_retained void* )callback withCallBackWhenError: (__bridge_retained void* )callback ]; + + NSParameterAssert(_callbackOperation!=nil); + + + // execute the command, free parameters int resultFormat = ([self tupleFormat]==PGClientTupleFormatBinary) ? 1 : 0; int returnCode = PQsendQueryParams(_connection,[query UTF8String],(int)params->size,params->types,(const char** )params->values,params->lengths,params->formats,resultFormat); _paramFree(params); if(!returnCode) { +#if defined DEBUG && defined DEBUG2 + NSLog(@"%@ :: %@ :: - execute - error :: callback %p ", NSStringFromSelector(_cmd),NSStringFromClass([self class]), callback); +#endif callback(nil,[self raiseError:nil code:PGClientErrorExecute reason:[NSString stringWithUTF8String:PQerrorMessage(_connection)]]); return; } @@ -76,8 +106,12 @@ -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGR [self setState:PGConnectionStateQuery]; [self _updateStatus]; - NSParameterAssert(_callback!=nil); - _callback = (__bridge_retained void* )[callback copy]; + + +#if defined DEBUG && defined DEBUG2 + NSLog(@"%@ :: %@ :: - execute - return :: callback %p :: %p ", NSStringFromSelector(_cmd),NSStringFromClass([self class]), callback, _callbackOperation); +#endif + [NSThread sleepForTimeInterval: .2]; } //////////////////////////////////////////////////////////////////////////////// @@ -95,11 +129,17 @@ -(void)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) cal query2 = [(PGQuery* )query quoteForConnection:self error:&error]; } if(error) { +#if defined DEBUG && defined DEBUG2 + NSLog(@"%@ :: %@ - query ERROR - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); +#endif callback(nil,error); } else if(query2==nil) { callback(nil,[self raiseError:nil code:PGClientErrorExecute reason:@"Query is nil"]); } else { - [self _execute:query2 values:nil whenDone:callback]; +#if defined DEBUG && defined DEBUG2 + NSLog(@"%@ :: %@ - query - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); +#endif + [self _execute:query2 values:nil whenDone: callback]; } } diff --git a/src/Frameworks/PGClientKit/PGConnection.h b/src/Frameworks/PGClientKit/PGConnection.h index 74a1136..e4724c7 100644 --- a/src/Frameworks/PGClientKit/PGConnection.h +++ b/src/Frameworks/PGClientKit/PGConnection.h @@ -21,6 +21,8 @@ * and errors. */ + + //////////////////////////////////////////////////////////////////////////////// // constants @@ -75,13 +77,17 @@ typedef enum { PGClientTupleFormatBinary = 1 } PGClientTupleFormat; +@class PGConnectionOperation; + //////////////////////////////////////////////////////////////////////////////// // PGConnection interface -@interface PGConnection : NSObject { +@interface PGConnection : NSObject { void* _connection; void* _cancel; - void* _callback; +// replaced by a pool Mechanism :: void* _callback; + void* _callbackOperation; + CFMutableArrayRef _callbackOperationPool; CFSocketRef _socket; CFRunLoopSourceRef _runloopsource; NSUInteger _timeout; @@ -176,6 +182,14 @@ typedef enum { -(NSString* )quoteString:(NSString* )string; -(NSString* )encryptedPassword:(NSString* )password role:(NSString* )roleName; + +-(id)addOperation:(id)operationClass withCallBackWhenDone:(void*)callBackWhenDone withCallBackWhenError:(void*)callBackWhenError; + +-(PGConnectionOperation*)currentPoolOperation; + +-(id)invalidateOperation:(NSInteger)operationRefIndex; + + @end //////////////////////////////////////////////////////////////////////////////// diff --git a/src/Frameworks/PGClientKit/PGConnection.m b/src/Frameworks/PGClientKit/PGConnection.m index 47aebd3..131d1eb 100644 --- a/src/Frameworks/PGClientKit/PGConnection.m +++ b/src/Frameworks/PGClientKit/PGConnection.m @@ -12,6 +12,16 @@ // License for the specific language governing permissions and limitations // under the License. +// ************************************* +// +// Copyright 2017 - ?? Sebastien Cotillard - Genose.org +// 07/2017 Sebastien Cotillard +// https://github.com/genose +// +// ************************************* +// ADDING Pool concurrent operation +// ************************************* + #import #import #include @@ -48,11 +58,11 @@ @implementation PGConnection //////////////////////////////////////////////////////////////////////////////// +(NSArray* )allURLSchemes { - return [PGConnectionSchemes componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + return [PGConnectionSchemes componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; } +(NSString* )defaultURLScheme { - return [[self allURLSchemes] objectAtIndex:0]; + return [[self allURLSchemes] objectAtIndex:0]; } //////////////////////////////////////////////////////////////////////////////// @@ -62,22 +72,30 @@ +(NSString* )defaultURLScheme { -(instancetype)init { self = [super init]; if(self) { - _connection = nil; - _cancel = nil; - _callback = nil; - _socket = nil; - _runloopsource = nil; - _timeout = 0; - _state = PGConnectionStateNone; - _parameters = nil; - _tupleFormat = PGClientTupleFormatText; - pgdata2obj_init(); // set up cache for translating binary data from server + _connection = nil; + _cancel = nil; + // _callback = nil; + _callbackOperation = nil; + _callbackOperationPool = CFArrayCreateMutable(NULL, 64, &kCFTypeArrayCallBacks); + // (NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + // CFArrayInsertValueAtIndex(_callbackOperationPool, 0, CFBridgingRetain([[PGConnectionOperation alloc]init])); + + // (_callbackOperationPool, CFSTR("A String Key"), CFBridgingRetain([PGConnectionOperation new])); + // :: dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + _socket = nil; + _runloopsource = nil; + _timeout = 0; + _state = PGConnectionStateNone; + _parameters = nil; + _tupleFormat = PGClientTupleFormatText; + pgdata2obj_init(); // set up cache for translating binary data from server } return self; } -(void)finalize { - [self disconnect]; + [self disconnect]; } //////////////////////////////////////////////////////////////////////////////// @@ -95,127 +113,127 @@ -(void)finalize { @synthesize tupleFormat = _tupleFormat; -(PGConnectionStatus)status { - if(_connection==nil) { - return PGConnectionStatusDisconnected; - } - switch(PQstatus(_connection)) { - case CONNECTION_OK: - return [self state]==PGConnectionStateNone ? PGConnectionStatusConnected : PGConnectionStatusBusy; - case CONNECTION_STARTED: - case CONNECTION_MADE: - case CONNECTION_AWAITING_RESPONSE: - case CONNECTION_AUTH_OK: - case CONNECTION_SSL_STARTUP: - case CONNECTION_SETENV: - return PGConnectionStatusConnecting; - default: - return PGConnectionStatusRejected; - } + if(_connection==nil) { + return PGConnectionStatusDisconnected; + } + switch(PQstatus(_connection)) { + case CONNECTION_OK: + return [self state]==PGConnectionStateNone ? PGConnectionStatusConnected : PGConnectionStatusBusy; + case CONNECTION_STARTED: + case CONNECTION_MADE: + case CONNECTION_AWAITING_RESPONSE: + case CONNECTION_AUTH_OK: + case CONNECTION_SSL_STARTUP: + case CONNECTION_SETENV: + return PGConnectionStatusConnecting; + default: + return PGConnectionStatusRejected; + } } -(NSString* )user { - if(_connection==nil || PQstatus(_connection) != CONNECTION_OK) { - return nil; - } - return [NSString stringWithUTF8String:PQuser(_connection)]; + if(_connection==nil || PQstatus(_connection) != CONNECTION_OK) { + return nil; + } + return [NSString stringWithUTF8String:PQuser(_connection)]; } -(NSString* )database { - if(_connection==nil || PQstatus(_connection) != CONNECTION_OK) { - return nil; - } - return [NSString stringWithUTF8String:PQdb(_connection)]; + if(_connection==nil || PQstatus(_connection) != CONNECTION_OK) { + return nil; + } + return [NSString stringWithUTF8String:PQdb(_connection)]; } -(NSString* )host { - if(_connection==nil || PQstatus(_connection) != CONNECTION_OK) { - return nil; - } - const char* host = PQhost(_connection); - if(host) { - return [NSString stringWithUTF8String:host]; - } else { - return nil; - } + if(_connection==nil || PQstatus(_connection) != CONNECTION_OK) { + return nil; + } + const char* host = PQhost(_connection); + if(host) { + return [NSString stringWithUTF8String:host]; + } else { + return nil; + } } -(int)serverProcessID { - if(_connection==nil || PQstatus(_connection) != CONNECTION_OK) { - return 0; - } - return PQbackendPID(_connection); + if(_connection==nil || PQstatus(_connection) != CONNECTION_OK) { + return 0; + } + return PQbackendPID(_connection); } -(NSDictionary* )parameters { - if(_parameters != nil) { - return _parameters; - } - NSMutableDictionary* parameters = [NSMutableDictionary dictionary]; - NSParameterAssert(parameters); - _parameters = parameters; - - // populate parameters from bundle - NSBundle* bundle = [NSBundle bundleForClass:[self class]]; - for(NSString* key in @[ @"CFBundleIdentifier", @"CFBundleName", @"CFBundleShortVersionString" ]) { - id value = [[bundle infoDictionary] objectForKey:key]; - if(value) { - [parameters setObject:value forKey:key]; - } - } - - // populate parameters from connection - if(_connection) { - - // server version - int serverVersion = PQserverVersion(_connection); - if(serverVersion) { - [parameters setObject:[NSNumber numberWithInt:serverVersion] forKey:PGConnectionServerVersionKey]; - [parameters setObject:[NSNumber numberWithInt:(serverVersion / 10000) % 10] forKey:PGConnectionServerMajorVersionKey]; - [parameters setObject:[NSNumber numberWithInt:(serverVersion / 100) % 10] forKey:PGConnectionServerMinorVersionKey]; - [parameters setObject:[NSNumber numberWithInt:(serverVersion / 1) % 10] forKey:PGConnectionServerRevisionVersionKey]; - } - - // protocol version and pid - NSNumber* protocol = [NSNumber numberWithInt:PQprotocolVersion(_connection)]; - NSNumber* pid = [NSNumber numberWithInt:[self serverProcessID]]; - if(protocol) { - [parameters setObject:protocol forKey:PGConnectionProtocolVersionKey]; - } - if(pid) { - [parameters setObject:pid forKey:PGConnectionServerProcessKey]; - } - - // user, database & host - NSString* user = [self user]; - NSString* database = [self database]; - NSString* host = [self host]; - if(user) { - [parameters setObject:user forKey:PGConnectionUserKey]; - } - if(database) { - [parameters setObject:database forKey:PGConnectionDatabaseKey]; - } - if(host) { - [parameters setObject:database forKey:PGConnectionHostKey]; - } - - // ssl - SSL* ssl = PQgetssl(_connection); - if(ssl) { - [parameters setObject:[NSNumber numberWithInt:ssl->version] forKey:PGConnectionSSLVersionKey]; - } - - // other server parameters - for(NSString* key in @[ @"server_version", @"server_encoding", @"client_encoding", @"application_name", @"is_superuser", @"session_authorization", @"DateStyle", @"IntervalStyle", @"TimeZone", @"integer_datetimes", @"standard_conforming_strings"]) { - const char* value = PQparameterStatus(_connection,[key UTF8String]); - if(value) { - [parameters setObject:[NSString stringWithUTF8String:value] forKey:key]; - } - } - } - - // return parameters - return parameters; + if(_parameters != nil) { + return _parameters; + } + NSMutableDictionary* parameters = [NSMutableDictionary dictionary]; + NSParameterAssert(parameters); + _parameters = parameters; + + // populate parameters from bundle + NSBundle* bundle = [NSBundle bundleForClass:[self class]]; + for(NSString* key in @[ @"CFBundleIdentifier", @"CFBundleName", @"CFBundleShortVersionString" ]) { + id value = [[bundle infoDictionary] objectForKey:key]; + if(value) { + [parameters setObject:value forKey:key]; + } + } + + // populate parameters from connection + if(_connection) { + + // server version + int serverVersion = PQserverVersion(_connection); + if(serverVersion) { + [parameters setObject:[NSNumber numberWithInt:serverVersion] forKey:PGConnectionServerVersionKey]; + [parameters setObject:[NSNumber numberWithInt:(serverVersion / 10000) % 10] forKey:PGConnectionServerMajorVersionKey]; + [parameters setObject:[NSNumber numberWithInt:(serverVersion / 100) % 10] forKey:PGConnectionServerMinorVersionKey]; + [parameters setObject:[NSNumber numberWithInt:(serverVersion / 1) % 10] forKey:PGConnectionServerRevisionVersionKey]; + } + + // protocol version and pid + NSNumber* protocol = [NSNumber numberWithInt:PQprotocolVersion(_connection)]; + NSNumber* pid = [NSNumber numberWithInt:[self serverProcessID]]; + if(protocol) { + [parameters setObject:protocol forKey:PGConnectionProtocolVersionKey]; + } + if(pid) { + [parameters setObject:pid forKey:PGConnectionServerProcessKey]; + } + + // user, database & host + NSString* user = [self user]; + NSString* database = [self database]; + NSString* host = [self host]; + if(user) { + [parameters setObject:user forKey:PGConnectionUserKey]; + } + if(database) { + [parameters setObject:database forKey:PGConnectionDatabaseKey]; + } + if(host) { + [parameters setObject:database forKey:PGConnectionHostKey]; + } + + // ssl + SSL* ssl = PQgetssl(_connection); + if(ssl) { + [parameters setObject:[NSNumber numberWithInt:ssl->version] forKey:PGConnectionSSLVersionKey]; + } + + // other server parameters + for(NSString* key in @[ @"server_version", @"server_encoding", @"client_encoding", @"application_name", @"is_superuser", @"session_authorization", @"DateStyle", @"IntervalStyle", @"TimeZone", @"integer_datetimes", @"standard_conforming_strings"]) { + const char* value = PQparameterStatus(_connection,[key UTF8String]); + if(value) { + [parameters setObject:[NSString stringWithUTF8String:value] forKey:key]; + } + } + } + + // return parameters + return parameters; } //////////////////////////////////////////////////////////////////////////////// @@ -223,46 +241,108 @@ -(NSDictionary* )parameters { //////////////////////////////////////////////////////////////////////////////// -(void)_updateStatusDelayed:(NSArray* )arguments { - NSParameterAssert(arguments && [arguments count]==2); - PGConnectionStatus status = [[arguments objectAtIndex:0] intValue]; - NSString* description = [arguments objectAtIndex:1]; - if([[self delegate] respondsToSelector:@selector(connection:statusChange:description:)]) { - [[self delegate] connection:self statusChange:status description:description]; - } + NSParameterAssert(arguments && [arguments count]==2); + PGConnectionStatus status = [[arguments objectAtIndex:0] intValue]; + NSString* description = [arguments objectAtIndex:1]; + if([[self delegate] respondsToSelector:@selector(connection:statusChange:description:)]) { + [[self delegate] connection:self statusChange:status description:description]; + } + // [[NSThread currentThread] cancel]; + // [NSThread cancelPreviousPerformRequestsWithTarget:self]; } -(void)_updateStatus { - static PGConnectionStatus oldStatus = PGConnectionStatusDisconnected; - static dispatch_once_t onceToken; +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnection (%p) - _updateStatus ",self); +#endif + static PGConnectionStatus oldStatus = PGConnectionStatusDisconnected; + static dispatch_once_t onceToken; dispatch_once(&onceToken,^{ // Do some work that happens once - PGConnectionStatusDescription = @{ - [NSNumber numberWithInt:PGConnectionStatusBusy]: @"Busy", - [NSNumber numberWithInt:PGConnectionStatusConnected]: @"Idle", - [NSNumber numberWithInt:PGConnectionStatusConnecting]: @"Connecting", - [NSNumber numberWithInt:PGConnectionStatusDisconnected]: @"Disconnected", - [NSNumber numberWithInt:PGConnectionStatusRejected]: @"Rejected" - }; + PGConnectionStatusDescription = @{ + [NSNumber numberWithInt:PGConnectionStatusBusy]: @"Busy", + [NSNumber numberWithInt:PGConnectionStatusConnected]: @"Idle", + [NSNumber numberWithInt:PGConnectionStatusConnecting]: @"Connecting", + [NSNumber numberWithInt:PGConnectionStatusDisconnected]: @"Disconnected", + [NSNumber numberWithInt:PGConnectionStatusRejected]: @"Rejected" + }; }); - if([self status] == oldStatus) { - return; - } - // reset oldStatus - oldStatus = [self status]; - - // we call the delegate in a delayed fashion, so as to not stop the callbacks - // from continuing - NSNumber* key = [NSNumber numberWithInt:oldStatus]; - NSString* description = [PGConnectionStatusDescription objectForKey:key]; - [self performSelectorOnMainThread:@selector(_updateStatusDelayed:) withObject:@[ key,description ] waitUntilDone:NO]; + if([self status] == oldStatus) { + return; + } + // reset oldStatus + oldStatus = [self status]; + + // we call the delegate in a delayed fashion, so as to not stop the callbacks + // from continuing + NSNumber* key = [NSNumber numberWithInt:oldStatus]; + NSString* description = [PGConnectionStatusDescription objectForKey:key]; + [self performSelectorOnMainThread:@selector(_updateStatusDelayed:) withObject:@[ key,description ] waitUntilDone:NO]; +#ifdef DEBUG2 + NSLog(@"status => %@ %@",key,description); +#endif + + // if connection is rejected, then call disconnect + if(oldStatus==PGConnectionStatusRejected) { #ifdef DEBUG2 - NSLog(@"status => %@ %@",key,description); + NSLog(@"_updateStatus => disconnect/rejected :: %@ %@",key,description); #endif + [self disconnect]; + } +} - // if connection is rejected, then call disconnect - if(oldStatus==PGConnectionStatusRejected) { - [self disconnect]; - } +-(PGConnectionOperation*)currentPoolOperation +{ + PGConnectionOperation* masterPoolOperation = nil; + + CFIndex indexInPool = CFArrayGetCount(_callbackOperationPool); + if(indexInPool > 0 ) + { + masterPoolOperation = (__bridge PGConnectionOperation*) CFArrayGetValueAtIndex(_callbackOperationPool, indexInPool-1); + }else{ + NSLog(@" ERROR :: NO pool .... "); + } +#if defined DEBUG && defined DEBUG2 + NSLog(@" %@::%@ :: SELECT pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, masterPoolOperation); +#endif + id currentPoolOpe = nil; + + return masterPoolOperation; +} +-(id)addOperation: (id)operationClass withCallBackWhenDone:(void*)callBackWhenDone withCallBackWhenError:(void*)callBackWhenError +{ + // void * callbackDone = ^(id result, NSError *error) { + // callBackWhenDone(result, error); + // [[ self getConnectionDelegate] invalidateOperation: [((PGConnectionOperation*)self) poolIdentifier] ]; + // } + + CFIndex indexInPool = CFArrayGetCount(_callbackOperationPool); + + PGConnectionOperation *newPool = [[PGConnectionOperation alloc] initWithParametersDelegate: self withRefPoolIdentifier: indexInPool refClassOperation:operationClass callWhenDone: callBackWhenDone callWhenError: (__bridge void (^)(__strong id, NSError *__strong))(callBackWhenError)]; + + CFArrayAppendValue(_callbackOperationPool, CFBridgingRetain(newPool)); + + indexInPool = CFArrayGetCount(_callbackOperationPool); + id obj = CFArrayGetValueAtIndex(_callbackOperationPool, indexInPool-1); +#if defined DEBUG && defined DEBUG2 + NSLog(@" %@::%@ :: ADDED pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, [obj description]); +#endif + + return nil; +} +-(id)invalidateOperation:(NSInteger)operationRefIndex +{ + CFIndex indexInPool = CFArrayGetCount(_callbackOperationPool); + if(indexInPool > 0 && indexInPool>=operationRefIndex && operationRefIndex !=0) + { + id obj = CFArrayGetValueAtIndex(_callbackOperationPool, operationRefIndex); +#if defined DEBUG && defined DEBUG2 + NSLog(@" %@::%@ :: REMOVED pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, [obj description]); +#endif + CFArrayRemoveValueAtIndex(_callbackOperationPool, operationRefIndex); + + } + return nil; } //////////////////////////////////////////////////////////////////////////////// @@ -270,53 +350,70 @@ -(void)_updateStatus { //////////////////////////////////////////////////////////////////////////////// -(NSString* )quoteIdentifier:(NSString* )string { - if(_connection==nil) { - return nil; - } - - // if identifier only contains alphanumberic characters, return it unmodified - if([string isAlphanumericOrUnderscore]) { - return string; - } - - const char* quoted_identifier = PQescapeIdentifier(_connection,[string UTF8String],[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); - if(quoted_identifier==nil) { - return nil; - } - NSString* quoted_identifier2 = [NSString stringWithUTF8String:quoted_identifier]; - NSParameterAssert(quoted_identifier2); - PQfreemem((void* )quoted_identifier); - return quoted_identifier2; + if(_connection==nil) { + return nil; + } + + // if identifier only contains alphanumberic characters, return it unmodified + if([string isAlphanumericOrUnderscore]) { + return string; + } + + const char* quoted_identifier = PQescapeIdentifier(_connection,[string UTF8String],[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); + if(quoted_identifier==nil) { + return nil; + } + NSString* quoted_identifier2 = [NSString stringWithUTF8String:quoted_identifier]; + NSParameterAssert(quoted_identifier2); + PQfreemem((void* )quoted_identifier); + return quoted_identifier2; } -(NSString* )quoteString:(NSString* )string { - if(_connection==nil) { - return nil; - } - const char* quoted_string = PQescapeLiteral(_connection,[string UTF8String],[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); - if(quoted_string==nil) { - return nil; - } - NSString* quoted_string2 = [NSString stringWithUTF8String:quoted_string]; - NSParameterAssert(quoted_string2); - PQfreemem((void* )quoted_string); - return quoted_string2; + if(_connection==nil) { + return nil; + } + const char* quoted_string = PQescapeLiteral(_connection,[string UTF8String],[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); + if(quoted_string==nil) { + return nil; + } + NSString* quoted_string2 = [NSString stringWithUTF8String:quoted_string]; + NSParameterAssert(quoted_string2); + PQfreemem((void* )quoted_string); + return quoted_string2; } -(NSString* )encryptedPassword:(NSString* )password role:(NSString* )roleName { - NSParameterAssert(password); - NSParameterAssert(roleName); - if(_connection==nil) { - return nil; - } - char* encryptedPassword = PQencryptPassword([password UTF8String],[roleName UTF8String]); - if(encryptedPassword==nil) { - return nil; - } - NSString* encryptedPassword2 = [NSString stringWithUTF8String:encryptedPassword]; - NSParameterAssert(encryptedPassword2); - PQfreemem(encryptedPassword); - return encryptedPassword2; + NSParameterAssert(password); + NSParameterAssert(roleName); + if(_connection==nil) { + return nil; + } + char* encryptedPassword = PQencryptPassword([password UTF8String],[roleName UTF8String]); + if(encryptedPassword==nil) { + return nil; + } + NSString* encryptedPassword2 = [NSString stringWithUTF8String:encryptedPassword]; + NSParameterAssert(encryptedPassword2); + PQfreemem(encryptedPassword); + return encryptedPassword2; +} +-(id)copyWithZone:(NSZone *)zone +{ + + PGConnection* newClass = [[[self class] allocWithZone:zone] init]; + (newClass)->_connection = (self)->_connection; + (newClass)->_cancel = (self)->_cancel; + // (newClass)->_callback = (self)->_callback; + (newClass)->_socket = (self)->_socket; + (newClass)->_runloopsource = (self)->_runloopsource ; + (newClass)->_timeout = (self)->_timeout; + (newClass)->_state = (self)->_state; + + + (newClass)->_parameters = (self)->_parameters; + (newClass)->_tupleFormat = (self)->_tupleFormat; + return newClass; + } - @end diff --git a/src/Frameworks/PGClientKit/PGConnectionOperation.h b/src/Frameworks/PGClientKit/PGConnectionOperation.h new file mode 100644 index 0000000..46ce326 --- /dev/null +++ b/src/Frameworks/PGClientKit/PGConnectionOperation.h @@ -0,0 +1,51 @@ +// ************************************* +// +// Copyright 2017 - ?? Sebastien Cotillard - Genose.org +// https://github.com/genose +// +// ************************************* +// +// Copyright 2009-2015 David Thorpe +// https://github.com/djthorpe/postgresql-kit +// +// Originaly Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +#import + + +@class PGConnection; +@interface PGConnectionOperation : NSObject +{ + + void * _operationConnectionRef; + id _operationConnectionClassRef; + + void * _callbackWhenDone; + void* _callbackWhenError; + id _operation; + id _operationInfo; + id _operationType; + NSInteger poolRefIdentifier; + NSInteger operationStatus; + bool invalidated; +} +//(void(^)(id result,NSError* error)) +-(instancetype)initWithParametersDelegate:(id)connectionDelegate withRefPoolIdentifier:(NSInteger)poolIdentifier refClassOperation:(id)operation callWhenDone:(void*) callBackBlockDone callWhenError:(void(^)(id result,NSError* error)) callBackBlockError; + +-(PGConnection*)getConnectionDelegate; +-(id)queryString; +-(id)UTF8String; + +-(bool)valid; +-(void)invalidate; +-(void *)getCallback; + +@end diff --git a/src/Frameworks/PGClientKit/PGConnectionOperation.m b/src/Frameworks/PGClientKit/PGConnectionOperation.m new file mode 100644 index 0000000..542ead0 --- /dev/null +++ b/src/Frameworks/PGClientKit/PGConnectionOperation.m @@ -0,0 +1,134 @@ +// ************************************* +// +// Copyright 2017 - ?? Sebastien Cotillard - Genose.org +// 07/2017 Sebastien Cotillard +// https://github.com/genose +// +// ************************************* +// +// Copyright 2009-2015 David Thorpe +// https://github.com/djthorpe/postgresql-kit +// +// Originaly Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + + +#import "PGConnectionOperation.h" +#import + +@implementation PGConnectionOperation + +-(instancetype)init +{ + self = [super init]; + if( self == nil) return nil; + + + _operation = [NSObject new]; + _operationInfo = nil; + _callbackWhenDone = NULL; + _callbackWhenError = NULL; + invalidated = YES; + return self; + +} +-(instancetype)initWithParametersDelegate:(id)connectionDelegate withRefPoolIdentifier:(NSInteger)poolIdentifier refClassOperation:(id)operation callWhenDone:(void*) callBackBlockDone callWhenError:(void*) callBackBlockError +{ + // void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); + self = [[[self class] alloc ] init]; + if(self != nil) + { + _operationConnectionClassRef = connectionDelegate; +// _operationConnectionRef = ((PGConnection*)_operationConnectionClassRef)->_connection; + + + _operationType = [((NSObject*)operation) class]; + _operation = operation; + + + poolRefIdentifier = poolIdentifier; + + _callbackWhenDone = (__bridge_retained void* )([(__bridge void (^)(void* ,void* ))(callBackBlockDone) copy]);//(__bridge void (^)(PGResult* ,NSError* ))(callBackBlockDone); + _callbackWhenError = (__bridge_retained void* )([(__bridge void (^)(void* ,void* ))(callBackBlockError) copy]);//(__bridge void (^)(PGResult* ,NSError* ))(callBackBlockDone); + invalidated = NO; + }else{ + return nil; + } + return self; +} +-(bool)valid +{ + return !invalidated; +} +-(void)invalidate +{ + NSLog(@" %@::%@ :: INVALIDATE pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), poolRefIdentifier, [self description]); + if(poolRefIdentifier !=0) + [_operationConnectionClassRef invalidateOperation: poolRefIdentifier]; + invalidated = TRUE; +} +-(PGConnection*)getConnectionDelegate +{ + return _operationConnectionClassRef; + +} + +-(void *)getCallback +{ +// if(invalidated){ +// _callbackWhenDone = nil; +// }; + return _callbackWhenDone; +} +-(id)UTF8String +{ + if([_operation respondsToSelector:@selector(UTF8String)]) + { + return [_operation UTF8String]; + } + + return nil; +} +-(id)queryString +{ + if([_operation respondsToSelector:@selector(queryString)]) + { + return [_operation queryString]; + } + + return nil; +} +-(id)string +{ + id queryStringDescription = [self queryString]; + if(queryStringDescription != nil) + { + return queryStringDescription; + } + + if([_operation isKindOfClass:[NSString class]] && [_operation respondsToSelector:@selector(UTF8String)]) + { + return [NSString stringWithFormat:@"<%@> : %@ ",NSStringFromClass([_operation class]), _operation ]; + } + + if([_operation respondsToSelector:@selector(string)]) + { + return [_operation string]; + } + + + + return @""; +} +-(NSString *)description +{ + return [NSString stringWithFormat:@"<%@:%p> \n OperationType : %@ \n Connection Delegate : <%@:%p> \n Operation (%@)",NSStringFromClass([self class]), self, _operationType, NSStringFromClass([_operationConnectionClassRef class ]), _operationConnectionClassRef, [self string] ]; +} +@end diff --git a/src/Frameworks/PGClientKit/PGPasswordStore.m b/src/Frameworks/PGClientKit/PGPasswordStore.m index 5ceade7..ee3e548 100644 --- a/src/Frameworks/PGClientKit/PGPasswordStore.m +++ b/src/Frameworks/PGClientKit/PGPasswordStore.m @@ -60,7 +60,13 @@ -(NSString* )_accountForURL:(NSURL* )url { value = [NSString stringWithFormat:@"%lu",(unsigned long)PGClientDefaultPort]; } if(value) { - [parts addObject:[NSString stringWithFormat:@"%@=%@",key,[[value description] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; +#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0 || MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_10 + NSCharacterSet *allowedCharset = [NSCharacterSet URLPathAllowedCharacterSet]; + + [parts addObject:[NSString stringWithFormat:@"%@=%@",key,[[value description] stringByAddingPercentEncodingWithAllowedCharacters: allowedCharset ]]]; +#else + [parts addObject:[NSString stringWithFormat:@"%@=%@",key,[[value description] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; +#endif } } return [parts componentsJoinedByString:@";"]; diff --git a/src/Frameworks/PGClientKit/PGQueryObject.h b/src/Frameworks/PGClientKit/PGQueryObject.h index 17d1953..ec1184c 100644 --- a/src/Frameworks/PGClientKit/PGQueryObject.h +++ b/src/Frameworks/PGClientKit/PGQueryObject.h @@ -45,6 +45,7 @@ * Return option flags */ @property NSUInteger options; +@property void* _callback; //////////////////////////////////////////////////////////////////////////////// // methods @@ -102,4 +103,7 @@ */ -(NSString* )quoteForConnection:(PGConnection* )connection error:(NSError** )error; +-(const char* )UTF8String; +-(NSString* )queryString; + @end diff --git a/src/Frameworks/PGClientKit/PGQueryObject.m b/src/Frameworks/PGClientKit/PGQueryObject.m index b237c40..c9db784 100644 --- a/src/Frameworks/PGClientKit/PGQueryObject.m +++ b/src/Frameworks/PGClientKit/PGQueryObject.m @@ -72,7 +72,7 @@ +(instancetype)queryWithDictionary:(NSDictionary* )dictionary class:(NSString* ) //////////////////////////////////////////////////////////////////////////////// #pragma mark properties //////////////////////////////////////////////////////////////////////////////// - +@synthesize _callback = _callback; @synthesize dictionary = _dictionary; @dynamic options; @@ -132,6 +132,22 @@ -(void)clearOptionFlags:(NSUInteger)flag { [self setOptions:([self options] & ~flag)]; } + +-(const char* )UTF8String +{ + return [[self queryString] UTF8String]; +} +-(NSString* )string +{ + return [self queryString]; +} +-(NSString* )queryString +{ + NSString* queryTales = [self objectForKey:PGQueryStatementKey]; + NSLog(@"%@(%p) :: %@ :: %@", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), queryTales ); + return queryTales; +} + @end diff --git a/src/Frameworks/PGClientKit/PGQueryUpdate.m b/src/Frameworks/PGClientKit/PGQueryUpdate.m index bf3c27c..426d8c4 100644 --- a/src/Frameworks/PGClientKit/PGQueryUpdate.m +++ b/src/Frameworks/PGClientKit/PGQueryUpdate.m @@ -16,5 +16,8 @@ #import @implementation PGQueryUpdate ++(PGQueryUpdate* )into:(id)source values:(NSDictionary* )values where:(id)where +{ +} @end From 13a1e50d516a5d8a52a792eb98dd6d99eb97eeb3 Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Thu, 27 Jul 2017 19:45:57 +0200 Subject: [PATCH 04/21] Some progress on concurrent Operation and callback --- postgresql-kit.xcodeproj/project.pbxproj | 4 +- .../PGClientKit/PGConnection+Callbacks.m | 39 +- .../PGClientKit/PGConnection+Connect.m | 4 +- .../PGClientKit/PGConnection+Execute.m | 363 ++++++++++-------- src/Frameworks/PGClientKit/PGConnection.h | 9 +- src/Frameworks/PGClientKit/PGConnection.m | 138 ++++++- .../PGClientKit/PGConnectionOperation.h | 9 +- .../PGClientKit/PGConnectionOperation.m | 29 +- 8 files changed, 401 insertions(+), 194 deletions(-) diff --git a/postgresql-kit.xcodeproj/project.pbxproj b/postgresql-kit.xcodeproj/project.pbxproj index 62ebd16..f250052 100644 --- a/postgresql-kit.xcodeproj/project.pbxproj +++ b/postgresql-kit.xcodeproj/project.pbxproj @@ -818,7 +818,7 @@ 6EBDEA4F1AF3826A009CC810 /* PGSettingsRule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PGSettingsRule.m; sourceTree = ""; }; 6EBDEA521AF38A92009CC810 /* PGSettingsArray_testcases.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PGSettingsArray_testcases.m; sourceTree = ""; }; 6EBDEA681AF38B09009CC810 /* PGServerKit_unittests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PGServerKit_unittests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 6EBDEA691AF38B09009CC810 /* PGClientKit_unittests copy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "PGClientKit_unittests copy-Info.plist"; path = "/Volumes/Users/djt/Projects/postgresql-kit/PGClientKit_unittests copy-Info.plist"; sourceTree = ""; }; + 6EBDEA691AF38B09009CC810 /* PGClientKit_unittests copy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "PGClientKit_unittests copy-Info.plist"; sourceTree = ""; }; 6EC5E6771AD7B55900774D57 /* PGQueryInsert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PGQueryInsert.h; sourceTree = ""; }; 6EC5E6781AD7B55900774D57 /* PGQueryInsert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PGQueryInsert.m; sourceTree = ""; }; 6EC5E67E1AD7BDDE00774D57 /* PGQueryUpdate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PGQueryUpdate.h; sourceTree = ""; }; @@ -2870,7 +2870,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; - GCC_OPTIMIZATION_LEVEL = 0; + GCC_OPTIMIZATION_LEVEL = s; OTHER_CFLAGS = "-I/usr/local/include"; SDKROOT = macosx; }; diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index c97835e..e03ad80 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -85,7 +85,9 @@ -(void)_socketConnect:(PGConnectionState)state { // add to run loop to begin polling _runloopsource = CFSocketCreateRunLoopSource(NULL,_socket,0); NSParameterAssert(_runloopsource && CFRunLoopSourceIsValid(_runloopsource)); - CFRunLoopAddSource(CFRunLoopGetCurrent(),_runloopsource,(CFStringRef)kCFRunLoopCommonModes); + CFRunLoopAddSource( + CFRunLoopGetMain(), // CFRunLoopGetCurrent() + _runloopsource,(CFStringRef)kCFRunLoopCommonModes); #if defined DEBUG && defined DEBUG2 NSLog(@"%@ :: %@ :::: Socket created ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); #endif @@ -139,6 +141,8 @@ -(void)_socketCallbackNotification { -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus { //:: NSParameterAssert(_callback!=nil); //:: void (^callback)(BOOL usedPassword,NSError* error) = (__bridge void (^)(BOOL,NSError* ))(_callback); + if( ![((PGConnectionOperation*)[self currentPoolOperation]) valid] ) + return; _callbackOperation = [((PGConnectionOperation*)[self currentPoolOperation]) getCallback]; void (^callback)(BOOL usedPassword,NSError* error ) = (__bridge void (^)( BOOL,NSError* ))( _callbackOperation ); @@ -146,7 +150,7 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus BOOL needsPassword = PQconnectionNeedsPassword(_connection) ? YES : NO; BOOL usedPassword = PQconnectionUsedPassword(_connection) ? YES : NO; #if defined DEBUG && defined DEBUG2 - NSLog(@"%@ (%p) :: BEGIN :: - Read::end - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); + NSLog(@"%@ (%p) :: BEGIN :: - Read::BEGIN - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); #endif // update the status [self setState:PGConnectionStateNone]; @@ -157,7 +161,10 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus if(pqstatus==PGRES_POLLING_OK) { // set up notice processor, set success condition PQsetNoticeProcessor(_connection,_noticeProcessor,(__bridge void *)(self)); + [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; callback(usedPassword ? YES : NO,nil); + [((PGConnectionOperation*)[self masterPoolOperation]) validate]; + } else if(needsPassword) { // error callback - connection not made, needs password callback(NO,[self raiseError:nil code:PGClientErrorNeedsPassword]); @@ -170,12 +177,13 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus } #if defined DEBUG && defined DEBUG2 - NSLog(@"%@ (%p) :: END :: - Read::end - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); + NSLog(@"%@ (%p) :: END :: - Read::END - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); #endif // :: TODO :: //:: _callback = nil; // - [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; +// [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; +// [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; // [self pushPoolOperation]; } @@ -202,7 +210,12 @@ -(void)_socketCallbackResetEndedWithStatus:(PostgresPollingStatusType)pqstatus { */ -(void)_socketCallbackConnect { // ignore this call if either connection or callback are nil - if(_connection==nil || ![[self currentPoolOperation] valid]) { // || (_callback==nil) // && _callbackOperation == nil) + + PGConnectionOperation* currentpoolOpe = [self currentPoolOperation]; + if(_connection==nil +// || ![[self currentPoolOperation] valid] + || ( [currentpoolOpe poolIdentifier]) !=0 + ) { // || (_callback==nil) // && _callbackOperation == nil) return; } @@ -265,8 +278,13 @@ -(void)_socketCallbackQueryRead { // NSParameterAssert([[self currentPoolOperation] valid]); + + PGConnectionOperation* currentPoolOperation = [self currentPoolOperation]; + //:: void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); + void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); + #if defined DEBUG && defined DEBUG2 NSLog(@":::: PGConnectionStateQuery(%@::%p) - Read BEGIN - Result - :: callback \n_callback :: (%@)\n ********************************* ",NSStringFromClass([self class]), self , callback ); #endif @@ -302,7 +320,7 @@ -(void)_socketCallbackQueryRead { PQclear(result); } else { #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Read - Result - READ Query RESULT" ); + NSLog(@"PGConnectionStateQuery - Read - Result - READ Query RESULT (%@)",[currentPoolOperation queryString] ); #endif // TODO: allocate a different kind of class r = [[PGResult alloc] initWithResult:result format:[self tupleFormat]]; @@ -326,10 +344,13 @@ -(void)_socketCallbackQueryRead { #if defined DEBUG && defined DEBUG2 NSLog(@"PGConnectionStateQuery - Read - callback %p ",callback); #endif + callback(r,error); + [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; + [((PGConnectionOperation*)[self masterPoolOperation]) validate]; }); -// break; + break; } } #if defined DEBUG && defined DEBUG2 @@ -339,8 +360,8 @@ -(void)_socketCallbackQueryRead { [self setState:PGConnectionStateNone]; //:: _callback = nil; // release the callback - - [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; + [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; +// [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; [self _updateStatus]; #if defined DEBUG && defined DEBUG2 diff --git a/src/Frameworks/PGClientKit/PGConnection+Connect.m b/src/Frameworks/PGClientKit/PGConnection+Connect.m index 3e56bab..8f1b7b3 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Connect.m +++ b/src/Frameworks/PGClientKit/PGConnection+Connect.m @@ -105,7 +105,7 @@ -(void)connectWithURL:(NSURL* )url whenDone:(void(^)(BOOL usedPassword,NSError* NSParameterAssert(_connection==nil); NSParameterAssert(_socket==nil); NSParameterAssert(_runloopsource==nil); - + [NSThread detachNewThreadWithBlock:^{ // extract connection parameters NSDictionary* parameters = [self _connectionParametersForURL:url]; if(parameters==nil) { @@ -145,10 +145,12 @@ -(void)connectWithURL:(NSURL* )url whenDone:(void(^)(BOOL usedPassword,NSError* // not quite good for cascaded Operation //:: _callback = (__bridge_retained void* )[callback copy]; // So we do good things to deal with cascaded Operation + [self addOperation:self withCallBackWhenDone: (__bridge_retained void* )callback withCallBackWhenError: (__bridge_retained void* )callback ]; // add socket to run loop [self _socketConnect:PGConnectionStateConnect]; + }]; } -(BOOL)connectWithURL:(NSURL* )url usedPassword:(BOOL* )usedPassword error:(NSError** )error { diff --git a/src/Frameworks/PGClientKit/PGConnection+Execute.m b/src/Frameworks/PGClientKit/PGConnection+Execute.m index ff21ae3..ba07e42 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Execute.m +++ b/src/Frameworks/PGClientKit/PGConnection+Execute.m @@ -31,87 +31,96 @@ @implementation PGConnection (Execute) #pragma mark private methods - statement execution //////////////////////////////////////////////////////////////////////////////// + + -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGResult* result,NSError* error)) callback { - - NSParameterAssert(query && [query isKindOfClass:[NSString class]]); - if(_connection==nil || [self state] != PGConnectionStateNone) { - callback(nil,[self raiseError:nil code:PGClientErrorState]); - return; - } - - // create parameters object - PGClientParams* params = _paramAllocForValues(values); - if(params==nil) { - callback(nil,[self raiseError:nil code:PGClientErrorParameters]); - return; - } - // convert parameters - for(NSUInteger i = 0; i < [values count]; i++) { - id obj = [values objectAtIndex:i]; - if([obj isKindOfClass:[NSNull class]]) { - _paramSetNull(params,i); - continue; - } - if([obj isKindOfClass:[NSString class]]) { - NSData* data = [(NSString* )obj dataUsingEncoding:NSUTF8StringEncoding]; - _paramSetBinary(params,i,data,(Oid)25); - continue; - } - // TODO - other kinds of parameters - NSLog(@"TODO: Turn %@ into arg",[obj class]); - _paramSetNull(params,i); - } - - - // check number of parameters - if(params->size > INT_MAX) { - _paramFree(params); - callback(nil,[self raiseError:nil code:PGClientErrorParameters]); - return; - } - - // call the delegate, determine the class to use for the resultset - NSString* className = nil; - if([[self delegate] respondsToSelector:@selector(connection:willExecute:)]) { - className = [[self delegate] connection:self willExecute:query]; - } - - NSParameterAssert(callback!=nil); + NSParameterAssert(query && [query isKindOfClass:[NSString class]]); + if(_connection==nil || [self state] != PGConnectionStateNone) { + callback(nil,[self raiseError:nil code:PGClientErrorState]); + return; + } - _callbackOperation = (__bridge_retained void* )[callback copy]; + // create parameters object + PGClientParams* params = _paramAllocForValues(values); + if(params==nil) { + callback(nil,[self raiseError:nil code:PGClientErrorParameters]); + return; + } + // convert parameters + for(NSUInteger i = 0; i < [values count]; i++) { + id obj = [values objectAtIndex:i]; + if([obj isKindOfClass:[NSNull class]]) { + _paramSetNull(params,i); + continue; + } + if([obj isKindOfClass:[NSString class]]) { + NSData* data = [(NSString* )obj dataUsingEncoding:NSUTF8StringEncoding]; + _paramSetBinary(params,i,data,(Oid)25); + continue; + } + // TODO - other kinds of parameters + NSLog(@"TODO: Turn %@ into arg",[obj class]); + _paramSetNull(params,i); + } - // if([self currentPoolOperation] != nil) [[self currentPoolOperation] invalidate]; - [self addOperation:query withCallBackWhenDone: (__bridge_retained void* )callback withCallBackWhenError: (__bridge_retained void* )callback ]; + // check number of parameters + if(params->size > INT_MAX) { + _paramFree(params); + callback(nil,[self raiseError:nil code:PGClientErrorParameters]); + return; + } - NSParameterAssert(_callbackOperation!=nil); + // call the delegate, determine the class to use for the resultset + NSString* className = nil; + if([[self delegate] respondsToSelector:@selector(connection:willExecute:)]) { + className = [[self delegate] connection:self willExecute:query]; + } + // set state, update status + [self setState:PGConnectionStateQuery]; - // execute the command, free parameters - int resultFormat = ([self tupleFormat]==PGClientTupleFormatBinary) ? 1 : 0; - int returnCode = PQsendQueryParams(_connection,[query UTF8String],(int)params->size,params->types,(const char** )params->values,params->lengths,params->formats,resultFormat); - _paramFree(params); - if(!returnCode) { + [self _updateStatus]; + + // execute the command, free parameters + int resultFormat = ([self tupleFormat]==PGClientTupleFormatBinary) ? 1 : 0; + int returnCode = PQsendQueryParams(_connection,[query UTF8String],(int)params->size,params->types,(const char** )params->values,params->lengths,params->formats,resultFormat); + _paramFree(params); + if(!returnCode) { #if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %@ :: - execute - error :: callback %p ", NSStringFromSelector(_cmd),NSStringFromClass([self class]), callback); + NSLog(@"%@ :: %@ :: - execute - ERROR :: callback %p :: While EXECUTE (%@)", NSStringFromSelector(_cmd),NSStringFromClass([self class]), callback, query); #endif - callback(nil,[self raiseError:nil code:PGClientErrorExecute reason:[NSString stringWithUTF8String:PQerrorMessage(_connection)]]); - return; - } - - // set state, update status - [self setState:PGConnectionStateQuery]; - - [self _updateStatus]; - - + callback(nil,[self raiseError:nil code:PGClientErrorExecute reason:[NSString stringWithUTF8String:PQerrorMessage(_connection)]]); + return; + }else{ #if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %@ :: - execute - return :: callback %p :: %p ", NSStringFromSelector(_cmd),NSStringFromClass([self class]), callback, _callbackOperation); + NSLog(@"%@ :: %@ :: - execute - PASSED :: callback %p :: While EXECUTE (%@)", NSStringFromSelector(_cmd),NSStringFromClass([self class]), callback, query); #endif - [NSThread sleepForTimeInterval: .2]; + } + + // // set state, update status + // [self setState:PGConnectionStateQuery]; + // + // [self _updateStatus]; + + +#if defined DEBUG && defined DEBUG2 + NSLog(@"%@ :: %@ :: - execute - RETURN :: callback %p :: %p ", NSStringFromSelector(_cmd),NSStringFromClass([self class]), callback, _callbackOperation); +#endif + NSParameterAssert(callback!=nil); + + _callbackOperation = (__bridge_retained void* )[callback copy]; + + // if([self currentPoolOperation] != nil) [[self currentPoolOperation] invalidate]; + + [self addOperation:query withCallBackWhenDone: (__bridge_retained void* )callback withCallBackWhenError: (__bridge_retained void* )callback ]; + + NSParameterAssert(_callbackOperation!=nil); + + // [NSThread sleepForTimeInterval: .2]; } //////////////////////////////////////////////////////////////////////////////// @@ -119,116 +128,142 @@ -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGR //////////////////////////////////////////////////////////////////////////////// -(void)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) callback { - NSParameterAssert([query isKindOfClass:[NSString class]] || [query isKindOfClass:[PGQuery class]]); - NSParameterAssert(callback); - NSString* query2 = nil; - NSError* error = nil; - if([query isKindOfClass:[NSString class]]) { - query2 = query; - } else { - query2 = [(PGQuery* )query quoteForConnection:self error:&error]; - } - if(error) { + + + + // if([((PGConnectionOperation*)[self currentPoolOperation]) valid]) + // if([((PGConnectionOperation*)[self currentPoolOperation]) poolIdentifier] !=0 ){ + + // [NSThread detachNewThreadSelector:_cmd toTarget:self withObject:nil ]; +// if([((PGConnectionOperation*)[self currentPoolOperation]) poolIdentifier] !=0 ) + + + + // } + [NSThread detachNewThreadWithBlock:^{ +// [self performSelectorOnMainThread:@selector(_waitingPoolOperationForResult) withObject:self waitUntilDone:YES ]; + + + NSParameterAssert([query isKindOfClass:[NSString class]] || [query isKindOfClass:[PGQuery class]]); + NSParameterAssert(callback); + NSString* query2 = nil; + NSError* error = nil; + if([query isKindOfClass:[NSString class]]) { + query2 = query; + } else { + query2 = [(PGQuery* )query quoteForConnection:self error:&error]; + } + if(error) { #if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %@ - query ERROR - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); + NSLog(@"%@ :: %@ - query ERROR - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); #endif - callback(nil,error); - } else if(query2==nil) { - callback(nil,[self raiseError:nil code:PGClientErrorExecute reason:@"Query is nil"]); - } else { + callback(nil,error); + } else if(query2==nil) { + callback(nil,[self raiseError:nil code:PGClientErrorExecute reason:@"Query is nil"]); + } else { #if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %@ - query - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); + NSLog(@"%@ :: %@ - query - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); #endif - [self _execute:query2 values:nil whenDone: callback]; - } + + + + [self _execute:query2 values:nil whenDone: callback]; + + } + }]; + + [self performSelector:@selector(_waitingPoolOperationForResult) withObject:self ]; + [self performSelector:@selector(_waitingPoolOperationForResultMaster) withObject:self ]; + + } -(PGResult* )execute:(id)query error:(NSError** )error { - dispatch_semaphore_t s = dispatch_semaphore_create(0); - __block PGResult* result = nil; - [self execute:query whenDone:^(PGResult* r, NSError* e) { - if(error) { - (*error) = e; - } - result = r; - dispatch_semaphore_signal(s); - }]; - dispatch_semaphore_wait(s,DISPATCH_TIME_FOREVER); - return result; + dispatch_semaphore_t s = dispatch_semaphore_create(0); + __block PGResult* result = nil; + [self execute:query whenDone:^(PGResult* r, NSError* e) { + if(error) { + (*error) = e; + } + result = r; + dispatch_semaphore_signal(s); + }]; + dispatch_semaphore_wait(s,DISPATCH_TIME_FOREVER); + return result; } -(void)_queue:(PGTransaction* )transaction index:(NSUInteger)i lastResult:(PGResult* )result lastError:(NSError* )error whenQueryDone:(void(^)(PGResult* result,BOOL isLastQuery,NSError* error)) callback { - if(error) { - // rollback - if([transaction transactional]) { - NSString* rollbackTransaction = [(PGTransaction* )transaction quoteRollbackTransactionForConnection:self]; - NSParameterAssert(rollbackTransaction); - [self execute:rollbackTransaction whenDone:^(PGResult* result2,NSError* error2) { - callback(nil,YES,error); - }]; - } else { - callback(nil,YES,error); - } - } else if(i==[transaction count]) { - // commit - if([transaction transactional]) { - NSString* commitTransaction = [(PGTransaction* )transaction quoteCommitTransactionForConnection:self]; - NSParameterAssert(commitTransaction); - [self execute:commitTransaction whenDone:^(PGResult* result2, NSError* error2) { - callback(result,YES,error); - }]; - } else { - callback(result,YES,error); - } - } else { - // execute a single query - [self execute:[transaction queryAtIndex:i] whenDone:^(PGResult* result,NSError* error) { - if(i < [transaction count]) { - [self _queue:transaction index:(i+1) lastResult:result lastError:error whenQueryDone:callback]; - } - }]; - } + if(error) { + // rollback + if([transaction transactional]) { + NSString* rollbackTransaction = [(PGTransaction* )transaction quoteRollbackTransactionForConnection:self]; + NSParameterAssert(rollbackTransaction); + [self execute:rollbackTransaction whenDone:^(PGResult* result2,NSError* error2) { + callback(nil,YES,error); + }]; + } else { + callback(nil,YES,error); + } + } else if(i==[transaction count]) { + // commit + if([transaction transactional]) { + NSString* commitTransaction = [(PGTransaction* )transaction quoteCommitTransactionForConnection:self]; + NSParameterAssert(commitTransaction); + [self execute:commitTransaction whenDone:^(PGResult* result2, NSError* error2) { + callback(result,YES,error); + }]; + } else { + callback(result,YES,error); + } + } else { + // execute a single query + [self execute:[transaction queryAtIndex:i] whenDone:^(PGResult* result,NSError* error) { + if(i < [transaction count]) { + [self _queue:transaction index:(i+1) lastResult:result lastError:error whenQueryDone:callback]; + } + }]; + } } -(void)queue:(PGTransaction* )transaction whenQueryDone:(void(^)(PGResult* result,BOOL isLastQuery,NSError* error)) callback { - NSParameterAssert(transaction && [transaction isKindOfClass:[PGTransaction class]]); - - // where there are no transactions to execute, raise error immediately - if([transaction count]==0) { - callback(nil,YES,[self raiseError:nil code:PGClientErrorExecute reason:@"No transactions to execute"]); - return; - } - - // check for connection status - if(_connection==nil || [self state] != PGConnectionStateNone) { - callback(nil,YES,[self raiseError:nil code:PGClientErrorState]); - return; - } - - // check for transaction status - PGTransactionStatusType tstatus = PQtransactionStatus(_connection); - if([transaction transactional] && tstatus != PQTRANS_IDLE) { - callback(nil,YES,[self raiseError:nil code:PGClientErrorState reason:@"Already in a transaction"]); - return; - } - - if([transaction transactional]==NO) { - // queue zeroth query - [self _queue:transaction index:0 lastResult:nil lastError:nil whenQueryDone:callback]; - } else { - // queue up a start transaction, which triggers the first query - NSString* beginTransaction = [(PGTransaction* )transaction quoteBeginTransactionForConnection:self]; - NSParameterAssert(beginTransaction); - [self execute:beginTransaction whenDone:^(PGResult* result, NSError* error) { - // if the BEGIN transaction didn't work, then callback - if(error) { - callback(nil,YES,error); - } else { - // else queue up zeroth query - [self _queue:transaction index:0 lastResult:result lastError:error whenQueryDone:callback]; - } - }]; - } + NSParameterAssert(transaction && [transaction isKindOfClass:[PGTransaction class]]); + + // where there are no transactions to execute, raise error immediately + if([transaction count]==0) { + callback(nil,YES,[self raiseError:nil code:PGClientErrorExecute reason:@"No transactions to execute"]); + return; + } + + // check for connection status + if(_connection==nil || [self state] != PGConnectionStateNone) { + callback(nil,YES,[self raiseError:nil code:PGClientErrorState]); + return; + } + + // check for transaction status + PGTransactionStatusType tstatus = PQtransactionStatus(_connection); + if([transaction transactional] && tstatus != PQTRANS_IDLE) { + callback(nil,YES,[self raiseError:nil code:PGClientErrorState reason:@"Already in a transaction"]); + return; + } + + if([transaction transactional]==NO) { + // queue zeroth query + [self _queue:transaction index:0 lastResult:nil lastError:nil whenQueryDone:callback]; + } else { + // queue up a start transaction, which triggers the first query + NSString* beginTransaction = [(PGTransaction* )transaction quoteBeginTransactionForConnection:self]; + NSParameterAssert(beginTransaction); + [self execute:beginTransaction whenDone:^(PGResult* result, NSError* error) { + // if the BEGIN transaction didn't work, then callback + if(error) { + callback(nil,YES,error); + } else { + // else queue up zeroth query + [self _queue:transaction index:0 lastResult:result lastError:error whenQueryDone:callback]; + } + }]; + } } @end diff --git a/src/Frameworks/PGClientKit/PGConnection.h b/src/Frameworks/PGClientKit/PGConnection.h index e4724c7..4c7f52a 100644 --- a/src/Frameworks/PGClientKit/PGConnection.h +++ b/src/Frameworks/PGClientKit/PGConnection.h @@ -183,12 +183,19 @@ typedef enum { -(NSString* )encryptedPassword:(NSString* )password role:(NSString* )roleName; + +-(NSInteger)currentPoolOperationChildCount; +-(NSInteger)connectionPoolOperationCount; + -(id)addOperation:(id)operationClass withCallBackWhenDone:(void*)callBackWhenDone withCallBackWhenError:(void*)callBackWhenError; +-(PGConnectionOperation*)prevPoolOperation; -(PGConnectionOperation*)currentPoolOperation; +-(PGConnectionOperation*)masterPoolOperation; -(id)invalidateOperation:(NSInteger)operationRefIndex; - +-(void)_waitingPoolOperationForResult; +-(void)_waitingPoolOperationForResultMaster; @end diff --git a/src/Frameworks/PGClientKit/PGConnection.m b/src/Frameworks/PGClientKit/PGConnection.m index 131d1eb..0451741 100644 --- a/src/Frameworks/PGClientKit/PGConnection.m +++ b/src/Frameworks/PGClientKit/PGConnection.m @@ -291,6 +291,38 @@ -(void)_updateStatus { } } + + +-(NSInteger)currentPoolOperationChildCount +{ + CFIndex indexInPool = CFArrayGetCount(_callbackOperationPool); + return indexInPool; +} + +-(NSInteger)connectionPoolOperationCount +{ + CFIndex indexInPool = CFArrayGetCount(_callbackOperationPool); + return indexInPool; +} +-(PGConnectionOperation*)masterPoolOperation +{ + PGConnectionOperation* masterPoolOperation = nil; + + CFIndex indexInPool = CFArrayGetCount(_callbackOperationPool); + if(indexInPool > 0 ) + { + masterPoolOperation = (__bridge PGConnectionOperation*) CFArrayGetValueAtIndex(_callbackOperationPool, 0); + }else{ + NSLog(@" ERROR :: NO master pool .... "); + } +#if defined DEBUG && defined DEBUG2 + // NSLog(@" %@::%@ :: FETCH cureent pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, masterPoolOperation); +#endif + + + return masterPoolOperation; +} + -(PGConnectionOperation*)currentPoolOperation { PGConnectionOperation* masterPoolOperation = nil; @@ -303,18 +335,41 @@ -(PGConnectionOperation*)currentPoolOperation NSLog(@" ERROR :: NO pool .... "); } #if defined DEBUG && defined DEBUG2 - NSLog(@" %@::%@ :: SELECT pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, masterPoolOperation); +// NSLog(@" %@::%@ :: FETCH cureent pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, masterPoolOperation); #endif - id currentPoolOpe = nil; + + + return masterPoolOperation; +} + + +-(PGConnectionOperation*)prevPoolOperation +{ + PGConnectionOperation* masterPoolOperation = nil; + + CFIndex indexInPool = CFArrayGetCount(_callbackOperationPool); + if(indexInPool > 1 ) + { + masterPoolOperation = (__bridge PGConnectionOperation*) CFArrayGetValueAtIndex(_callbackOperationPool, indexInPool-2); + }else{ + NSLog(@" ERROR :: NO PREV pool .... "); + return [self currentPoolOperation]; + } +#if defined DEBUG && defined DEBUG2 + // NSLog(@" %@::%@ :: FETCH prev pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, masterPoolOperation); +#endif + return masterPoolOperation; } -(id)addOperation: (id)operationClass withCallBackWhenDone:(void*)callBackWhenDone withCallBackWhenError:(void*)callBackWhenError { - // void * callbackDone = ^(id result, NSError *error) { - // callBackWhenDone(result, error); - // [[ self getConnectionDelegate] invalidateOperation: [((PGConnectionOperation*)self) poolIdentifier] ]; - // } + void * recall_callbackDone = (__bridge void *)((__bridge void (^)(void* result, void* error)) (callBackWhenDone)); + + +// callBackWhenDone(result, error); +// [[ ((PGConnectionOperation*)self) getConnectionDelegate] invalidateOperation: [((PGConnectionOperation*)self) poolIdentifier] ]; + CFIndex indexInPool = CFArrayGetCount(_callbackOperationPool); @@ -345,6 +400,77 @@ -(id)invalidateOperation:(NSInteger)operationRefIndex return nil; } +-(void)_waitingPoolOperationForResult +{ + PGConnectionOperation* prevPoolOpe = [self prevPoolOperation]; + PGConnectionOperation* currentPoolOpe = [self currentPoolOperation]; + + NSLog(@" Waiting for concurrent queries resultset (%lu) (%@) ...... ", [self connectionPoolOperationCount], [self currentPoolOperation]); + NSTimeInterval resolutionTimeOut = 0.5; + bool isRunning = NO; + while (1) { + + + prevPoolOpe = [self prevPoolOperation]; + currentPoolOpe = [self currentPoolOperation]; + + + + + + if([((PGConnectionOperation*)currentPoolOpe) valid] + && [((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0 + ) + { +// NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; +// isRunning = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; +// [NSThread sleepForTimeInterval:.1]; +// NSLog(@" >>>>> :::: %@ .... %d",NSStringFromSelector(_cmd),isRunning); + +// return; + }else{ + + break; + } + } + NSLog(@" CLEARED Waiting for concurrent queries resultset (%lu) (%@) ...... ", [self connectionPoolOperationCount], [self currentPoolOperation]); +} +-(void)_waitingPoolOperationForResultMaster +{ + NSTimeInterval resolutionTimeOut = 0.5; + bool isRunning = NO; + + PGConnectionOperation* prevPoolOpe = [self prevPoolOperation]; + PGConnectionOperation* currentPoolOpe = [self currentPoolOperation]; + + while ([((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0) { + + + prevPoolOpe = [self prevPoolOperation]; + currentPoolOpe = [self currentPoolOperation]; + + + + if([((PGConnectionOperation*)prevPoolOpe) valid] + && [((PGConnectionOperation*)currentPoolOpe) valid] + ) + { +// NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; +// isRunning = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; + [NSThread sleepForTimeInterval:.1]; + NSLog(@" >>>>> master wait :::: %@ .... %d",NSStringFromSelector(_cmd),isRunning); + + // return; + }else{ + NSLog(@" >>>>> master wait :: done :::: .... %d",isRunning); + break; + } + } + + +} + + //////////////////////////////////////////////////////////////////////////////// #pragma mark public methods - quoting //////////////////////////////////////////////////////////////////////////////// diff --git a/src/Frameworks/PGClientKit/PGConnectionOperation.h b/src/Frameworks/PGClientKit/PGConnectionOperation.h index 46ce326..88c41e4 100644 --- a/src/Frameworks/PGClientKit/PGConnectionOperation.h +++ b/src/Frameworks/PGClientKit/PGConnectionOperation.h @@ -33,18 +33,21 @@ id _operation; id _operationInfo; id _operationType; - NSInteger poolRefIdentifier; - NSInteger operationStatus; - bool invalidated; + NSInteger _poolRefIdentifier; + NSInteger _operationStatus; + bool _invalidated; } //(void(^)(id result,NSError* error)) -(instancetype)initWithParametersDelegate:(id)connectionDelegate withRefPoolIdentifier:(NSInteger)poolIdentifier refClassOperation:(id)operation callWhenDone:(void*) callBackBlockDone callWhenError:(void(^)(id result,NSError* error)) callBackBlockError; -(PGConnection*)getConnectionDelegate; +-(NSInteger)poolIdentifier; + -(id)queryString; -(id)UTF8String; -(bool)valid; +-(void)validate; -(void)invalidate; -(void *)getCallback; diff --git a/src/Frameworks/PGClientKit/PGConnectionOperation.m b/src/Frameworks/PGClientKit/PGConnectionOperation.m index 542ead0..8cd3573 100644 --- a/src/Frameworks/PGClientKit/PGConnectionOperation.m +++ b/src/Frameworks/PGClientKit/PGConnectionOperation.m @@ -35,7 +35,7 @@ -(instancetype)init _operationInfo = nil; _callbackWhenDone = NULL; _callbackWhenError = NULL; - invalidated = YES; + _invalidated = YES; return self; } @@ -53,11 +53,11 @@ -(instancetype)initWithParametersDelegate:(id)connectionDelegate withRefPoolIden _operation = operation; - poolRefIdentifier = poolIdentifier; + _poolRefIdentifier = poolIdentifier; _callbackWhenDone = (__bridge_retained void* )([(__bridge void (^)(void* ,void* ))(callBackBlockDone) copy]);//(__bridge void (^)(PGResult* ,NSError* ))(callBackBlockDone); _callbackWhenError = (__bridge_retained void* )([(__bridge void (^)(void* ,void* ))(callBackBlockError) copy]);//(__bridge void (^)(PGResult* ,NSError* ))(callBackBlockDone); - invalidated = NO; + _invalidated = NO; }else{ return nil; } @@ -65,19 +65,32 @@ -(instancetype)initWithParametersDelegate:(id)connectionDelegate withRefPoolIden } -(bool)valid { - return !invalidated; + return !_invalidated; } -(void)invalidate { - NSLog(@" %@::%@ :: INVALIDATE pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), poolRefIdentifier, [self description]); - if(poolRefIdentifier !=0) - [_operationConnectionClassRef invalidateOperation: poolRefIdentifier]; - invalidated = TRUE; + NSLog(@" %@::%@ :: INVALIDATE pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), _poolRefIdentifier, [self description]); + if(_poolRefIdentifier !=0) + [_operationConnectionClassRef invalidateOperation: _poolRefIdentifier]; + _invalidated = TRUE; +} + +-(void)validate +{ + NSLog(@" %@::%@ :: REACTIVATE pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), _poolRefIdentifier, [self description]); + if(_poolRefIdentifier !=0) + [_operationConnectionClassRef invalidateOperation: _poolRefIdentifier]; + _invalidated = NO; } -(PGConnection*)getConnectionDelegate { return _operationConnectionClassRef; +} +-(NSInteger)poolIdentifier +{ + return _poolRefIdentifier; + } -(void *)getCallback From 502706935705ffc901061b7e012925f1f547ca8b Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Wed, 2 Aug 2017 19:14:18 +0200 Subject: [PATCH 05/21] More Dark Experimental thinks --- postgresql-kit.xcodeproj/project.pbxproj | 4 +- .../PGClientKit/NSURL+PGAdditions.m | 4 +- src/Frameworks/PGClientKit/PGClientKit.h | 55 ++++ .../PGClientKit/PGConnection+Callbacks.m | 76 +++++- .../PGClientKit/PGConnection+Connect.m | 43 ++- .../PGClientKit/PGConnection+Errors.m | 16 +- .../PGClientKit/PGConnection+Execute.m | 254 +++++++++++++++--- src/Frameworks/PGClientKit/PGConnection.h | 9 + src/Frameworks/PGClientKit/PGConnection.m | 14 +- .../PGClientKit/PGConnectionOperation.h | 3 + .../PGClientKit/PGConnectionOperation.m | 8 +- src/Frameworks/PGClientKit/PGPasswordStore.m | 2 +- 12 files changed, 427 insertions(+), 61 deletions(-) diff --git a/postgresql-kit.xcodeproj/project.pbxproj b/postgresql-kit.xcodeproj/project.pbxproj index f250052..74d3d03 100644 --- a/postgresql-kit.xcodeproj/project.pbxproj +++ b/postgresql-kit.xcodeproj/project.pbxproj @@ -2861,7 +2861,7 @@ ); ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "-I/usr/local/include"; - SDKROOT = macosx; + SDKROOT = macosx10.10; STRIP_INSTALLED_PRODUCT = NO; }; name = Debug; @@ -2872,7 +2872,7 @@ CLANG_ENABLE_OBJC_ARC = YES; GCC_OPTIMIZATION_LEVEL = s; OTHER_CFLAGS = "-I/usr/local/include"; - SDKROOT = macosx; + SDKROOT = macosx10.10; }; name = Release; }; diff --git a/src/Frameworks/PGClientKit/NSURL+PGAdditions.m b/src/Frameworks/PGClientKit/NSURL+PGAdditions.m index cb3f6e6..b86c1b2 100644 --- a/src/Frameworks/PGClientKit/NSURL+PGAdditions.m +++ b/src/Frameworks/PGClientKit/NSURL+PGAdditions.m @@ -21,7 +21,7 @@ @implementation NSURL (PGAdditions) // PRIVATE METHODS +(NSString* )_pg_urlencode:(NSString* )string { -#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0 || MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_10 +#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) // NSCharacterSet *allowedCharset = [NSCharacterSet characterSetWithCharactersInString:@"!*'();:@&=+$,/?%#[]"]; NSCharacterSet *allowedCharset = [NSCharacterSet URLQueryAllowedCharacterSet ]; return (NSString* ) [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharset ] ; @@ -295,7 +295,7 @@ -(NSDictionary* )postgresqlParameters { return nil; } -#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0 || MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_10 +#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) NSCharacterSet *allowedCharset = [NSCharacterSet URLPathAllowedCharacterSet]; diff --git a/src/Frameworks/PGClientKit/PGClientKit.h b/src/Frameworks/PGClientKit/PGClientKit.h index 42004d2..834c4e6 100644 --- a/src/Frameworks/PGClientKit/PGClientKit.h +++ b/src/Frameworks/PGClientKit/PGClientKit.h @@ -14,6 +14,61 @@ #import +typedef struct __CFRuntimeBase { + uintptr_t _cfisa; + uint8_t _cfinfo[4]; +#if __LP64__ + uint32_t _rc; +#endif +} CFRuntimeBase; + + +struct __shared_blob { + __unsafe_unretained dispatch_source_t _rdsrc; + __unsafe_unretained dispatch_source_t _wrsrc; + __unsafe_unretained CFRunLoopSourceRef _source; + __unsafe_unretained CFSocketNativeHandle _socket; + uint8_t _closeFD; + uint8_t _refCnt; +}; + +struct __CFSocket { + __unsafe_unretained CFRuntimeBase _base; + __unsafe_unretained struct __shared_blob *_shared; // non-NULL when valid, NULL when invalid + + uint8_t _state:2; // mutable, not written safely + uint8_t _isSaneFD:1; // immutable + uint8_t _connOriented:1; // immutable + uint8_t _wantConnect:1; // immutable + uint8_t _wantWrite:1; // immutable + uint8_t _wantReadType:2; // immutable + + uint8_t _error; + + uint8_t _rsuspended:1; + uint8_t _wsuspended:1; + uint8_t _readable:1; + uint8_t _writeable:1; + uint8_t _unused:4; + + uint8_t _reenableRead:1; + uint8_t _readDisabled:1; + uint8_t _reenableWrite:1; + uint8_t _writeDisabled:1; + uint8_t _connectDisabled:1; + uint8_t _connected:1; + uint8_t _leaveErrors:1; + uint8_t _closeOnInvalidate:1; + + int32_t _runLoopCounter; + + CFDataRef _address; // immutable, once created + CFDataRef _peerAddress; // immutable, once created + CFSocketCallBack _callout; // immutable + CFSocketContext _context; // immutable +}; + + //////////////////////////////////////////////////////////////////////////////// // typedefs diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index e03ad80..20cfb75 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -24,11 +24,13 @@ #import #import - +#include //////////////////////////////////////////////////////////////////////////////// #pragma mark C callback functions //////////////////////////////////////////////////////////////////////////////// + +//typedef struct __shared_blob soctted ; /** * This method is called from the run loop upon new data being available to read * on the socket, or the socket being able to write more data to the socket @@ -73,24 +75,44 @@ -(void)_socketConnect:(PGConnectionState)state { // create socket object CFSocketContext context = {0, (__bridge void* )(self), NULL, NULL, NULL}; - _socket = CFSocketCreateWithNative(NULL,PQsocket(_connection),kCFSocketReadCallBack | kCFSocketWriteCallBack,&_socketCallback,&context); + _socket = CFSocketCreateWithNative(kCFAllocatorDefault,PQsocket(_connection),kCFSocketReadCallBack | kCFSocketWriteCallBack,&_socketCallback,&context); + +// _socket = CFSocketCreate(kCFAllocatorDefault, 0, 0, 0, kCFSocketReadCallBack | kCFSocketWriteCallBack,&_socketCallback,&context); + NSParameterAssert(_socket && CFSocketIsValid(_socket)); // let libpq do the socket closing CFSocketSetSocketFlags(_socket,~kCFSocketCloseOnInvalidate & CFSocketGetSocketFlags(_socket)); - +// CFSocketEnableCallBacks(_socket, kCFSocketDataCallBack | kCFSocketReadCallBack | kCFSocketWriteCallBack); + + + dispatch_source_t dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_current_queue() ); + + dispatch_source_set_timer(dsrc, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC / 2, NSEC_PER_SEC); + +// cf(_socket, F_SETFL, O_NONBLOCK); // set state [self setState:state]; [self _updateStatus]; // add to run loop to begin polling - _runloopsource = CFSocketCreateRunLoopSource(NULL,_socket,0); + _runloopsource = CFSocketCreateRunLoopSource(NULL,_socket,128); NSParameterAssert(_runloopsource && CFRunLoopSourceIsValid(_runloopsource)); CFRunLoopAddSource( - CFRunLoopGetMain(), // CFRunLoopGetCurrent() +// CFRunLoopGetMain(), + CFRunLoopGetCurrent(), _runloopsource,(CFStringRef)kCFRunLoopCommonModes); #if defined DEBUG && defined DEBUG2 NSLog(@"%@ :: %@ :::: Socket created ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); #endif + + dispatch_semaphore_t semaphore_query_send = [[self masterPoolOperation] semaphore]; + [self wait_semaphore_read: semaphore_query_send ]; + + +// CFRunLoopRun();//(kCFRunLoopDefaultMode, 0.2 , NO); +#if defined DEBUG && defined DEBUG2 + NSLog(@" ------- %@ :: %@ :::: Socket Runloop Started ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); +#endif } -(void)_socketDisconnect { @@ -161,10 +183,41 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus if(pqstatus==PGRES_POLLING_OK) { // set up notice processor, set success condition PQsetNoticeProcessor(_connection,_noticeProcessor,(__bridge void *)(self)); - [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; - callback(usedPassword ? YES : NO,nil); - [((PGConnectionOperation*)[self masterPoolOperation]) validate]; - +#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) + [NSThread detachNewThreadWithBlock:^ +#else + + [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; + dispatch_semaphore_t ss = dispatch_semaphore_create(0); + + mach_port_t machTID = pthread_mach_thread_np(pthread_self()); + + const char * queued_name = [[NSString stringWithFormat:@"%s_%x", "operation_dispacthed_threads", machTID ] cString]; + + NSLog(@" //// %s ", queued_name); + + dispatch_queue_t queue = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); + + dispatch_barrier_async(queue,^ +#endif + { + + callback(usedPassword ? YES : NO,nil); + dispatch_semaphore_signal(ss); + + } +#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) + ] +#else + + ) +#endif + ; +// dispatch_semaphore_wait(ss,DISPATCH_TIME_FOREVER); + [self wait_semaphore_read:ss]; +// + [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; +// dispatch_destroy(queue); } else if(needsPassword) { // error callback - connection not made, needs password callback(NO,[self raiseError:nil code:PGClientErrorNeedsPassword]); @@ -339,8 +392,8 @@ -(void)_socketCallbackQueryRead { - // queue up callback on main thread - dispatch_async(dispatch_get_main_queue(),^{ + // queue up callback on nearest thread + dispatch_async(dispatch_get_current_queue(),^{ #if defined DEBUG && defined DEBUG2 NSLog(@"PGConnectionStateQuery - Read - callback %p ",callback); #endif @@ -367,6 +420,7 @@ -(void)_socketCallbackQueryRead { #if defined DEBUG && defined DEBUG2 NSLog(@"PGConnectionStateQuery - Read END - Result - Clear::End " ); #endif + _stateOperation = PGOperationStateNone; } /** diff --git a/src/Frameworks/PGClientKit/PGConnection+Connect.m b/src/Frameworks/PGClientKit/PGConnection+Connect.m index 8f1b7b3..43c45c8 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Connect.m +++ b/src/Frameworks/PGClientKit/PGConnection+Connect.m @@ -105,7 +105,14 @@ -(void)connectWithURL:(NSURL* )url whenDone:(void(^)(BOOL usedPassword,NSError* NSParameterAssert(_connection==nil); NSParameterAssert(_socket==nil); NSParameterAssert(_runloopsource==nil); - [NSThread detachNewThreadWithBlock:^{ +#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) + [NSThread detachNewThreadWithBlock:^{ +#else + +// dispatch_async(dispatch_get_main_queue(),^{ +#endif + + // extract connection parameters NSDictionary* parameters = [self _connectionParametersForURL:url]; if(parameters==nil) { @@ -147,10 +154,40 @@ -(void)connectWithURL:(NSURL* )url whenDone:(void(^)(BOOL usedPassword,NSError* // So we do good things to deal with cascaded Operation [self addOperation:self withCallBackWhenDone: (__bridge_retained void* )callback withCallBackWhenError: (__bridge_retained void* )callback ]; +#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) + } ]; +#else +// } ); +#endif // add socket to run loop - [self _socketConnect:PGConnectionStateConnect]; - }]; +#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) + [NSThread detachNewThreadWithBlock:^ +#else +// dispatch_get_current_queue +// dispatch_async(dispatch_get_current_queue(),^ +#endif + { + [self _socketConnect:PGConnectionStateConnect]; +// CFRunLoopRun(); +// [self performSelector:@selector(_waitingPoolOperationForResult) withObject:self ]; +// [self performSelector:@selector(_waitingPoolOperationForResultMaster) withObject:self ]; + +#if defined DEBUG && defined DEBUG2 + NSLog(@" ------- %@ :: %@ :::: Connection STOPPed ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); +#endif + + } +#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) + ] +#else + +// ) +#endif + ; +#if defined DEBUG && defined DEBUG2 + NSLog(@" ------- %@ :: %@ :::: Connection Started ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); +#endif } -(BOOL)connectWithURL:(NSURL* )url usedPassword:(BOOL* )usedPassword error:(NSError** )error { diff --git a/src/Frameworks/PGClientKit/PGConnection+Errors.m b/src/Frameworks/PGClientKit/PGConnection+Errors.m index e4966e5..9024181 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Errors.m +++ b/src/Frameworks/PGClientKit/PGConnection+Errors.m @@ -74,9 +74,21 @@ -(void)_raiseError:(NSError* )error { #endif // [[self delegate] connection:self error:error]; // @{@"connection":self, @"error":error} - [NSThread detachNewThreadWithBlock:^{ +#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) + [NSThread detachNewThreadWithBlock: +#else + + dispatch_async(dispatch_get_main_queue(), +#endif +^{ [[self delegate] connection:self error:error]; - }]; +} +#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) +]; +#else +); +#endif + // [NSThread detachNewThreadSelector:@selector(connection:error:) toTarget:[self delegate] withObject:nil ]; }else{ #if defined DEBUG && defined DEBUG2 diff --git a/src/Frameworks/PGClientKit/PGConnection+Execute.m b/src/Frameworks/PGClientKit/PGConnection+Execute.m index ba07e42..a650a94 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Execute.m +++ b/src/Frameworks/PGClientKit/PGConnection+Execute.m @@ -25,6 +25,53 @@ #import #import +#import +#import +#import + + + +#define INVALID_SOCKET (CFSocketNativeHandle)(-1) + +#define closesocket(a) close((a)) +#define ioctlsocket(a,b,c) ioctl((a),(b),(c)) + +CF_INLINE Boolean __CFSocketIsValid(CFSocketRef s); + +static CFStringRef __CFFSocketCopyDescription(CFTypeRef cf) { + CFSocketRef sock = (CFSocketRef)cf; + CFStringRef contextDesc = NULL; + if (NULL != sock->_context.info && NULL != sock->_context.copyDescription) { + contextDesc = sock->_context.copyDescription(sock->_context.info); + } + if (NULL == contextDesc) { + contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR(""), sock->_context.info); + } + Dl_info info; + void *addr = sock->_callout; + const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; + int avail = -1; + ioctlsocket(sock->_shared ? sock->_shared->_socket : -1, FIONREAD, &avail); + CFStringRef result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR( + "{valid = %s, socket = %d, " + "want connect = %s, connect disabled = %s, " + "want write = %s, reenable write = %s, write disabled = %s, " + "want read = %s, reenable read = %s, read disabled = %s, " + "leave errors = %s, close on invalidate = %s, connected = %s, " + "last error code = %d, bytes available for read = %d, " + "source = %p, callout = %s (%p), context = %@}"), + cf, CFGetAllocator(sock), (sock) ? "Yes" : "No", sock->_shared ? sock->_shared->_socket : -1, + sock->_wantConnect ? "Yes" : "No", sock->_connectDisabled ? "Yes" : "No", + sock->_wantWrite ? "Yes" : "No", sock->_reenableWrite ? "Yes" : "No", sock->_writeDisabled ? "Yes" : "No", + sock->_wantReadType ? "Yes" : "No", sock->_reenableRead ? "Yes" : "No", sock->_readDisabled? "Yes" : "No", + sock->_leaveErrors ? "Yes" : "No", sock->_closeOnInvalidate ? "Yes" : "No", sock->_connected ? "Yes" : "No", + sock->_error, avail, + sock->_shared ? sock->_shared->_source : NULL, name, addr, contextDesc); + if (NULL != contextDesc) { + CFRelease(contextDesc); + } + return result; +} @implementation PGConnection (Execute) //////////////////////////////////////////////////////////////////////////////// @@ -120,7 +167,7 @@ -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGR NSParameterAssert(_callbackOperation!=nil); - // [NSThread sleepForTimeInterval: .2]; + [NSThread sleepForTimeInterval: .2]; } //////////////////////////////////////////////////////////////////////////////// @@ -130,52 +177,191 @@ -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGR -(void)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) callback { - // if([((PGConnectionOperation*)[self currentPoolOperation]) valid]) // if([((PGConnectionOperation*)[self currentPoolOperation]) poolIdentifier] !=0 ){ // [NSThread detachNewThreadSelector:_cmd toTarget:self withObject:nil ]; -// if([((PGConnectionOperation*)[self currentPoolOperation]) poolIdentifier] !=0 ) + // if([((PGConnectionOperation*)[self currentPoolOperation]) poolIdentifier] !=0 ) + + _stateOperation = PGOperationStatePrepare; - // } - [NSThread detachNewThreadWithBlock:^{ -// [self performSelectorOnMainThread:@selector(_waitingPoolOperationForResult) withObject:self waitUntilDone:YES ]; - - - NSParameterAssert([query isKindOfClass:[NSString class]] || [query isKindOfClass:[PGQuery class]]); - NSParameterAssert(callback); - NSString* query2 = nil; - NSError* error = nil; - if([query isKindOfClass:[NSString class]]) { - query2 = query; - } else { - query2 = [(PGQuery* )query quoteForConnection:self error:&error]; - } - if(error) { +#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) + [NSThread detachNewThreadWithBlock:^ +#else + +// dispatch_queue_t queue_inRun = ( ( dispatch_get_current_queue() == dispatch_get_main_queue() )? dispatch_get_main_queue() : dispatch_get_current_queue() ); + mach_port_t machTID = pthread_mach_thread_np(pthread_self()); + + const char * queued_name = [[NSString stringWithFormat:@"%s_%x", "query_operation_dispacthed_threads", machTID ] cString]; + + NSLog(@" //// %s ", queued_name); + + dispatch_queue_t queue_inRun = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); + + dispatch_barrier_sync(queue_inRun,^ +#endif + + { + // [self performSelectorOnMainThread:@selector(_waitingPoolOperationForResult) withObject:self waitUntilDone:YES ]; + + + NSParameterAssert([query isKindOfClass:[NSString class]] || [query isKindOfClass:[PGQuery class]]); + NSParameterAssert(callback); + NSString* query2 = nil; + NSError* error = nil; + if([query isKindOfClass:[NSString class]]) { + query2 = query; + } else { + query2 = [(PGQuery* )query quoteForConnection:self error:&error]; + } + if(error) { #if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %@ - query ERROR - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); + NSLog(@"%@ :: %@ - query ERROR - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); #endif - callback(nil,error); - } else if(query2==nil) { - callback(nil,[self raiseError:nil code:PGClientErrorExecute reason:@"Query is nil"]); - } else { + callback(nil,error); + } else if(query2==nil) { + callback(nil,[self raiseError:nil code:PGClientErrorExecute reason:@"Query is nil"]); + } else { #if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %@ - query - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); + NSLog(@"%@ :: %@ - query - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); #endif - - - - [self _execute:query2 values:nil whenDone: callback]; - - } - }]; - - [self performSelector:@selector(_waitingPoolOperationForResult) withObject:self ]; - [self performSelector:@selector(_waitingPoolOperationForResultMaster) withObject:self ]; + void (^callback_recall)(PGResult* result,NSError* error) = ^(PGResult* result_recall ,NSError* error_recall) + { + NSLog(@" .... semaphore callback..... "); + callback(result_recall , error_recall); + NSLog(@" .... semaphore pass ..... "); + dispatch_semaphore_signal( [[self currentPoolOperation] semaphore] ); + NSLog(@" .... semaphore signal end ..... "); + + }; + // dispatch_semaphore_signal(semaphore_query_send); + [self _execute:query2 values:nil whenDone: callback_recall]; + + } + } + +#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) + ] +#else + + ) +#endif + ; + + // [self performSelector:@selector(_waitingPoolOperationForResult) withObject:self ]; + // [self performSelector:@selector(_waitingPoolOperationForResultMaster) withObject:self ]; + + _stateOperation = PGOperationStateBusy; + [NSThread sleepForTimeInterval:.2]; + NSLog(@"Is main queue? : %d", dispatch_get_current_queue() == dispatch_get_main_queue()); + dispatch_semaphore_t semaphore_query_send = [[self currentPoolOperation] semaphore]; + [self wait_semaphore_read: semaphore_query_send ]; + NSLog(@"I will see this, after dispatch_semaphore_signal is called"); +} +-(void)wait_semaphore_read:(dispatch_semaphore_t) sem +{ + mach_port_t machTID = pthread_mach_thread_np(pthread_self()); + const char * queued_name = [[NSString stringWithFormat:@"%@_%x :: %s :: %s :: %@ ", NSStringFromSelector(_cmd), machTID, dispatch_queue_get_label(dispatch_get_current_queue()), dispatch_queue_get_label(dispatch_get_main_queue()), sem ] cString]; + + NSLog(@" //// %s ", queued_name); + long diispacthed = YES; + NSTimeInterval resolutionTimeOut = 0.05; + NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; + bool isRunningThreadMain = YES; + bool isRunningThread = YES; + while( diispacthed && _runloopsource ) + { + + + diispacthed = dispatch_semaphore_wait(sem,DISPATCH_TIME_NOW); + dispatch_queue_t qq_qq = dispatch_get_current_queue(); + + id shared_info = (__bridge id)(_socket); + CFSocketCallBack shared_info_shared = (_socket->_callout); + const char * class_named = object_getClassName(shared_info); + + CFSocketNativeHandle sock = CFSocketGetNative(_socket); + + struct __shared_blob *shared_dd = malloc(sizeof(struct __shared_blob)); + + NSLog(@"%s", __CFFSocketCopyDescription(_socket)); + +// shared_dd->_rdsrc = (_socket->_shared)->_rdsrc; +// shared_dd->_wrsrc = (_socket->_shared)->_wrsrc; +// shared_dd->_source = (_socket->_shared)->_source; +// shared_dd->_socket = (_socket->_shared)->_socket; +// shared_dd->_closeFD = (_socket->_shared)->_closeFD ; +// shared_dd->_refCnt = (_socket->_shared)->_refCnt; + +// objc_mem(&shared_dd, *(_socket->_shared) , sizeof(struct __shared_blob)); + + unsigned int outCount, i; + objc_property_t *objcProperties = class_copyPropertyList([shared_info class], &outCount); + for (i = 0; i < outCount; i++) { + objc_property_t property = objcProperties[i]; + const char *propName = property_getName(property); + if(propName) { +// const char * propType = getPropertyType(property); + NSString * propertyName = [NSString stringWithUTF8String:propName]; + + } + } + +// [((NSObject*)shared_info) shared]; + id sockk = (__bridge id)((_socket)->_shared); + +// typedef struct __CFSocket sockt; +// +// dispatch_object_t disp_obj = (dispatch_object_t) ((shared_info*)->_shared->_rdsrc); +// dispatch_resume( ((dispatch_object_t) disp_obj) );; + if( diispacthed && !isRunningThreadMain && !isRunningThreadMain + && [[self currentPoolOperation] valid] + ) + [NSThread sleepForTimeInterval:.01]; + + CFRunLoopSourceSignal(_runloopsource); + CFRunLoopWakeUp(CFRunLoopGetMain()); + + + isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; + if(!isRunningThreadMain) + { + [NSThread sleepForTimeInterval:.01];; + } + + isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; + if(!isRunningThreadMain) + { + [NSThread sleepForTimeInterval:.01];; + } + + CFRunLoopSourceSignal(_runloopsource); + CFRunLoopWakeUp(CFRunLoopGetCurrent()); + + + isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; + if(!isRunningThread) + { + [NSThread sleepForTimeInterval:.01];; + } + + isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; + if(!isRunningThread) + { + [NSThread sleepForTimeInterval:.01];; + } + + if( diispacthed && !isRunningThreadMain && !isRunningThreadMain + && [[self currentPoolOperation] valid] && [self connectionPoolOperationCount] > 1 + && !PQisBusy(_connection) ) + break; + + } + // [[NSThread currentThread] cancel]; } -(PGResult* )execute:(id)query error:(NSError** )error { diff --git a/src/Frameworks/PGClientKit/PGConnection.h b/src/Frameworks/PGClientKit/PGConnection.h index 4c7f52a..aab9eca 100644 --- a/src/Frameworks/PGClientKit/PGConnection.h +++ b/src/Frameworks/PGClientKit/PGConnection.h @@ -77,6 +77,12 @@ typedef enum { PGClientTupleFormatBinary = 1 } PGClientTupleFormat; +typedef enum { + PGOperationStateNone = 0, + PGOperationStatePrepare = 1, + PGOperationStateBusy = 4 +} PGOperationState; + @class PGConnectionOperation; //////////////////////////////////////////////////////////////////////////////// @@ -92,6 +98,7 @@ typedef enum { CFRunLoopSourceRef _runloopsource; NSUInteger _timeout; PGConnectionState _state; + PGOperationState _stateOperation; NSDictionary* _parameters; PGClientTupleFormat _tupleFormat; } @@ -197,6 +204,8 @@ typedef enum { -(void)_waitingPoolOperationForResult; -(void)_waitingPoolOperationForResultMaster; +-(void)wait_semaphore_read:(dispatch_semaphore_t) sem; + @end //////////////////////////////////////////////////////////////////////////////// diff --git a/src/Frameworks/PGClientKit/PGConnection.m b/src/Frameworks/PGClientKit/PGConnection.m index 0451741..9ca56e0 100644 --- a/src/Frameworks/PGClientKit/PGConnection.m +++ b/src/Frameworks/PGClientKit/PGConnection.m @@ -75,6 +75,7 @@ -(instancetype)init { _connection = nil; _cancel = nil; // _callback = nil; + _stateOperation = PGOperationStateNone; _callbackOperation = nil; _callbackOperationPool = CFArrayCreateMutable(NULL, 64, &kCFTypeArrayCallBacks); // (NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); @@ -418,13 +419,16 @@ -(void)_waitingPoolOperationForResult - if([((PGConnectionOperation*)currentPoolOpe) valid] - && [((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0 + if( + ([((PGConnectionOperation*)currentPoolOpe) valid] && [((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0 ) +// && [((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0 + || (_stateOperation) ) { -// NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; -// isRunning = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; -// [NSThread sleepForTimeInterval:.1]; + NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; + isRunning = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; + isRunning = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; + [NSThread sleepForTimeInterval:.1]; // NSLog(@" >>>>> :::: %@ .... %d",NSStringFromSelector(_cmd),isRunning); // return; diff --git a/src/Frameworks/PGClientKit/PGConnectionOperation.h b/src/Frameworks/PGClientKit/PGConnectionOperation.h index 88c41e4..e78fae2 100644 --- a/src/Frameworks/PGClientKit/PGConnectionOperation.h +++ b/src/Frameworks/PGClientKit/PGConnectionOperation.h @@ -36,11 +36,14 @@ NSInteger _poolRefIdentifier; NSInteger _operationStatus; bool _invalidated; + dispatch_semaphore_t semaphore; } //(void(^)(id result,NSError* error)) -(instancetype)initWithParametersDelegate:(id)connectionDelegate withRefPoolIdentifier:(NSInteger)poolIdentifier refClassOperation:(id)operation callWhenDone:(void*) callBackBlockDone callWhenError:(void(^)(id result,NSError* error)) callBackBlockError; -(PGConnection*)getConnectionDelegate; + +-(dispatch_semaphore_t)semaphore; -(NSInteger)poolIdentifier; -(id)queryString; diff --git a/src/Frameworks/PGClientKit/PGConnectionOperation.m b/src/Frameworks/PGClientKit/PGConnectionOperation.m index 8cd3573..41131b0 100644 --- a/src/Frameworks/PGClientKit/PGConnectionOperation.m +++ b/src/Frameworks/PGClientKit/PGConnectionOperation.m @@ -58,6 +58,9 @@ -(instancetype)initWithParametersDelegate:(id)connectionDelegate withRefPoolIden _callbackWhenDone = (__bridge_retained void* )([(__bridge void (^)(void* ,void* ))(callBackBlockDone) copy]);//(__bridge void (^)(PGResult* ,NSError* ))(callBackBlockDone); _callbackWhenError = (__bridge_retained void* )([(__bridge void (^)(void* ,void* ))(callBackBlockError) copy]);//(__bridge void (^)(PGResult* ,NSError* ))(callBackBlockDone); _invalidated = NO; + + semaphore = dispatch_semaphore_create(0); + }else{ return nil; } @@ -92,7 +95,10 @@ -(NSInteger)poolIdentifier return _poolRefIdentifier; } - +-(dispatch_semaphore_t)semaphore +{ + return semaphore; +} -(void *)getCallback { // if(invalidated){ diff --git a/src/Frameworks/PGClientKit/PGPasswordStore.m b/src/Frameworks/PGClientKit/PGPasswordStore.m index ee3e548..d168af8 100644 --- a/src/Frameworks/PGClientKit/PGPasswordStore.m +++ b/src/Frameworks/PGClientKit/PGPasswordStore.m @@ -60,7 +60,7 @@ -(NSString* )_accountForURL:(NSURL* )url { value = [NSString stringWithFormat:@"%lu",(unsigned long)PGClientDefaultPort]; } if(value) { -#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0 || MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_10 +#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) NSCharacterSet *allowedCharset = [NSCharacterSet URLPathAllowedCharacterSet]; [parts addObject:[NSString stringWithFormat:@"%@=%@",key,[[value description] stringByAddingPercentEncodingWithAllowedCharacters: allowedCharset ]]]; From 5728d66e3b8f1a31ece2e23822246777d1cc2849 Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Thu, 3 Aug 2017 11:11:23 +0200 Subject: [PATCH 06/21] Separating / Replacing Socket creation --- postgresql-kit.xcodeproj/project.pbxproj | 12 ++ src/Frameworks/PGClientKit/PGClientKit.h | 109 ++++++++++++------ .../PGClientKit/PGConnection+Callbacks.m | 66 +---------- .../PGConnection+PGConnectionSocket.h | 15 +++ .../PGConnection+PGConnectionSocket.m | 100 ++++++++++++++++ 5 files changed, 203 insertions(+), 99 deletions(-) create mode 100644 src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.h create mode 100644 src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m diff --git a/postgresql-kit.xcodeproj/project.pbxproj b/postgresql-kit.xcodeproj/project.pbxproj index 74d3d03..aa89a05 100644 --- a/postgresql-kit.xcodeproj/project.pbxproj +++ b/postgresql-kit.xcodeproj/project.pbxproj @@ -326,6 +326,10 @@ 6EFFF2351A5F04C800CAA6E7 /* PGFoundationApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 6EFFF2311A5F044E00CAA6E7 /* PGFoundationApp.m */; }; 6EFFF23A1A5F052A00CAA6E7 /* PGFoundationApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 6EFFF2311A5F044E00CAA6E7 /* PGFoundationApp.m */; }; 6EFFF23C1A5F053000CAA6E7 /* Terminal.m in Sources */ = {isa = PBXBuildFile; fileRef = 6EFFF2391A5F051D00CAA6E7 /* Terminal.m */; }; + 74FDBBC21F32531F00606CC3 /* PGConnection+PGConnectionSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 74FDBBC01F32531F00606CC3 /* PGConnection+PGConnectionSocket.h */; }; + 74FDBBC31F32531F00606CC3 /* PGConnection+PGConnectionSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 74FDBBC01F32531F00606CC3 /* PGConnection+PGConnectionSocket.h */; }; + 74FDBBC41F32531F00606CC3 /* PGConnection+PGConnectionSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 74FDBBC11F32531F00606CC3 /* PGConnection+PGConnectionSocket.m */; }; + 74FDBBC51F32531F00606CC3 /* PGConnection+PGConnectionSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 74FDBBC11F32531F00606CC3 /* PGConnection+PGConnectionSocket.m */; }; C6457D4E1F288DD7005F6686 /* PGConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C6457D4A1F288DD7005F6686 /* PGConnectionOperation.m */; }; C6457D4F1F288DD7005F6686 /* PGConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C6457D4A1F288DD7005F6686 /* PGConnectionOperation.m */; }; C6457D501F288DD7005F6686 /* PGConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C6457D4A1F288DD7005F6686 /* PGConnectionOperation.m */; }; @@ -853,6 +857,8 @@ 6EFFF2331A5F044E00CAA6E7 /* PGFoundationServer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PGFoundationServer.m; sourceTree = ""; }; 6EFFF2381A5F051D00CAA6E7 /* Terminal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Terminal.h; sourceTree = ""; }; 6EFFF2391A5F051D00CAA6E7 /* Terminal.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Terminal.m; sourceTree = ""; }; + 74FDBBC01F32531F00606CC3 /* PGConnection+PGConnectionSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "PGConnection+PGConnectionSocket.h"; sourceTree = ""; }; + 74FDBBC11F32531F00606CC3 /* PGConnection+PGConnectionSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "PGConnection+PGConnectionSocket.m"; sourceTree = ""; }; C6457D491F288DD7005F6686 /* PGConnectionOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PGConnectionOperation.h; path = src/Frameworks/PGClientKit/PGConnectionOperation.h; sourceTree = SOURCE_ROOT; }; C6457D4A1F288DD7005F6686 /* PGConnectionOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PGConnectionOperation.m; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1597,6 +1603,8 @@ 6E9256B61AA64BDA007DAD82 /* PGConnection+Notifications.m */, 6E9256B71AA64BDA007DAD82 /* PGConnection+Ping.m */, 6E9256B81AA64BDA007DAD82 /* PGConnection+Reset.m */, + 74FDBBC01F32531F00606CC3 /* PGConnection+PGConnectionSocket.h */, + 74FDBBC11F32531F00606CC3 /* PGConnection+PGConnectionSocket.m */, ); name = PGConnection; sourceTree = ""; @@ -1826,6 +1834,7 @@ 1450A15F1AAA145A002D62D9 /* PGQuerySource.h in Headers */, 6E15484D1A5819EA00556573 /* PGQuery.h in Headers */, 6EC6748B1AD94F8900CAB4FF /* PGConnectionPool.h in Headers */, + 74FDBBC31F32531F00606CC3 /* PGConnection+PGConnectionSocket.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1867,6 +1876,7 @@ 6E4016B91ABEFA09009A2707 /* PGTransaction.h in Headers */, 1489AEC716669A6B00C3B67D /* PGResult+TextTable.h in Headers */, 14DECDA816B57EC400178235 /* PGConverters+Private.h in Headers */, + 74FDBBC21F32531F00606CC3 /* PGConnection+PGConnectionSocket.h in Headers */, 6EC5E6801AD7BDDE00774D57 /* PGQueryUpdate.h in Headers */, 1417B7BA1AAA1FF200B44DD4 /* PGQueryObject.h in Headers */, 6E0DDCD91AAB2A4000A38F3B /* NSString+PrivateAdditions.h in Headers */, @@ -2408,6 +2418,7 @@ 6E9256B31AA64B6C007DAD82 /* PGConnection+Connect.m in Sources */, 6E9256A21AA645FC007DAD82 /* PGConnection.m in Sources */, 1450A16A1AAA18DA002D62D9 /* PGQueryPredicate.m in Sources */, + 74FDBBC51F32531F00606CC3 /* PGConnection+PGConnectionSocket.m in Sources */, 6E1548461A5819C600556573 /* NSURL+PGAdditions.m in Sources */, 6EC6748D1AD94FAC00CAB4FF /* PGTransaction.m in Sources */, 6E0DDCE61AAB6F5200A38F3B /* PGQueryDatabase.m in Sources */, @@ -2533,6 +2544,7 @@ 6E9256A81AA6481E007DAD82 /* PGConnection+Callbacks.m in Sources */, 6E9256BD1AA64BDA007DAD82 /* PGConnection+Notifications.m in Sources */, 1489AEC816669A6B00C3B67D /* PGResult+TextTable.m in Sources */, + 74FDBBC41F32531F00606CC3 /* PGConnection+PGConnectionSocket.m in Sources */, 6E9256B21AA64B6C007DAD82 /* PGConnection+Connect.m in Sources */, 6E308D061ABD80810091BD17 /* NSError+PGAdditions.m in Sources */, 6E82F1741A9BC9B20024B8BE /* PGConnection.m in Sources */, diff --git a/src/Frameworks/PGClientKit/PGClientKit.h b/src/Frameworks/PGClientKit/PGClientKit.h index 834c4e6..d7208a4 100644 --- a/src/Frameworks/PGClientKit/PGClientKit.h +++ b/src/Frameworks/PGClientKit/PGClientKit.h @@ -32,43 +32,84 @@ struct __shared_blob { uint8_t _refCnt; }; +//struct __CFSocket { +// __unsafe_unretained CFRuntimeBase _base; +// __unsafe_unretained struct __shared_blob *_shared; // non-NULL when valid, NULL when invalid +// +// uint8_t _state:2; // mutable, not written safely +// uint8_t _isSaneFD:1; // immutable +// uint8_t _connOriented:1; // immutable +// uint8_t _wantConnect:1; // immutable +// uint8_t _wantWrite:1; // immutable +// uint8_t _wantReadType:2; // immutable +// +// uint8_t _error; +// +// uint8_t _rsuspended:1; +// uint8_t _wsuspended:1; +// uint8_t _readable:1; +// uint8_t _writeable:1; +// uint8_t _unused:4; +// +// uint8_t _reenableRead:1; +// uint8_t _readDisabled:1; +// uint8_t _reenableWrite:1; +// uint8_t _writeDisabled:1; +// uint8_t _connectDisabled:1; +// uint8_t _connected:1; +// uint8_t _leaveErrors:1; +// uint8_t _closeOnInvalidate:1; +// +// int32_t _runLoopCounter; +// +// CFDataRef _address; // immutable, once created +// CFDataRef _peerAddress; // immutable, once created +// CFSocketCallBack _callout; // immutable +// CFSocketContext _context; // immutable +//}; struct __CFSocket { - __unsafe_unretained CFRuntimeBase _base; - __unsafe_unretained struct __shared_blob *_shared; // non-NULL when valid, NULL when invalid - - uint8_t _state:2; // mutable, not written safely - uint8_t _isSaneFD:1; // immutable - uint8_t _connOriented:1; // immutable - uint8_t _wantConnect:1; // immutable - uint8_t _wantWrite:1; // immutable - uint8_t _wantReadType:2; // immutable - - uint8_t _error; - - uint8_t _rsuspended:1; - uint8_t _wsuspended:1; - uint8_t _readable:1; - uint8_t _writeable:1; - uint8_t _unused:4; - - uint8_t _reenableRead:1; - uint8_t _readDisabled:1; - uint8_t _reenableWrite:1; - uint8_t _writeDisabled:1; - uint8_t _connectDisabled:1; - uint8_t _connected:1; - uint8_t _leaveErrors:1; - uint8_t _closeOnInvalidate:1; - - int32_t _runLoopCounter; - - CFDataRef _address; // immutable, once created - CFDataRef _peerAddress; // immutable, once created - CFSocketCallBack _callout; // immutable - CFSocketContext _context; // immutable + CFRuntimeBase _base; + struct { + unsigned client:8; // flags set by client (reenable, CloseOnInvalidate) + unsigned disabled:8; // flags marking disabled callbacks + unsigned connected:1; // Are we connected yet? (also true for connectionless sockets) + unsigned writableHint:1; // Did the polling the socket show it to be writable? + unsigned closeSignaled:1; // Have we seen FD_CLOSE? (only used on Win32) + unsigned unused:13; + } _f; + CFLock_t _lock; + CFLock_t _writeLock; + CFSocketNativeHandle _socket; /* immutable */ + SInt32 _socketType; + SInt32 _errorCode; + CFDataRef _address; + CFDataRef _peerAddress; + SInt32 _socketSetCount; + CFRunLoopSourceRef _source0; // v0 RLS, messaged from SocketMgr + CFMutableArrayRef _runLoops; + CFSocketCallBack _callout; /* immutable */ + CFSocketContext _context; /* immutable */ + CFMutableArrayRef _dataQueue; // queues to pass data from SocketMgr thread + CFMutableArrayRef _addressQueue; + + struct timeval _readBufferTimeout; + CFMutableDataRef _readBuffer; + CFIndex _bytesToBuffer; /* is length of _readBuffer */ + CFIndex _bytesToBufferPos; /* where the next _CFSocketRead starts from */ + CFIndex _bytesToBufferReadPos; /* Where the buffer will next be read into (always after _bytesToBufferPos, but less than _bytesToBuffer) */ + Boolean _atEOF; + int _bufferedReadError; + + CFMutableDataRef _leftoverBytes; + + // + // If the timeout is set on the CFSocketRef but we never get select() timeout + // because we always have some network events so select never times out (e.g. while having a large download). + // We need to notify any waiting buffered read clients if there is data available without relying on select timing out. + struct timeval _readBufferTimeoutNotificationTime; + Boolean _hitTheTimeout; }; - //////////////////////////////////////////////////////////////////////////////// // typedefs diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index 20cfb75..5968d9d 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -24,6 +24,7 @@ #import #import + #include //////////////////////////////////////////////////////////////////////////////// #pragma mark C callback functions @@ -63,71 +64,6 @@ void _noticeProcessor(void* arg,const char* cString) { @implementation PGConnection (Callbacks) -//////////////////////////////////////////////////////////////////////////////// -#pragma mark private methods - socket connect/disconnect -//////////////////////////////////////////////////////////////////////////////// - --(void)_socketConnect:(PGConnectionState)state { - NSParameterAssert(_state==PGConnectionStateNone); - NSParameterAssert(state==PGConnectionStateConnect || state==PGConnectionStateReset || state==PGConnectionStateNone); - NSParameterAssert(_connection); - NSParameterAssert(_socket==nil && _runloopsource==nil); - - // create socket object - CFSocketContext context = {0, (__bridge void* )(self), NULL, NULL, NULL}; - _socket = CFSocketCreateWithNative(kCFAllocatorDefault,PQsocket(_connection),kCFSocketReadCallBack | kCFSocketWriteCallBack,&_socketCallback,&context); - -// _socket = CFSocketCreate(kCFAllocatorDefault, 0, 0, 0, kCFSocketReadCallBack | kCFSocketWriteCallBack,&_socketCallback,&context); - - NSParameterAssert(_socket && CFSocketIsValid(_socket)); - // let libpq do the socket closing - CFSocketSetSocketFlags(_socket,~kCFSocketCloseOnInvalidate & CFSocketGetSocketFlags(_socket)); -// CFSocketEnableCallBacks(_socket, kCFSocketDataCallBack | kCFSocketReadCallBack | kCFSocketWriteCallBack); - - - dispatch_source_t dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_current_queue() ); - - dispatch_source_set_timer(dsrc, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC / 2, NSEC_PER_SEC); - -// cf(_socket, F_SETFL, O_NONBLOCK); - // set state - [self setState:state]; - [self _updateStatus]; - - // add to run loop to begin polling - _runloopsource = CFSocketCreateRunLoopSource(NULL,_socket,128); - NSParameterAssert(_runloopsource && CFRunLoopSourceIsValid(_runloopsource)); - CFRunLoopAddSource( -// CFRunLoopGetMain(), - CFRunLoopGetCurrent(), - _runloopsource,(CFStringRef)kCFRunLoopCommonModes); -#if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %@ :::: Socket created ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); -#endif - - dispatch_semaphore_t semaphore_query_send = [[self masterPoolOperation] semaphore]; - [self wait_semaphore_read: semaphore_query_send ]; - - -// CFRunLoopRun();//(kCFRunLoopDefaultMode, 0.2 , NO); -#if defined DEBUG && defined DEBUG2 - NSLog(@" ------- %@ :: %@ :::: Socket Runloop Started ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); -#endif -} - --(void)_socketDisconnect { - if(_runloopsource) { - CFRunLoopSourceInvalidate(_runloopsource); - CFRelease(_runloopsource); - _runloopsource = nil; - } - if(_socket) { - CFSocketInvalidate(_socket); - CFRelease(_socket); - _socket = nil; - } -} - //////////////////////////////////////////////////////////////////////////////// #pragma mark private methods - socket callbacks //////////////////////////////////////////////////////////////////////////////// diff --git a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.h b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.h new file mode 100644 index 0000000..9f6f597 --- /dev/null +++ b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.h @@ -0,0 +1,15 @@ +// +// PGConnection+PGConnectionSocket.h +// postgresql-kit +// +// Created by Cotillard Sebastien on 02/08/2017. +// +// + +#import +#import + +@interface PGConnection (PGConnectionSocket) + +-(void)__CFSocket_instanciate; +@end diff --git a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m new file mode 100644 index 0000000..5101133 --- /dev/null +++ b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m @@ -0,0 +1,100 @@ +// +// PGConnection+PGConnectionSocket.m +// postgresql-kit + + // ************************************* + // + // Copyright 2017 - ?? Sebastien Cotillard - Genose.org + // 07/2017 Sebastien Cotillard + // https://github.com/genose + // + // ************************************* + // ADDING Pool concurrent operation + // ************************************* + // ADDING Fraking CFSocket non-blocking Main Thread respons and concurrent operation + // ************************************* + +#import "PGConnection+PGConnectionSocket.h" +extern void _socketCallback; +@implementation PGConnection (PGConnectionSocket) +-(CFSocketRef)__CFSocket_instanciate +{ + + // create socket object + CFSocketContext context = {0, (__bridge void* )(self), NULL, NULL, NULL}; + + _socket = CFSocketCreate(kCFAllocatorDefault, 0, 0, 0, kCFSocketReadCallBack | kCFSocketWriteCallBack, &_socketCallback,&context); + + PQsocket(_connection); + +// _socket = CFSocketCreateWithNative(kCFAllocatorDefault,PQsocket(_connection),kCFSocketReadCallBack | kCFSocketWriteCallBack,&_socketCallback,&context); + + +} + + + //////////////////////////////////////////////////////////////////////////////// +#pragma mark private methods - socket connect/disconnect + //////////////////////////////////////////////////////////////////////////////// + +-(void)_socketConnect:(PGConnectionState)state { + NSParameterAssert(_state==PGConnectionStateNone); + NSParameterAssert(state==PGConnectionStateConnect || state==PGConnectionStateReset || state==PGConnectionStateNone); + NSParameterAssert(_connection); + NSParameterAssert(_socket==nil && _runloopsource==nil); + + + [self __CFSocket_instanciate]; + + // _socket = CFSocketCreate(kCFAllocatorDefault, 0, 0, 0, kCFSocketReadCallBack | kCFSocketWriteCallBack,&_socketCallback,&context); + + NSParameterAssert(_socket && CFSocketIsValid(_socket)); + // let libpq do the socket closing + CFSocketSetSocketFlags(_socket,~kCFSocketCloseOnInvalidate & CFSocketGetSocketFlags(_socket)); + // CFSocketEnableCallBacks(_socket, kCFSocketDataCallBack | kCFSocketReadCallBack | kCFSocketWriteCallBack); + + + dispatch_source_t dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_current_queue() ); + + dispatch_source_set_timer(dsrc, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC / 2, NSEC_PER_SEC); + + // cf(_socket, F_SETFL, O_NONBLOCK); + // set state + [self setState:state]; + [self _updateStatus]; + + // add to run loop to begin polling + _runloopsource = CFSocketCreateRunLoopSource(NULL,_socket,128); + NSParameterAssert(_runloopsource && CFRunLoopSourceIsValid(_runloopsource)); + CFRunLoopAddSource( + // CFRunLoopGetMain(), + CFRunLoopGetCurrent(), + _runloopsource,(CFStringRef)kCFRunLoopCommonModes); +#if defined DEBUG && defined DEBUG2 + NSLog(@"%@ :: %@ :::: Socket created ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); +#endif + + dispatch_semaphore_t semaphore_query_send = [[self masterPoolOperation] semaphore]; + [self wait_semaphore_read: semaphore_query_send ]; + + + // CFRunLoopRun();//(kCFRunLoopDefaultMode, 0.2 , NO); +#if defined DEBUG && defined DEBUG2 + NSLog(@" ------- %@ :: %@ :::: Socket Runloop Started ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); +#endif +} + +-(void)_socketDisconnect { + if(_runloopsource) { + CFRunLoopSourceInvalidate(_runloopsource); + CFRelease(_runloopsource); + _runloopsource = nil; + } + if(_socket) { + CFSocketInvalidate(_socket); + CFRelease(_socket); + _socket = nil; + } +} + +@end From 9717e8062b7d9b762389f226ab844722d94e51ca Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Thu, 3 Aug 2017 18:23:58 +0200 Subject: [PATCH 07/21] More dispatch socket workaround --- src/Frameworks/PGClientKit/PGClientKit.h | 206 ++++--- .../PGClientKit/PGConnection+Callbacks.m | 38 +- .../PGClientKit/PGConnection+Execute.m | 572 ++++++++++-------- .../PGConnection+PGConnectionSocket.m | 334 ++++++++-- src/Frameworks/PGClientKit/PGConnection.h | 3 +- 5 files changed, 771 insertions(+), 382 deletions(-) diff --git a/src/Frameworks/PGClientKit/PGClientKit.h b/src/Frameworks/PGClientKit/PGClientKit.h index d7208a4..6949a68 100644 --- a/src/Frameworks/PGClientKit/PGClientKit.h +++ b/src/Frameworks/PGClientKit/PGClientKit.h @@ -13,6 +13,27 @@ // under the License. #import +#import + + +enum { // Legal level values for CFLog() + kCFLogLevelEmergency = 0, + kCFLogLevelAlert = 1, + kCFLogLevelCritical = 2, + kCFLogLevelError = 3, + kCFLogLevelWarning = 4, + kCFLogLevelNotice = 5, + kCFLogLevelInfo = 6, + kCFLogLevelDebug = 7, +}; + + +enum { + kCFSocketStateReady = 0, + kCFSocketStateInvalidating = 1, + kCFSocketStateInvalid = 2, + kCFSocketStateDeallocating = 3 +}; typedef struct __CFRuntimeBase { uintptr_t _cfisa; @@ -26,88 +47,121 @@ typedef struct __CFRuntimeBase { struct __shared_blob { __unsafe_unretained dispatch_source_t _rdsrc; __unsafe_unretained dispatch_source_t _wrsrc; - __unsafe_unretained CFRunLoopSourceRef _source; - __unsafe_unretained CFSocketNativeHandle _socket; + CFRunLoopSourceRef _source; + CFSocketNativeHandle _socket; uint8_t _closeFD; uint8_t _refCnt; }; -//struct __CFSocket { -// __unsafe_unretained CFRuntimeBase _base; -// __unsafe_unretained struct __shared_blob *_shared; // non-NULL when valid, NULL when invalid -// -// uint8_t _state:2; // mutable, not written safely -// uint8_t _isSaneFD:1; // immutable -// uint8_t _connOriented:1; // immutable -// uint8_t _wantConnect:1; // immutable -// uint8_t _wantWrite:1; // immutable -// uint8_t _wantReadType:2; // immutable -// -// uint8_t _error; -// -// uint8_t _rsuspended:1; -// uint8_t _wsuspended:1; -// uint8_t _readable:1; -// uint8_t _writeable:1; -// uint8_t _unused:4; -// -// uint8_t _reenableRead:1; -// uint8_t _readDisabled:1; -// uint8_t _reenableWrite:1; -// uint8_t _writeDisabled:1; -// uint8_t _connectDisabled:1; -// uint8_t _connected:1; -// uint8_t _leaveErrors:1; -// uint8_t _closeOnInvalidate:1; -// -// int32_t _runLoopCounter; -// -// CFDataRef _address; // immutable, once created -// CFDataRef _peerAddress; // immutable, once created -// CFSocketCallBack _callout; // immutable -// CFSocketContext _context; // immutable -//}; struct __CFSocket { CFRuntimeBase _base; - struct { - unsigned client:8; // flags set by client (reenable, CloseOnInvalidate) - unsigned disabled:8; // flags marking disabled callbacks - unsigned connected:1; // Are we connected yet? (also true for connectionless sockets) - unsigned writableHint:1; // Did the polling the socket show it to be writable? - unsigned closeSignaled:1; // Have we seen FD_CLOSE? (only used on Win32) - unsigned unused:13; - } _f; - CFLock_t _lock; - CFLock_t _writeLock; - CFSocketNativeHandle _socket; /* immutable */ - SInt32 _socketType; - SInt32 _errorCode; - CFDataRef _address; - CFDataRef _peerAddress; - SInt32 _socketSetCount; - CFRunLoopSourceRef _source0; // v0 RLS, messaged from SocketMgr - CFMutableArrayRef _runLoops; - CFSocketCallBack _callout; /* immutable */ - CFSocketContext _context; /* immutable */ - CFMutableArrayRef _dataQueue; // queues to pass data from SocketMgr thread - CFMutableArrayRef _addressQueue; - - struct timeval _readBufferTimeout; - CFMutableDataRef _readBuffer; - CFIndex _bytesToBuffer; /* is length of _readBuffer */ - CFIndex _bytesToBufferPos; /* where the next _CFSocketRead starts from */ - CFIndex _bytesToBufferReadPos; /* Where the buffer will next be read into (always after _bytesToBufferPos, but less than _bytesToBuffer) */ - Boolean _atEOF; - int _bufferedReadError; - - CFMutableDataRef _leftoverBytes; - - // - // If the timeout is set on the CFSocketRef but we never get select() timeout - // because we always have some network events so select never times out (e.g. while having a large download). - // We need to notify any waiting buffered read clients if there is data available without relying on select timing out. - struct timeval _readBufferTimeoutNotificationTime; - Boolean _hitTheTimeout; + struct __shared_blob *_shared; // non-NULL when valid, NULL when invalid + + uint8_t _state:2; // mutable, not written safely + uint8_t _isSaneFD:1; // immutable + uint8_t _connOriented:1; // immutable + uint8_t _wantConnect:1; // immutable + uint8_t _wantWrite:1; // immutable + uint8_t _wantReadType:2; // immutable + + uint8_t _error; + + uint8_t _rsuspended:1; + uint8_t _wsuspended:1; + uint8_t _readable:1; + uint8_t _writeable:1; + uint8_t _unused:4; + + uint8_t _reenableRead:1; + uint8_t _readDisabled:1; + uint8_t _reenableWrite:1; + uint8_t _writeDisabled:1; + uint8_t _connectDisabled:1; + uint8_t _connected:1; + uint8_t _leaveErrors:1; + uint8_t _closeOnInvalidate:1; + + int32_t _runLoopCounter; + + CFDataRef _address; // immutable, once created + CFDataRef _peerAddress; // immutable, once created + CFSocketCallBack _callout; // immutable + CFSocketContext _context; // immutable +} ; + +// +//struct __CFCF_CFSocket { +// CFRuntimeBase _base; +// struct { +// unsigned client:8; // flags set by client (reenable, CloseOnInvalidate) +// unsigned disabled:8; // flags marking disabled callbacks +// unsigned connected:1; // Are we connected yet? (also true for connectionless sockets) +// unsigned writableHint:1; // Did the polling the socket show it to be writable? +// unsigned closeSignaled:1; // Have we seen FD_CLOSE? (only used on Win32) +// unsigned unused:13; +// } _f; +// SInt32 _lock; +// SInt32 _writeLock; +// CFSocketNativeHandle _socket; /* immutable */ +// SInt32 _socketType; +// SInt32 _errorCode; +// CFDataRef _address; +// CFDataRef _peerAddress; +// SInt32 _socketSetCount; +// CFRunLoopSourceRef _source0; // v0 RLS, messaged from SocketMgr +// CFMutableArrayRef _runLoops; +// CFSocketCallBack _callout; /* immutable */ +// CFSocketContext _context; /* immutable */ +// CFMutableArrayRef _dataQueue; // queues to pass data from SocketMgr thread +// CFMutableArrayRef _addressQueue; +// +// struct timeval _readBufferTimeout; +// CFMutableDataRef _readBuffer; +// CFIndex _bytesToBuffer; /* is length of _readBuffer */ +// CFIndex _bytesToBufferPos; /* where the next _CFSocketRead starts from */ +// CFIndex _bytesToBufferReadPos; /* Where the buffer will next be read into (always after _bytesToBufferPos, but less than _bytesToBuffer) */ +// Boolean _atEOF; +// int _bufferedReadError; +// +// CFMutableDataRef _leftoverBytes; +// +// // +// // If the timeout is set on the CFSocketRef but we never get select() timeout +// // because we always have some network events so select never times out (e.g. while having a large download). +// // We need to notify any waiting buffered read clients if there is data available without relying on select timing out. +// struct timeval _readBufferTimeoutNotificationTime; +// Boolean _hitTheTimeout; +//}; +typedef struct __CFSocket * __CF_CFSocketRef; +typedef CFStringRef CFRunLoopMode ; +// CF_EXTENSIBLE_STRING_ENUM; +struct __CFRunLoop { + CFRuntimeBase _base; + pthread_mutex_t _lock; /* locked for accessing mode list */ + void * _wakeUpPort; // used for CFRunLoopWakeUp + Boolean _ignoreWakeUps; + volatile uint32_t *_stopped; + pthread_t _pthread; + uint32_t _winthread; + CFMutableSetRef _commonModes; + CFMutableSetRef _commonModeItems; + CFRunLoopMode * _currentMode; + CFMutableSetRef _modes; + struct _block_item *_blocks_head; + struct _block_item *_blocks_tail; + CFTypeRef _counterpart; +}; + +struct __CFRunLoopSource { + CFRuntimeBase _base; + uint32_t _bits; + pthread_mutex_t _lock; + CFIndex _order; /* immutable */ + CFMutableBagRef _runLoops; + union { + CFRunLoopSourceContext version0; /* immutable, except invalidation */ + CFRunLoopSourceContext1 version1; /* immutable, except invalidation */ + } _context; }; //////////////////////////////////////////////////////////////////////////////// diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index 5968d9d..7901ee1 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -99,7 +99,7 @@ -(void)_socketCallbackNotification { -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus { //:: NSParameterAssert(_callback!=nil); //:: void (^callback)(BOOL usedPassword,NSError* error) = (__bridge void (^)(BOOL,NSError* ))(_callback); - if( ![((PGConnectionOperation*)[self currentPoolOperation]) valid] ) + if( ![((PGConnectionOperation*)[self currentPoolOperation]) valid] || [[self currentPoolOperation] poolIdentifier] != 0) return; _callbackOperation = [((PGConnectionOperation*)[self currentPoolOperation]) getCallback]; @@ -119,27 +119,31 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus if(pqstatus==PGRES_POLLING_OK) { // set up notice processor, set success condition PQsetNoticeProcessor(_connection,_noticeProcessor,(__bridge void *)(self)); + if([[self currentPoolOperation] poolIdentifier] == 0){ + dispatch_semaphore_t ss = dispatch_semaphore_create(0); + + mach_port_t machTID = pthread_mach_thread_np(pthread_self()); + + const char * queued_name = [[NSString stringWithFormat:@"%s_%x_%@", "operation_dispacthed_threads", machTID, NSStringFromSelector(_cmd) ] cString]; + + NSLog(@" //// %s ", queued_name); + + dispatch_queue_t queue_inRun = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); + + + #if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) [NSThread detachNewThreadWithBlock:^ #else [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; - dispatch_semaphore_t ss = dispatch_semaphore_create(0); - - mach_port_t machTID = pthread_mach_thread_np(pthread_self()); - - const char * queued_name = [[NSString stringWithFormat:@"%s_%x", "operation_dispacthed_threads", machTID ] cString]; - - NSLog(@" //// %s ", queued_name); - - dispatch_queue_t queue = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); - - dispatch_barrier_async(queue,^ + + dispatch_barrier_sync(queue_inRun,^ #endif { callback(usedPassword ? YES : NO,nil); - dispatch_semaphore_signal(ss); +// dispatch_semaphore_signal(ss); } #if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) @@ -150,9 +154,11 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus #endif ; // dispatch_semaphore_wait(ss,DISPATCH_TIME_FOREVER); - [self wait_semaphore_read:ss]; +// [self wait_semaphore_read:ss]; + [self wait_semaphore_read: ss withQueue:queue_inRun]; // [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; + } // dispatch_destroy(queue); } else if(needsPassword) { // error callback - connection not made, needs password @@ -202,8 +208,8 @@ -(void)_socketCallbackConnect { PGConnectionOperation* currentpoolOpe = [self currentPoolOperation]; if(_connection==nil -// || ![[self currentPoolOperation] valid] - || ( [currentpoolOpe poolIdentifier]) !=0 + || ![[self currentPoolOperation] valid] +// || ( [currentpoolOpe poolIdentifier]) !=0 ) { // || (_callback==nil) // && _callbackOperation == nil) return; } diff --git a/src/Frameworks/PGClientKit/PGConnection+Execute.m b/src/Frameworks/PGClientKit/PGConnection+Execute.m index a650a94..440793a 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Execute.m +++ b/src/Frameworks/PGClientKit/PGConnection+Execute.m @@ -187,271 +187,349 @@ -(void)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) cal // } + // dispatch_queue_t queue_inRun = ( ( dispatch_get_current_queue() == dispatch_get_main_queue() )? dispatch_get_main_queue() : dispatch_get_current_queue() ); + mach_port_t machTID = pthread_mach_thread_np(pthread_self()); + + const char * queued_name = [[NSString stringWithFormat:@"%s_%x", "query_operation_dispacthed_threads", machTID ] cString]; + + NSLog(@" //// %s ", queued_name); + + dispatch_queue_t queue_inRun = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); + #if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) [NSThread detachNewThreadWithBlock:^ #else -// dispatch_queue_t queue_inRun = ( ( dispatch_get_current_queue() == dispatch_get_main_queue() )? dispatch_get_main_queue() : dispatch_get_current_queue() ); - mach_port_t machTID = pthread_mach_thread_np(pthread_self()); - const char * queued_name = [[NSString stringWithFormat:@"%s_%x", "query_operation_dispacthed_threads", machTID ] cString]; - - NSLog(@" //// %s ", queued_name); - - dispatch_queue_t queue_inRun = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); - - dispatch_barrier_sync(queue_inRun,^ + dispatch_barrier_sync(queue_inRun,^ #endif - - { - // [self performSelectorOnMainThread:@selector(_waitingPoolOperationForResult) withObject:self waitUntilDone:YES ]; - - - NSParameterAssert([query isKindOfClass:[NSString class]] || [query isKindOfClass:[PGQuery class]]); - NSParameterAssert(callback); - NSString* query2 = nil; - NSError* error = nil; - if([query isKindOfClass:[NSString class]]) { - query2 = query; - } else { - query2 = [(PGQuery* )query quoteForConnection:self error:&error]; - } - if(error) { + + { + // [self performSelectorOnMainThread:@selector(_waitingPoolOperationForResult) withObject:self waitUntilDone:YES ]; + + + NSParameterAssert([query isKindOfClass:[NSString class]] || [query isKindOfClass:[PGQuery class]]); + NSParameterAssert(callback); + NSString* query2 = nil; + NSError* error = nil; + if([query isKindOfClass:[NSString class]]) { + query2 = query; + } else { + query2 = [(PGQuery* )query quoteForConnection:self error:&error]; + } + if(error) { #if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %@ - query ERROR - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); + NSLog(@"%@ :: %@ - query ERROR - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); #endif - callback(nil,error); - } else if(query2==nil) { - callback(nil,[self raiseError:nil code:PGClientErrorExecute reason:@"Query is nil"]); - } else { + callback(nil,error); + } else if(query2==nil) { + callback(nil,[self raiseError:nil code:PGClientErrorExecute reason:@"Query is nil"]); + } else { #if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %@ - query - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); + NSLog(@"%@ :: %@ - query - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); #endif - void (^callback_recall)(PGResult* result,NSError* error) = ^(PGResult* result_recall ,NSError* error_recall) - { - NSLog(@" .... semaphore callback..... "); - callback(result_recall , error_recall); - NSLog(@" .... semaphore pass ..... "); - dispatch_semaphore_signal( [[self currentPoolOperation] semaphore] ); - NSLog(@" .... semaphore signal end ..... "); - - }; - // dispatch_semaphore_signal(semaphore_query_send); - [self _execute:query2 values:nil whenDone: callback_recall]; - - } - } - + void (^callback_recall)(PGResult* result,NSError* error) = ^(PGResult* result_recall ,NSError* error_recall) + { + NSLog(@" .... semaphore callback..... "); + callback(result_recall , error_recall); + NSLog(@" .... semaphore pass ..... "); + dispatch_semaphore_signal( [[self currentPoolOperation] semaphore] ); + NSLog(@" .... semaphore signal end ..... "); + + }; + // dispatch_semaphore_signal(semaphore_query_send); + [self _execute:query2 values:nil whenDone: callback_recall]; + + } + } + #if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) - ] + ] #else - - ) + + ) #endif - ; - - // [self performSelector:@selector(_waitingPoolOperationForResult) withObject:self ]; - // [self performSelector:@selector(_waitingPoolOperationForResultMaster) withObject:self ]; - - _stateOperation = PGOperationStateBusy; - [NSThread sleepForTimeInterval:.2]; - NSLog(@"Is main queue? : %d", dispatch_get_current_queue() == dispatch_get_main_queue()); - dispatch_semaphore_t semaphore_query_send = [[self currentPoolOperation] semaphore]; - [self wait_semaphore_read: semaphore_query_send ]; - NSLog(@"I will see this, after dispatch_semaphore_signal is called"); + ; + + // [self performSelector:@selector(_waitingPoolOperationForResult) withObject:self ]; + // [self performSelector:@selector(_waitingPoolOperationForResultMaster) withObject:self ]; + + _stateOperation = PGOperationStateBusy; + [NSThread sleepForTimeInterval:.2]; + NSLog(@"Is main queue? : %d", dispatch_get_current_queue() == dispatch_get_main_queue()); + dispatch_semaphore_t semaphore_query_send = [[self currentPoolOperation] semaphore]; + [self wait_semaphore_read: semaphore_query_send withQueue:queue_inRun]; + + NSLog(@"I will see this, after dispatch_semaphore_signal is called"); } --(void)wait_semaphore_read:(dispatch_semaphore_t) sem -{ - mach_port_t machTID = pthread_mach_thread_np(pthread_self()); - const char * queued_name = [[NSString stringWithFormat:@"%@_%x :: %s :: %s :: %@ ", NSStringFromSelector(_cmd), machTID, dispatch_queue_get_label(dispatch_get_current_queue()), dispatch_queue_get_label(dispatch_get_main_queue()), sem ] cString]; - - NSLog(@" //// %s ", queued_name); - - long diispacthed = YES; - - NSTimeInterval resolutionTimeOut = 0.05; - NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; - bool isRunningThreadMain = YES; - bool isRunningThread = YES; - while( diispacthed && _runloopsource ) - { - - - diispacthed = dispatch_semaphore_wait(sem,DISPATCH_TIME_NOW); - dispatch_queue_t qq_qq = dispatch_get_current_queue(); - - id shared_info = (__bridge id)(_socket); - CFSocketCallBack shared_info_shared = (_socket->_callout); - const char * class_named = object_getClassName(shared_info); - - CFSocketNativeHandle sock = CFSocketGetNative(_socket); - - struct __shared_blob *shared_dd = malloc(sizeof(struct __shared_blob)); +-(void)wait_semaphore_read:(dispatch_semaphore_t) sem { + [self wait_semaphore_read:sem withQueue:nil]; + } +-(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_t)qq_in { + + mach_port_t machTID = pthread_mach_thread_np(pthread_self()); + const char * queued_name = [[NSString stringWithFormat:@"%@_%x :: %s :: %s :: %@ ", NSStringFromSelector(_cmd), machTID, dispatch_queue_get_label(dispatch_get_current_queue()), dispatch_queue_get_label(dispatch_get_main_queue()), sem ] cString]; - NSLog(@"%s", __CFFSocketCopyDescription(_socket)); + NSLog(@" //// Start :: %s ", queued_name); -// shared_dd->_rdsrc = (_socket->_shared)->_rdsrc; -// shared_dd->_wrsrc = (_socket->_shared)->_wrsrc; -// shared_dd->_source = (_socket->_shared)->_source; -// shared_dd->_socket = (_socket->_shared)->_socket; -// shared_dd->_closeFD = (_socket->_shared)->_closeFD ; -// shared_dd->_refCnt = (_socket->_shared)->_refCnt; -// objc_mem(&shared_dd, *(_socket->_shared) , sizeof(struct __shared_blob)); +// dispatch_barrier_async(dispatch_get_current_queue(), ^{ - unsigned int outCount, i; - objc_property_t *objcProperties = class_copyPropertyList([shared_info class], &outCount); - for (i = 0; i < outCount; i++) { - objc_property_t property = objcProperties[i]; - const char *propName = property_getName(property); - if(propName) { -// const char * propType = getPropertyType(property); - NSString * propertyName = [NSString stringWithUTF8String:propName]; + NSLog(@" //// Start **** :: %s ", queued_name); + long diispacthed = YES; + + NSTimeInterval resolutionTimeOut = 0.05; + NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; + bool isRunningThreadMain = YES; + bool isRunningThread = YES; + + + +// dispatch_async(((qq_in)?qq_in : dispatch_get_main_queue()), ^{ +// +// bool isRunningThreadMain = YES; +// bool isRunningThread = YES; +// +// CFRunLoopSourceSignal(_runloopsource); +// CFRunLoopWakeUp(CFRunLoopGetMain()); +// +// +// isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; +// if(!isRunningThreadMain) +// { +// [NSThread sleepForTimeInterval:.01];; +// } +// +// isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; +// if(!isRunningThreadMain) +// { +// [NSThread sleepForTimeInterval:.01];; +// } +// +// CFRunLoopSourceSignal(_runloopsource); +// CFRunLoopWakeUp(CFRunLoopGetCurrent()); +// +// +// isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; +// if(!isRunningThread) +// { +// [NSThread sleepForTimeInterval:.01];; +// } +// +// isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; +// if(!isRunningThread) +// { +// [NSThread sleepForTimeInterval:.01];; +// } +// +// }); + + +// if([[self currentPoolOperation] poolIdentifier] == 0) + while( diispacthed && _runloopsource ) + { + + + + diispacthed = dispatch_semaphore_wait(sem,DISPATCH_TIME_NOW); + dispatch_queue_t qq_qq = dispatch_get_current_queue(); + +// [self performSelector:@selector(dispathCall) withObject:nil afterDelay:.1 inModes:[NSArray arrayWithObjects: kCFRunLoopCommonModes, kCFRunLoopDefaultMode, nil]]; + if([[self currentPoolOperation] poolIdentifier] == 0) + { + [self performSelector:@selector(dispathCall) withObject:nil]; + }else{ + [NSThread sleepForTimeInterval:.01]; + [self performSelector:@selector(dispathCall) withObject:nil]; + } + + id shared_info = (__bridge id)(_socket); + CFSocketCallBack shared_info_shared = (_socket->_callout); + const char * class_named = object_getClassName(shared_info); + + CFSocketNativeHandle sock = CFSocketGetNative(_socket); + + struct __shared_blob *shared_dd = malloc(sizeof(struct __shared_blob)); + + // NSLog(@"%s", __CFFSocketCopyDescription(_socket)); + + // shared_dd->_rdsrc = (_socket->_shared)->_rdsrc; + // shared_dd->_wrsrc = (_socket->_shared)->_wrsrc; + // shared_dd->_source = (_socket->_shared)->_source; + // shared_dd->_socket = (_socket->_shared)->_socket; + // shared_dd->_closeFD = (_socket->_shared)->_closeFD ; + // shared_dd->_refCnt = (_socket->_shared)->_refCnt; + + // objc_mem(&shared_dd, *(_socket->_shared) , sizeof(struct __shared_blob)); + + unsigned int outCount, i; + objc_property_t *objcProperties = class_copyPropertyList([shared_info class], &outCount); + for (i = 0; i < outCount; i++) { + objc_property_t property = objcProperties[i]; + const char *propName = property_getName(property); + if(propName) { + // const char * propType = getPropertyType(property); + NSString * propertyName = [NSString stringWithUTF8String:propName]; + + } + } + + // [((NSObject*)shared_info) shared]; + id sockk = (__bridge id)((_socket)->_shared); + + // typedef struct __CFSocket sockt; + // + // dispatch_object_t disp_obj = (dispatch_object_t) ((shared_info*)->_shared->_rdsrc); + // dispatch_resume( ((dispatch_object_t) disp_obj) );; + if( diispacthed && !isRunningThreadMain && !isRunningThreadMain + && [[self currentPoolOperation] valid] + ) + [NSThread sleepForTimeInterval:.01]; + + if( diispacthed && !isRunningThreadMain && !isRunningThreadMain + && [[self currentPoolOperation] valid] && [self connectionPoolOperationCount] > 1 + && !PQisBusy(_connection) ) + break; } - } - -// [((NSObject*)shared_info) shared]; - id sockk = (__bridge id)((_socket)->_shared); - -// typedef struct __CFSocket sockt; -// -// dispatch_object_t disp_obj = (dispatch_object_t) ((shared_info*)->_shared->_rdsrc); -// dispatch_resume( ((dispatch_object_t) disp_obj) );; - if( diispacthed && !isRunningThreadMain && !isRunningThreadMain - && [[self currentPoolOperation] valid] - ) - [NSThread sleepForTimeInterval:.01]; - - CFRunLoopSourceSignal(_runloopsource); - CFRunLoopWakeUp(CFRunLoopGetMain()); - - - isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; - if(!isRunningThreadMain) - { - [NSThread sleepForTimeInterval:.01];; - } - - isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; - if(!isRunningThreadMain) - { - [NSThread sleepForTimeInterval:.01];; - } - - CFRunLoopSourceSignal(_runloopsource); - CFRunLoopWakeUp(CFRunLoopGetCurrent()); - - - isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; - if(!isRunningThread) - { - [NSThread sleepForTimeInterval:.01];; - } - - isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; - if(!isRunningThread) - { - [NSThread sleepForTimeInterval:.01];; - } - - if( diispacthed && !isRunningThreadMain && !isRunningThreadMain - && [[self currentPoolOperation] valid] && [self connectionPoolOperationCount] > 1 - && !PQisBusy(_connection) ) - break; - - } - // [[NSThread currentThread] cancel]; -} - --(PGResult* )execute:(id)query error:(NSError** )error { - dispatch_semaphore_t s = dispatch_semaphore_create(0); - __block PGResult* result = nil; - [self execute:query whenDone:^(PGResult* r, NSError* e) { - if(error) { - (*error) = e; - } - result = r; - dispatch_semaphore_signal(s); - }]; - dispatch_semaphore_wait(s,DISPATCH_TIME_FOREVER); - return result; -} - --(void)_queue:(PGTransaction* )transaction index:(NSUInteger)i lastResult:(PGResult* )result lastError:(NSError* )error whenQueryDone:(void(^)(PGResult* result,BOOL isLastQuery,NSError* error)) callback { - if(error) { - // rollback - if([transaction transactional]) { - NSString* rollbackTransaction = [(PGTransaction* )transaction quoteRollbackTransactionForConnection:self]; - NSParameterAssert(rollbackTransaction); - [self execute:rollbackTransaction whenDone:^(PGResult* result2,NSError* error2) { - callback(nil,YES,error); - }]; - } else { - callback(nil,YES,error); - } - } else if(i==[transaction count]) { - // commit - if([transaction transactional]) { - NSString* commitTransaction = [(PGTransaction* )transaction quoteCommitTransactionForConnection:self]; - NSParameterAssert(commitTransaction); - [self execute:commitTransaction whenDone:^(PGResult* result2, NSError* error2) { - callback(result,YES,error); - }]; - } else { - callback(result,YES,error); - } - } else { - // execute a single query - [self execute:[transaction queryAtIndex:i] whenDone:^(PGResult* result,NSError* error) { - if(i < [transaction count]) { - [self _queue:transaction index:(i+1) lastResult:result lastError:error whenQueryDone:callback]; - } - }]; - } -} - --(void)queue:(PGTransaction* )transaction whenQueryDone:(void(^)(PGResult* result,BOOL isLastQuery,NSError* error)) callback { - NSParameterAssert(transaction && [transaction isKindOfClass:[PGTransaction class]]); - - // where there are no transactions to execute, raise error immediately - if([transaction count]==0) { - callback(nil,YES,[self raiseError:nil code:PGClientErrorExecute reason:@"No transactions to execute"]); - return; - } - - // check for connection status - if(_connection==nil || [self state] != PGConnectionStateNone) { - callback(nil,YES,[self raiseError:nil code:PGClientErrorState]); - return; - } - - // check for transaction status - PGTransactionStatusType tstatus = PQtransactionStatus(_connection); - if([transaction transactional] && tstatus != PQTRANS_IDLE) { - callback(nil,YES,[self raiseError:nil code:PGClientErrorState reason:@"Already in a transaction"]); - return; - } - - if([transaction transactional]==NO) { - // queue zeroth query - [self _queue:transaction index:0 lastResult:nil lastError:nil whenQueryDone:callback]; - } else { - // queue up a start transaction, which triggers the first query - NSString* beginTransaction = [(PGTransaction* )transaction quoteBeginTransactionForConnection:self]; - NSParameterAssert(beginTransaction); - [self execute:beginTransaction whenDone:^(PGResult* result, NSError* error) { - // if the BEGIN transaction didn't work, then callback - if(error) { - callback(nil,YES,error); - } else { - // else queue up zeroth query - [self _queue:transaction index:0 lastResult:result lastError:error whenQueryDone:callback]; - } - }]; + + NSLog(@" //// Clean **** :: %s ", queued_name); +// }); + // [[NSThread currentThread] cancel]; + NSLog(@" //// END :: %s ", queued_name); } -} - -@end - - + + -(PGResult* )execute:(id)query error:(NSError** )error { + dispatch_semaphore_t s = dispatch_semaphore_create(0); + __block PGResult* result = nil; + [self execute:query whenDone:^(PGResult* r, NSError* e) { + if(error) { + (*error) = e; + } + result = r; + dispatch_semaphore_signal(s); + }]; + dispatch_semaphore_wait(s,DISPATCH_TIME_FOREVER); + return result; + } + -(void)dispathCall + { +// dispatch_async(dispatch_get_current_queue(), ^{ + NSTimeInterval resolutionTimeOut = 0.05; + NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; + bool isRunningThreadMain = YES; + bool isRunningThread = YES; + + while(YES || isRunningThreadMain || isRunningThread){ + CFRunLoopSourceSignal(_runloopsource); + CFRunLoopWakeUp(CFRunLoopGetMain()); + + + isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; + if(!isRunningThreadMain) + { + [NSThread sleepForTimeInterval:.01];; + } + + isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; + if(!isRunningThreadMain) + { + [NSThread sleepForTimeInterval:.01];; + } + + CFRunLoopSourceSignal(_runloopsource); + CFRunLoopWakeUp(CFRunLoopGetCurrent()); + + + isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; + if(!isRunningThread) + { + [NSThread sleepForTimeInterval:.01];; + } + + isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; + if(!isRunningThread) + { + [NSThread sleepForTimeInterval:.01];; + } + } +// }); + + } + -(void)_queue:(PGTransaction* )transaction index:(NSUInteger)i lastResult:(PGResult* )result lastError:(NSError* )error whenQueryDone:(void(^)(PGResult* result,BOOL isLastQuery,NSError* error)) callback { + if(error) { + // rollback + if([transaction transactional]) { + NSString* rollbackTransaction = [(PGTransaction* )transaction quoteRollbackTransactionForConnection:self]; + NSParameterAssert(rollbackTransaction); + [self execute:rollbackTransaction whenDone:^(PGResult* result2,NSError* error2) { + callback(nil,YES,error); + }]; + } else { + callback(nil,YES,error); + } + } else if(i==[transaction count]) { + // commit + if([transaction transactional]) { + NSString* commitTransaction = [(PGTransaction* )transaction quoteCommitTransactionForConnection:self]; + NSParameterAssert(commitTransaction); + [self execute:commitTransaction whenDone:^(PGResult* result2, NSError* error2) { + callback(result,YES,error); + }]; + } else { + callback(result,YES,error); + } + } else { + // execute a single query + [self execute:[transaction queryAtIndex:i] whenDone:^(PGResult* result,NSError* error) { + if(i < [transaction count]) { + [self _queue:transaction index:(i+1) lastResult:result lastError:error whenQueryDone:callback]; + } + }]; + } + } + + -(void)queue:(PGTransaction* )transaction whenQueryDone:(void(^)(PGResult* result,BOOL isLastQuery,NSError* error)) callback { + NSParameterAssert(transaction && [transaction isKindOfClass:[PGTransaction class]]); + + // where there are no transactions to execute, raise error immediately + if([transaction count]==0) { + callback(nil,YES,[self raiseError:nil code:PGClientErrorExecute reason:@"No transactions to execute"]); + return; + } + + // check for connection status + if(_connection==nil || [self state] != PGConnectionStateNone) { + callback(nil,YES,[self raiseError:nil code:PGClientErrorState]); + return; + } + + // check for transaction status + PGTransactionStatusType tstatus = PQtransactionStatus(_connection); + if([transaction transactional] && tstatus != PQTRANS_IDLE) { + callback(nil,YES,[self raiseError:nil code:PGClientErrorState reason:@"Already in a transaction"]); + return; + } + + if([transaction transactional]==NO) { + // queue zeroth query + [self _queue:transaction index:0 lastResult:nil lastError:nil whenQueryDone:callback]; + } else { + // queue up a start transaction, which triggers the first query + NSString* beginTransaction = [(PGTransaction* )transaction quoteBeginTransactionForConnection:self]; + NSParameterAssert(beginTransaction); + [self execute:beginTransaction whenDone:^(PGResult* result, NSError* error) { + // if the BEGIN transaction didn't work, then callback + if(error) { + callback(nil,YES,error); + } else { + // else queue up zeroth query + [self _queue:transaction index:0 lastResult:result lastError:error whenQueryDone:callback]; + } + }]; + } + } + + @end + + diff --git a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m index 5101133..88acd50 100644 --- a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m +++ b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m @@ -2,83 +2,333 @@ // PGConnection+PGConnectionSocket.m // postgresql-kit - // ************************************* - // - // Copyright 2017 - ?? Sebastien Cotillard - Genose.org - // 07/2017 Sebastien Cotillard - // https://github.com/genose - // - // ************************************* - // ADDING Pool concurrent operation - // ************************************* - // ADDING Fraking CFSocket non-blocking Main Thread respons and concurrent operation - // ************************************* +// ************************************* +// +// Copyright 2017 - ?? Sebastien Cotillard - Genose.org +// 07/2017 Sebastien Cotillard +// https://github.com/genose +// +// ************************************* +// ADDING Pool concurrent operation +// ************************************* +// ADDING Fraking CFSocket non-blocking Main Thread respons and concurrent operation +// ************************************* #import "PGConnection+PGConnectionSocket.h" + + +#include + +//#include "" +#include +#include +#include +#include +#include +#include +#include + + +extern void _CFRunLoopSourceWakeUpRunLoops(CFRunLoopSourceRef rls); +extern void __CFRunLoopSourceWakeUpLoop(const void*,void*); + extern void _socketCallback; -@implementation PGConnection (PGConnectionSocket) --(CFSocketRef)__CFSocket_instanciate -{ +static CFMutableArrayRef __CFCF_CFAllSockets = NULL; - // create socket object - CFSocketContext context = {0, (__bridge void* )(self), NULL, NULL, NULL}; +#define INVALID_SOCKET (CFSocketNativeHandle)(-1) +#define MAX_SOCKADDR_LEN 256 +#define __CFCF_CFSockQueue() dispatch_get_current_queue() - _socket = CFSocketCreate(kCFAllocatorDefault, 0, 0, 0, kCFSocketReadCallBack | kCFSocketWriteCallBack, &_socketCallback,&context); +@implementation PGConnection (PGConnectionSocket) +void _CFRunLoopSourceWakeUpRunLoops(CFRunLoopSourceRef rls) { + return; + // CFBagRef loops = NULL; + // __CFRunLoopSourceLock(rls); + // if (__CFIsValid(rls) && NULL != rls->_runLoops) { + // loops = CFBagCreateCopy(kCFAllocatorSystemDefault, rls->_runLoops); + // } + // __CFRunLoopSourceUnlock(rls); + // if (loops) { + // CFBagApplyFunction(loops, __CFRunLoopSourceWakeUpLoop, NULL); + // CFRelease(loops); + // } +} +CFSocketRef _CFCF_CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHandle ufd, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) { +#if defined(CHECK_FOR_FORK_RET) + CHECK_FOR_FORK_RET(NULL); +#endif + if(__CFCF_CFAllSockets == nil) + __CFCF_CFAllSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + CFSocketGetTypeID(); // cause initialization if necessary + + struct stat statbuf; + int ret = fstat(ufd, &statbuf); + if (ret < 0) ufd = INVALID_SOCKET; + + Boolean sane = false; + if (INVALID_SOCKET != ufd) { + uint32_t type = (statbuf.st_mode & S_IFMT); + sane = (S_IFSOCK == type) || (S_IFIFO == type) || (S_IFCHR == type); + if (0 && !sane) { + CFLog(kCFLogLevelWarning, CFSTR("*** _CFCF_CFSocketCreateWithNative(): creating CFSocket with silly fd type (%07o) -- may or may not work"), type); + } + } + + if (INVALID_SOCKET != ufd) { + Boolean canHandle = false; + int tmp_kq = kqueue(); + if (0 <= tmp_kq) { + struct kevent ev[2]; + EV_SET(&ev[0], ufd, EVFILT_READ, EV_ADD, 0, 0, 0); + EV_SET(&ev[1], ufd, EVFILT_WRITE, EV_ADD, 0, 0, 0); + int ret = kevent(tmp_kq, ev, 2, NULL, 0, NULL); + canHandle = (0 <= ret); // if kevent(ADD) succeeds, can handle + close(tmp_kq); + } + if (0 && !canHandle) { + CFLog(kCFLogLevelWarning, CFSTR("*** _CFCF_CFSocketCreateWithNative(): creating CFSocket with unsupported fd type -- may or may not work")); + } + } + + if (INVALID_SOCKET == ufd) { + // Historically, bad ufd was allowed, but gave an uncached and already-invalid CFSocketRef + SInt32 size = sizeof(struct __CFSocket) - sizeof(CFRuntimeBase); + CFSocketRef memory = (CFSocketRef)_CFRuntimeCreateInstance(allocator, CFSocketGetTypeID(), size, NULL); + if (NULL == memory) { + return NULL; + } + memory->_callout = callout; + memory->_state = kCFSocketStateInvalid; + return memory; + } + + __block CFSocketRef sock = NULL; + dispatch_sync(__CFCF_CFSockQueue(), ^{ + @try { + + for (CFIndex idx = 0, cnt = CFArrayGetCount(__CFCF_CFAllSockets); idx < cnt; idx++) { + CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFCF_CFAllSockets, idx); + if (s->_shared->_socket == ufd) { + CFRetain(s); + sock = s; + return; + } + } + + SInt32 size = sizeof(struct __CFSocket) - sizeof(CFRuntimeBase); + __CF_CFSocketRef memory = malloc(sizeof(__CF_CFSocketRef)); + CFSocketRef cfcf_memory = (CFSocketRef)_CFRuntimeCreateInstance(allocator, CFSocketGetTypeID(), size, NULL); + if (NULL == memory) { + return; + } + + int socketType = 0; + if (INVALID_SOCKET != ufd) { + socklen_t typeSize = sizeof(socketType); + int ret = getsockopt(ufd, SOL_SOCKET, SO_TYPE, (void *)&socketType, (socklen_t *)&typeSize); + if (ret < 0) socketType = 0; + } + + ((CFSocketRef)cfcf_memory)->_error = 0; + + memory->_rsuspended = true; + memory->_wsuspended = true; + memory->_readable = false; + memory->_writeable = false; + + memory->_isSaneFD = sane ? 1 : 0; + memory->_wantReadType = (callBackTypes & 0x3); + memory->_reenableRead = memory->_wantReadType ? true : false; + memory->_readDisabled = false; + memory->_wantWrite = (callBackTypes & kCFSocketWriteCallBack) ? true : false; + memory->_reenableWrite = false; + memory->_writeDisabled = false; + memory->_wantConnect = (callBackTypes & kCFSocketConnectCallBack) ? true : false; + memory->_connectDisabled = false; + memory->_leaveErrors = false; + memory->_closeOnInvalidate = true; + memory->_connOriented = (SOCK_STREAM == socketType || SOCK_SEQPACKET == socketType); + memory->_connected = (memory->_wantReadType == kCFSocketAcceptCallBack || !memory->_connOriented) ? true : false; + + memory->_error = 0; + memory->_runLoopCounter = 0; + memory->_address = NULL; + memory->_peerAddress = NULL; + memory->_context.info = NULL; + memory->_context.retain = NULL; + memory->_context.release = NULL; + memory->_context.copyDescription = NULL; + memory->_callout = callout; + if (NULL != context) { + objc_memmove_collectable(&memory->_context, context, sizeof(CFSocketContext)); + memory->_context.info = context->retain ? (void *)context->retain(context->info) : context->info; + } + + struct __shared_blob *shared = malloc(sizeof(struct __shared_blob)); + shared->_rdsrc = NULL; + shared->_wrsrc = NULL; + shared->_source = NULL; + shared->_socket = ufd; + shared->_closeFD = true; // copy of _closeOnInvalidate + shared->_refCnt = 1; // one for the CFSocket + memory->_shared = shared; + + if (memory->_wantReadType) { + dispatch_source_t dsrc = NULL; + if (sane != nil) { + dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, ufd, 0, __CFCF_CFSockQueue()); + } else { + dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, __CFCF_CFSockQueue()); + dispatch_source_set_timer(dsrc, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC / 2, NSEC_PER_SEC); + } + dispatch_block_t event_block = ^{ + memory->_readable = true; + if (!memory->_rsuspended) { + dispatch_suspend(dsrc); + memory->_rsuspended = true; + } + if (shared->_source) { + CFRunLoopSourceSignal(shared->_source); + _CFRunLoopSourceWakeUpRunLoops(shared->_source); + } + }; + dispatch_block_t cancel_block = ^{ + shared->_rdsrc = NULL; + shared->_refCnt--; + if (0 == shared->_refCnt) { + if (shared->_closeFD) close(shared->_socket); + free(shared); + } + // dispatch_release(dsrc); + }; + dispatch_source_set_event_handler(dsrc, event_block); + dispatch_source_set_cancel_handler(dsrc, cancel_block); + shared->_rdsrc = dsrc; + } + if (memory->_wantWrite || memory->_wantConnect) { + dispatch_source_t dsrc = NULL; + if (sane != nil) { + dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, ufd, 0, __CFCF_CFSockQueue()); + } else { + dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, __CFCF_CFSockQueue()); + dispatch_source_set_timer(dsrc, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC / 2, NSEC_PER_SEC); + } + dispatch_block_t event_block = ^{ + memory->_writeable = true; + if (!memory->_wsuspended) { + dispatch_suspend(dsrc); + memory->_wsuspended = true; + } + if (shared->_source) { + CFRunLoopSourceSignal(shared->_source); + _CFRunLoopSourceWakeUpRunLoops(shared->_source); + } + }; + dispatch_block_t cancel_block = ^{ + shared->_wrsrc = NULL; + shared->_refCnt--; + if (0 == shared->_refCnt) { + if (shared->_closeFD) close(shared->_socket); + free(shared); + } + // dispatch_release(dsrc); + }; + dispatch_source_set_event_handler(dsrc, event_block); + dispatch_source_set_cancel_handler(dsrc, cancel_block); + shared->_wrsrc = dsrc; + } + + if (shared->_rdsrc) { + shared->_refCnt++; + } + if (shared->_wrsrc) { + shared->_refCnt++; + } + + memory->_state = kCFSocketStateReady; + CFIndex indexInPool = CFArrayGetCount(__CFCF_CFAllSockets); + + CFArrayAppendValue(__CFCF_CFAllSockets, cfcf_memory); + sock = memory; + + } @catch (NSException *exception) { + NSLog(@" :::::: Error :: %@ ", exception ); + } @finally { + + } + }); + CFLog(5, CFSTR("_CFCF_CFSocketCreateWithNative(): created socket %p with callbacks 0x%x"), sock, callBackTypes); + return sock; +} - PQsocket(_connection); -// _socket = CFSocketCreateWithNative(kCFAllocatorDefault,PQsocket(_connection),kCFSocketReadCallBack | kCFSocketWriteCallBack,&_socketCallback,&context); +-(CFSocketRef)__CFSocket_instanciate +{ + + // create socket object + CFSocketContext context = {0, (__bridge void* )(self), NULL, NULL, NULL}; + + // _socket = CFSocketCreate(kCFAllocatorDefault, 0, 0, 0, kCFSocketReadCallBack | kCFSocketWriteCallBack, &_socketCallback,&context); + + // PQsocket(_connection); + + _socket = CFSocketCreateWithNative(kCFAllocatorDefault,PQsocket(_connection),kCFSocketReadCallBack | kCFSocketWriteCallBack,&_socketCallback,&context); + + } - //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// #pragma mark private methods - socket connect/disconnect - //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// -(void)_socketConnect:(PGConnectionState)state { NSParameterAssert(_state==PGConnectionStateNone); NSParameterAssert(state==PGConnectionStateConnect || state==PGConnectionStateReset || state==PGConnectionStateNone); NSParameterAssert(_connection); NSParameterAssert(_socket==nil && _runloopsource==nil); - - + + [self __CFSocket_instanciate]; - - // _socket = CFSocketCreate(kCFAllocatorDefault, 0, 0, 0, kCFSocketReadCallBack | kCFSocketWriteCallBack,&_socketCallback,&context); - - NSParameterAssert(_socket && CFSocketIsValid(_socket)); - // let libpq do the socket closing + + // _socket = CFSocketCreate(kCFAllocatorDefault, 0, 0, 0, kCFSocketReadCallBack | kCFSocketWriteCallBack,&_socketCallback,&context); + +// NSParameterAssert(_socket && CFSocketIsValid(_socket)); + // let libpq do the socket closing CFSocketSetSocketFlags(_socket,~kCFSocketCloseOnInvalidate & CFSocketGetSocketFlags(_socket)); - // CFSocketEnableCallBacks(_socket, kCFSocketDataCallBack | kCFSocketReadCallBack | kCFSocketWriteCallBack); - - + // CFSocketEnableCallBacks(_socket, kCFSocketDataCallBack | kCFSocketReadCallBack | kCFSocketWriteCallBack); + + dispatch_source_t dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_current_queue() ); - + dispatch_source_set_timer(dsrc, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC / 2, NSEC_PER_SEC); - - // cf(_socket, F_SETFL, O_NONBLOCK); - // set state + + // cf(_socket, F_SETFL, O_NONBLOCK); + // set state [self setState:state]; [self _updateStatus]; - - // add to run loop to begin polling + + // add to run loop to begin polling _runloopsource = CFSocketCreateRunLoopSource(NULL,_socket,128); NSParameterAssert(_runloopsource && CFRunLoopSourceIsValid(_runloopsource)); CFRunLoopAddSource( // CFRunLoopGetMain(), CFRunLoopGetCurrent(), _runloopsource,(CFStringRef)kCFRunLoopCommonModes); + + dispatch_semaphore_t semaphore_query_send = [[self masterPoolOperation] semaphore]; + [self dispathCall]; #if defined DEBUG && defined DEBUG2 NSLog(@"%@ :: %@ :::: Socket created ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); #endif - - dispatch_semaphore_t semaphore_query_send = [[self masterPoolOperation] semaphore]; + + [self wait_semaphore_read: semaphore_query_send ]; - - - // CFRunLoopRun();//(kCFRunLoopDefaultMode, 0.2 , NO); + + + // CFRunLoopRun();//(kCFRunLoopDefaultMode, 0.2 , NO); #if defined DEBUG && defined DEBUG2 NSLog(@" ------- %@ :: %@ :::: Socket Runloop Started ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); #endif diff --git a/src/Frameworks/PGClientKit/PGConnection.h b/src/Frameworks/PGClientKit/PGConnection.h index aab9eca..ad05584 100644 --- a/src/Frameworks/PGClientKit/PGConnection.h +++ b/src/Frameworks/PGClientKit/PGConnection.h @@ -205,7 +205,8 @@ typedef enum { -(void)_waitingPoolOperationForResultMaster; -(void)wait_semaphore_read:(dispatch_semaphore_t) sem; - +-(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_t)qq_in; +-(void)dispathCall; @end //////////////////////////////////////////////////////////////////////////////// From b98ef07b1ab3a6d3bbb464375dbfb8d2d188a158 Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Mon, 7 Aug 2017 19:05:17 +0200 Subject: [PATCH 08/21] more workaround Succes --- .../PGClientKit/PGConnection+Callbacks.m | 37 +- .../PGClientKit/PGConnection+Execute.m | 688 ++++++++++-------- .../PGConnection+PGConnectionSocket.m | 9 +- src/Frameworks/PGClientKit/PGConnection.m | 3 + 4 files changed, 404 insertions(+), 333 deletions(-) diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index 7901ee1..fa08b43 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -42,7 +42,10 @@ void _socketCallback(CFSocketRef s, CFSocketCallBackType callBackType,CFDataRef #endif PGConnection* connection = (PGConnection* ) ((__bridge PGConnection* )__self); // PGConnection* connection_cp = [ connection copy]; - [((PGConnection* )connection) _socketCallback:callBackType]; + dispatch_async(dispatch_get_main_queue(), ^{ + [((PGConnection* )connection) _socketCallback:callBackType]; + }); + #if defined DEBUG && defined DEBUG2 NSLog(@"%@ :: %s :::: Socket CALL END .... (%lu) ", NSStringFromClass([((__bridge NSObject *)__self) class]), (__FUNCTION__), callBackType); #endif @@ -99,9 +102,12 @@ -(void)_socketCallbackNotification { -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus { //:: NSParameterAssert(_callback!=nil); //:: void (^callback)(BOOL usedPassword,NSError* error) = (__bridge void (^)(BOOL,NSError* ))(_callback); - if( ![((PGConnectionOperation*)[self currentPoolOperation]) valid] || [[self currentPoolOperation] poolIdentifier] != 0) + if( ![((PGConnectionOperation*)[self currentPoolOperation]) valid] + || [[self currentPoolOperation] poolIdentifier] != 0) return; + pqstatus = PQconnectPoll(_connection); + _callbackOperation = [((PGConnectionOperation*)[self currentPoolOperation]) getCallback]; void (^callback)(BOOL usedPassword,NSError* error ) = (__bridge void (^)( BOOL,NSError* ))( _callbackOperation ); @@ -120,7 +126,7 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus // set up notice processor, set success condition PQsetNoticeProcessor(_connection,_noticeProcessor,(__bridge void *)(self)); if([[self currentPoolOperation] poolIdentifier] == 0){ - dispatch_semaphore_t ss = dispatch_semaphore_create(0); + dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); mach_port_t machTID = pthread_mach_thread_np(pthread_self()); @@ -129,7 +135,7 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus NSLog(@" //// %s ", queued_name); dispatch_queue_t queue_inRun = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); - + queue_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); #if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) @@ -138,12 +144,12 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; - dispatch_barrier_sync(queue_inRun,^ + dispatch_async(queue_inRun,^ #endif { callback(usedPassword ? YES : NO,nil); -// dispatch_semaphore_signal(ss); + dispatch_semaphore_signal(ss); } #if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) @@ -157,7 +163,7 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus // [self wait_semaphore_read:ss]; [self wait_semaphore_read: ss withQueue:queue_inRun]; // - [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; + [((PGConnectionOperation*)[self masterPoolOperation]) validate]; } // dispatch_destroy(queue); } else if(needsPassword) { @@ -209,7 +215,7 @@ -(void)_socketCallbackConnect { PGConnectionOperation* currentpoolOpe = [self currentPoolOperation]; if(_connection==nil || ![[self currentPoolOperation] valid] -// || ( [currentpoolOpe poolIdentifier]) !=0 + || ( [currentpoolOpe poolIdentifier]) !=0 ) { // || (_callback==nil) // && _callbackOperation == nil) return; } @@ -223,8 +229,15 @@ -(void)_socketCallbackConnect { break; case PGRES_POLLING_OK: case PGRES_POLLING_FAILED: + if(( [currentpoolOpe poolIdentifier]) ==0 && [currentpoolOpe valid] ) + { // finished connecting - [self _socketCallbackConnectEndedWithStatus:pqstatus]; +// [self performSelectorInBackground:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; +// [self performSelector:@selector(_socketCallbackConnect) withObject:nil afterDelay:0.1]; + + [self performSelector:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; + } +// [self _socketCallbackConnectEndedWithStatus:pqstatus]; break; default: break; @@ -331,11 +344,11 @@ -(void)_socketCallbackQueryRead { #if defined DEBUG && defined DEBUG2 NSLog(@"PGConnectionStateQuery(%@::%p) - Read - Result - Done :: callback \n ********************************* \nresult :: (%@)\n ********************************* \nerror :: (%@) \n_callback :: (%@)\n ********************************* ",NSStringFromClass([self class]), self, r, error, callback ); #endif + // queue up callback on nearest thread - + dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); - // queue up callback on nearest thread - dispatch_async(dispatch_get_current_queue(),^{ + dispatch_async( qu_inRun ,^{ #if defined DEBUG && defined DEBUG2 NSLog(@"PGConnectionStateQuery - Read - callback %p ",callback); #endif diff --git a/src/Frameworks/PGClientKit/PGConnection+Execute.m b/src/Frameworks/PGClientKit/PGConnection+Execute.m index 440793a..1eb6165 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Execute.m +++ b/src/Frameworks/PGClientKit/PGConnection+Execute.m @@ -167,7 +167,7 @@ -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGR NSParameterAssert(_callbackOperation!=nil); - [NSThread sleepForTimeInterval: .2]; + // [NSThread sleepForTimeInterval: .2]; } //////////////////////////////////////////////////////////////////////////////// @@ -189,10 +189,10 @@ -(void)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) cal // } // dispatch_queue_t queue_inRun = ( ( dispatch_get_current_queue() == dispatch_get_main_queue() )? dispatch_get_main_queue() : dispatch_get_current_queue() ); mach_port_t machTID = pthread_mach_thread_np(pthread_self()); + NSString * queued_name_STR = [NSString stringWithFormat:@"%s_%x", "query_operation_dispacthed_threads", machTID ]; + const char * queued_name = [queued_name_STR UTF8String]; - const char * queued_name = [[NSString stringWithFormat:@"%s_%x", "query_operation_dispacthed_threads", machTID ] cString]; - - NSLog(@" //// %s ", queued_name); + NSLog(@" //// Query dispatch :: %@ ", queued_name_STR); dispatch_queue_t queue_inRun = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); @@ -201,335 +201,389 @@ -(void)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) cal #else - dispatch_barrier_sync(queue_inRun,^ + // dispatch_barrier_sync(queue_inRun,^ #endif - - { - // [self performSelectorOnMainThread:@selector(_waitingPoolOperationForResult) withObject:self waitUntilDone:YES ]; - - - NSParameterAssert([query isKindOfClass:[NSString class]] || [query isKindOfClass:[PGQuery class]]); - NSParameterAssert(callback); - NSString* query2 = nil; - NSError* error = nil; - if([query isKindOfClass:[NSString class]]) { - query2 = query; - } else { - query2 = [(PGQuery* )query quoteForConnection:self error:&error]; - } - if(error) { + + { + // [self performSelectorOnMainThread:@selector(_waitingPoolOperationForResult) withObject:self waitUntilDone:YES ]; + + + NSParameterAssert([query isKindOfClass:[NSString class]] || [query isKindOfClass:[PGQuery class]]); + NSParameterAssert(callback); + NSString* query2 = nil; + NSError* error = nil; + if([query isKindOfClass:[NSString class]]) { + query2 = query; + } else { + query2 = [(PGQuery* )query quoteForConnection:self error:&error]; + } + if(error) { #if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %@ - query ERROR - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); + NSLog(@"%@ :: %@ - query ERROR - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); #endif - callback(nil,error); - } else if(query2==nil) { - callback(nil,[self raiseError:nil code:PGClientErrorExecute reason:@"Query is nil"]); - } else { + callback(nil,error); + } else if(query2==nil) { + callback(nil,[self raiseError:nil code:PGClientErrorExecute reason:@"Query is nil"]); + } else { #if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %@ - query - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); + NSLog(@"%@ :: %@ - query - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); #endif - void (^callback_recall)(PGResult* result,NSError* error) = ^(PGResult* result_recall ,NSError* error_recall) - { - NSLog(@" .... semaphore callback..... "); - callback(result_recall , error_recall); - NSLog(@" .... semaphore pass ..... "); - dispatch_semaphore_signal( [[self currentPoolOperation] semaphore] ); - NSLog(@" .... semaphore signal end ..... "); - - }; - // dispatch_semaphore_signal(semaphore_query_send); - [self _execute:query2 values:nil whenDone: callback_recall]; - - } - } - + void (^callback_recall)(PGResult* result,NSError* error) = ^(PGResult* result_recall ,NSError* error_recall) + { + NSLog(@" .... semaphore callback..... "); + callback(result_recall , error_recall); + NSLog(@" .... semaphore pass ..... "); +// dispatch_semaphore_signal( [[self currentPoolOperation] semaphore] ); + NSLog(@" .... semaphore signal end ..... "); + + }; + // dispatch_semaphore_signal(semaphore_query_send); + [self _execute:query2 values:nil whenDone: callback_recall]; + + } + } + #if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) - ] + ] #else - - ) + + // ) #endif - ; - - // [self performSelector:@selector(_waitingPoolOperationForResult) withObject:self ]; - // [self performSelector:@selector(_waitingPoolOperationForResultMaster) withObject:self ]; - - _stateOperation = PGOperationStateBusy; - [NSThread sleepForTimeInterval:.2]; - NSLog(@"Is main queue? : %d", dispatch_get_current_queue() == dispatch_get_main_queue()); - dispatch_semaphore_t semaphore_query_send = [[self currentPoolOperation] semaphore]; - [self wait_semaphore_read: semaphore_query_send withQueue:queue_inRun]; - - NSLog(@"I will see this, after dispatch_semaphore_signal is called"); + ; + + // [self performSelector:@selector(_waitingPoolOperationForResult) withObject:self ]; + // [self performSelector:@selector(_waitingPoolOperationForResultMaster) withObject:self ]; + + _stateOperation = PGOperationStateBusy; +// [NSThread sleepForTimeInterval:.2]; + dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); + NSLog(@"Is main queue? : %d", qu_inRun == dispatch_get_main_queue()); + + + + + dispatch_semaphore_t semaphore_query_send = [[self currentPoolOperation] semaphore]; + [self wait_semaphore_read: semaphore_query_send withQueue:queue_inRun]; + + NSLog(@"I will see this, after dispatch_semaphore_signal is called"); } -(void)wait_semaphore_read:(dispatch_semaphore_t) sem { - [self wait_semaphore_read:sem withQueue:nil]; - } + dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); + dispatch_barrier_sync(qu_inRun, ^{ + [self wait_semaphore_read:sem withQueue:nil]; + }); + +} -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_t)qq_in { - - mach_port_t machTID = pthread_mach_thread_np(pthread_self()); - const char * queued_name = [[NSString stringWithFormat:@"%@_%x :: %s :: %s :: %@ ", NSStringFromSelector(_cmd), machTID, dispatch_queue_get_label(dispatch_get_current_queue()), dispatch_queue_get_label(dispatch_get_main_queue()), sem ] cString]; - - NSLog(@" //// Start :: %s ", queued_name); + + mach_port_t machTID = pthread_mach_thread_np(pthread_self()); + + NSString *queued_name_STR = [NSString stringWithFormat:@"%@_%x :: %s :: %@ ", NSStringFromSelector(_cmd), machTID, + + dispatch_queue_get_label(dispatch_get_main_queue()), + sem ]; + const char * queued_name = [queued_name_STR UTF8String]; + + NSLog(@" //// Start :: %@ ", queued_name_STR); + + + // dispatch_barrier_async(dispatch_get_current_queue(), ^{ + + // NSLog(@" //// Start **** :: %s ", queued_name); + long diispacthed = YES; + + NSTimeInterval resolutionTimeOut = 0.05; + NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; + bool isRunningThreadMain = YES; + bool isRunningThread = YES; + + + + // dispatch_async(((qq_in)?qq_in : dispatch_get_main_queue()), ^{ + // + // bool isRunningThreadMain = YES; + // bool isRunningThread = YES; + // + // CFRunLoopSourceSignal(_runloopsource); + // CFRunLoopWakeUp(CFRunLoopGetMain()); + // + // + // isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; + // if(!isRunningThreadMain) + // { + // [NSThread sleepForTimeInterval:.01];; + // } + // + // isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; + // if(!isRunningThreadMain) + // { + // [NSThread sleepForTimeInterval:.01];; + // } + // + // CFRunLoopSourceSignal(_runloopsource); + // CFRunLoopWakeUp(CFRunLoopGetCurrent()); + // + // + // isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; + // if(!isRunningThread) + // { + // [NSThread sleepForTimeInterval:.01];; + // } + // + // isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; + // if(!isRunningThread) + // { + // [NSThread sleepForTimeInterval:.01];; + // } + // + // }); + + + // if([[self currentPoolOperation] poolIdentifier] == 0) + while( diispacthed && _runloopsource ) + { -// dispatch_barrier_async(dispatch_get_current_queue(), ^{ + bool PG_busy = PQisBusy(_connection); + diispacthed = dispatch_semaphore_wait(sem,5UL); + // dispatch_queue_t qq_qq = dispatch_get_current_queue(); + dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); - NSLog(@" //// Start **** :: %s ", queued_name); - long diispacthed = YES; + // [self performSelector:@selector(dispathCall) withObject:nil afterDelay:.1 inModes:[NSArray arrayWithObjects: kCFRunLoopCommonModes, kCFRunLoopDefaultMode, nil]]; + if([[self currentPoolOperation] poolIdentifier] == 0) + { +// dispatch_barrier_sync(qu_inRun, ^{ + [self performSelector:@selector(dispathCall) withObject:nil]; +// }); + // + // + // [self performSelectorInBackground:@selector(dispathCall) withObject:self]; - NSTimeInterval resolutionTimeOut = 0.05; - NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; - bool isRunningThreadMain = YES; - bool isRunningThread = YES; - - - -// dispatch_async(((qq_in)?qq_in : dispatch_get_main_queue()), ^{ -// -// bool isRunningThreadMain = YES; -// bool isRunningThread = YES; -// -// CFRunLoopSourceSignal(_runloopsource); -// CFRunLoopWakeUp(CFRunLoopGetMain()); -// -// -// isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; -// if(!isRunningThreadMain) -// { -// [NSThread sleepForTimeInterval:.01];; -// } -// -// isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; -// if(!isRunningThreadMain) -// { -// [NSThread sleepForTimeInterval:.01];; -// } -// -// CFRunLoopSourceSignal(_runloopsource); -// CFRunLoopWakeUp(CFRunLoopGetCurrent()); -// -// -// isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; -// if(!isRunningThread) -// { -// [NSThread sleepForTimeInterval:.01];; -// } -// -// isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; -// if(!isRunningThread) -// { -// [NSThread sleepForTimeInterval:.01];; -// } -// -// }); - - -// if([[self currentPoolOperation] poolIdentifier] == 0) - while( diispacthed && _runloopsource ) - { - - - - diispacthed = dispatch_semaphore_wait(sem,DISPATCH_TIME_NOW); - dispatch_queue_t qq_qq = dispatch_get_current_queue(); - -// [self performSelector:@selector(dispathCall) withObject:nil afterDelay:.1 inModes:[NSArray arrayWithObjects: kCFRunLoopCommonModes, kCFRunLoopDefaultMode, nil]]; - if([[self currentPoolOperation] poolIdentifier] == 0) - { - [self performSelector:@selector(dispathCall) withObject:nil]; - }else{ - [NSThread sleepForTimeInterval:.01]; - [self performSelector:@selector(dispathCall) withObject:nil]; - } - - id shared_info = (__bridge id)(_socket); - CFSocketCallBack shared_info_shared = (_socket->_callout); - const char * class_named = object_getClassName(shared_info); - - CFSocketNativeHandle sock = CFSocketGetNative(_socket); - - struct __shared_blob *shared_dd = malloc(sizeof(struct __shared_blob)); - - // NSLog(@"%s", __CFFSocketCopyDescription(_socket)); - - // shared_dd->_rdsrc = (_socket->_shared)->_rdsrc; - // shared_dd->_wrsrc = (_socket->_shared)->_wrsrc; - // shared_dd->_source = (_socket->_shared)->_source; - // shared_dd->_socket = (_socket->_shared)->_socket; - // shared_dd->_closeFD = (_socket->_shared)->_closeFD ; - // shared_dd->_refCnt = (_socket->_shared)->_refCnt; - - // objc_mem(&shared_dd, *(_socket->_shared) , sizeof(struct __shared_blob)); - - unsigned int outCount, i; - objc_property_t *objcProperties = class_copyPropertyList([shared_info class], &outCount); - for (i = 0; i < outCount; i++) { - objc_property_t property = objcProperties[i]; - const char *propName = property_getName(property); - if(propName) { - // const char * propType = getPropertyType(property); - NSString * propertyName = [NSString stringWithUTF8String:propName]; - - } - } - - // [((NSObject*)shared_info) shared]; - id sockk = (__bridge id)((_socket)->_shared); - - // typedef struct __CFSocket sockt; - // - // dispatch_object_t disp_obj = (dispatch_object_t) ((shared_info*)->_shared->_rdsrc); - // dispatch_resume( ((dispatch_object_t) disp_obj) );; - if( diispacthed && !isRunningThreadMain && !isRunningThreadMain - && [[self currentPoolOperation] valid] - ) - [NSThread sleepForTimeInterval:.01]; - - if( diispacthed && !isRunningThreadMain && !isRunningThreadMain - && [[self currentPoolOperation] valid] && [self connectionPoolOperationCount] > 1 - && !PQisBusy(_connection) ) - break; + [NSThread sleepForTimeInterval:.5]; + }else{ + + // [self performSelectorOnMainThread:@selector(dispathCall) withObject:self waitUntilDone:YES modes:@[NSRunLoopCommonModes, NSDefaultRunLoopMode] ]; + // [self performSelectorInBackground:@selector(dispathCall) withObject:self]; + // [self performSelector:@selector(dispathCall) withObject:nil]; +// isRunningThreadMain = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; + [self performSelector:@selector(dispathCall) withObject:nil]; + [NSThread sleepForTimeInterval:.5]; + if(!PG_busy) + break; + + } + + id shared_info = (__bridge id)(_socket); + CFSocketCallBack shared_info_shared = (_socket->_callout); + const char * class_named = object_getClassName(shared_info); + + CFSocketNativeHandle sock = CFSocketGetNative(_socket); + + struct __shared_blob *shared_dd = malloc(sizeof(struct __shared_blob)); + + // NSLog(@"%s", __CFFSocketCopyDescription(_socket)); + + // shared_dd->_rdsrc = (_socket->_shared)->_rdsrc; + // shared_dd->_wrsrc = (_socket->_shared)->_wrsrc; + // shared_dd->_source = (_socket->_shared)->_source; + // shared_dd->_socket = (_socket->_shared)->_socket; + // shared_dd->_closeFD = (_socket->_shared)->_closeFD ; + // shared_dd->_refCnt = (_socket->_shared)->_refCnt; + + // objc_mem(&shared_dd, *(_socket->_shared) , sizeof(struct __shared_blob)); + + unsigned int outCount, i; + objc_property_t *objcProperties = class_copyPropertyList([shared_info class], &outCount); + for (i = 0; i < outCount; i++) { + objc_property_t property = objcProperties[i]; + const char *propName = property_getName(property); + if(propName) { + // const char * propType = getPropertyType(property); + NSString * propertyName = [NSString stringWithUTF8String:propName]; } + } + + // [((NSObject*)shared_info) shared]; + id sockk = (__bridge id)((_socket)->_shared); + + // typedef struct __CFSocket sockt; + // + // dispatch_object_t disp_obj = (dispatch_object_t) ((shared_info*)->_shared->_rdsrc); + // dispatch_resume( ((dispatch_object_t) disp_obj) );; + if( diispacthed && !isRunningThreadMain && !isRunningThreadMain + && [[self currentPoolOperation] valid] + ) + [NSThread sleepForTimeInterval:.01]; + + // if( diispacthed + //// && !isRunningThreadMain && !isRunningThreadMain + // && [[self currentPoolOperation] valid] + // && [self connectionPoolOperationCount] > 1 + // && ! PG_busy ) + // break; + + } + + NSLog(@" //// Clean **** :: %s ", queued_name); + // }); + // + [[NSThread currentThread] cancel]; + NSLog(@" //// END :: %s ", queued_name); +} + +-(PGResult* )execute:(id)query error:(NSError** )error { + dispatch_semaphore_t s = dispatch_semaphore_create(0); + __block PGResult* result = nil; + [self execute:query whenDone:^(PGResult* r, NSError* e) { + if(error) { + (*error) = e; + } + result = r; + dispatch_semaphore_signal(s); + }]; + dispatch_semaphore_wait(s,DISPATCH_TIME_FOREVER); + return result; +} +-(void)dispathCall +{ + // dispatch_async(dispatch_get_current_queue(), ^{ + NSTimeInterval resolutionTimeOut = 0.05; + NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; + bool isRunningThreadMain = YES; + bool isRunningThread = YES; + + while( _runloopsource && ( isRunningThreadMain || isRunningThread ) ){ + if(_runloopsource){ + CFRunLoopSourceSignal(_runloopsource); + } + CFRunLoopWakeUp(CFRunLoopGetMain()); + + + + + if(_runloopsource){ + CFRunLoopSourceSignal(_runloopsource); + } + CFRunLoopWakeUp(CFRunLoopGetCurrent()); + + + isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; + if(!isRunningThread) + { + [NSThread sleepForTimeInterval:.01];; + } + dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); + NSRunLoop *qq_loop = [NSRunLoop currentRunLoop]; + NSRunLoop *qq_loop_main = [NSRunLoop mainRunLoop]; + if( qq_loop != [NSRunLoop mainRunLoop]){ + if([[self currentPoolOperation] poolIdentifier] == 0 ){ + [qq_loop runUntilDate:theNextDate]; + }else{ + [self performSelectorOnMainThread:@selector(dispathCall) withObject:self waitUntilDone:YES modes:@[NSRunLoopCommonModes, NSDefaultRunLoopMode] ]; + NSLog(@" END performSelectorOnMainThread :: %@", NSStringFromSelector(_cmd)); + } + } + if([[self currentPoolOperation] poolIdentifier] == 0 && [[self currentPoolOperation] valid]){ +// dispatch_async(dispatch_get_main_queue(), ^{ +// isRunningThread = [qq_loop runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; +// if(!isRunningThread) +// { +// bool isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; +// if(!isRunningThreadMain){ + [qq_loop runUntilDate:theNextDate]; + [qq_loop_main runUntilDate:theNextDate]; + + + +// } +// } +// }); - NSLog(@" //// Clean **** :: %s ", queued_name); -// }); - // [[NSThread currentThread] cancel]; - NSLog(@" //// END :: %s ", queued_name); + + }else if([[self currentPoolOperation] poolIdentifier] != 0 && [[self currentPoolOperation] valid]){ + [qq_loop runUntilDate:theNextDate]; + [qq_loop_main runUntilDate:theNextDate]; + } + [NSThread sleepForTimeInterval:.01];; } - - -(PGResult* )execute:(id)query error:(NSError** )error { - dispatch_semaphore_t s = dispatch_semaphore_create(0); - __block PGResult* result = nil; - [self execute:query whenDone:^(PGResult* r, NSError* e) { - if(error) { - (*error) = e; - } - result = r; - dispatch_semaphore_signal(s); - }]; - dispatch_semaphore_wait(s,DISPATCH_TIME_FOREVER); - return result; - } - -(void)dispathCall - { -// dispatch_async(dispatch_get_current_queue(), ^{ - NSTimeInterval resolutionTimeOut = 0.05; - NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; - bool isRunningThreadMain = YES; - bool isRunningThread = YES; - - while(YES || isRunningThreadMain || isRunningThread){ - CFRunLoopSourceSignal(_runloopsource); - CFRunLoopWakeUp(CFRunLoopGetMain()); - - - isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; - if(!isRunningThreadMain) - { - [NSThread sleepForTimeInterval:.01];; - } - - isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; - if(!isRunningThreadMain) - { - [NSThread sleepForTimeInterval:.01];; - } - - CFRunLoopSourceSignal(_runloopsource); - CFRunLoopWakeUp(CFRunLoopGetCurrent()); - - - isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; - if(!isRunningThread) - { - [NSThread sleepForTimeInterval:.01];; - } - - isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; - if(!isRunningThread) - { - [NSThread sleepForTimeInterval:.01];; - } - } -// }); - - } - -(void)_queue:(PGTransaction* )transaction index:(NSUInteger)i lastResult:(PGResult* )result lastError:(NSError* )error whenQueryDone:(void(^)(PGResult* result,BOOL isLastQuery,NSError* error)) callback { - if(error) { - // rollback - if([transaction transactional]) { - NSString* rollbackTransaction = [(PGTransaction* )transaction quoteRollbackTransactionForConnection:self]; - NSParameterAssert(rollbackTransaction); - [self execute:rollbackTransaction whenDone:^(PGResult* result2,NSError* error2) { - callback(nil,YES,error); - }]; - } else { - callback(nil,YES,error); - } - } else if(i==[transaction count]) { - // commit - if([transaction transactional]) { - NSString* commitTransaction = [(PGTransaction* )transaction quoteCommitTransactionForConnection:self]; - NSParameterAssert(commitTransaction); - [self execute:commitTransaction whenDone:^(PGResult* result2, NSError* error2) { - callback(result,YES,error); - }]; - } else { - callback(result,YES,error); - } - } else { - // execute a single query - [self execute:[transaction queryAtIndex:i] whenDone:^(PGResult* result,NSError* error) { - if(i < [transaction count]) { - [self _queue:transaction index:(i+1) lastResult:result lastError:error whenQueryDone:callback]; - } - }]; - } - } - - -(void)queue:(PGTransaction* )transaction whenQueryDone:(void(^)(PGResult* result,BOOL isLastQuery,NSError* error)) callback { - NSParameterAssert(transaction && [transaction isKindOfClass:[PGTransaction class]]); - - // where there are no transactions to execute, raise error immediately - if([transaction count]==0) { - callback(nil,YES,[self raiseError:nil code:PGClientErrorExecute reason:@"No transactions to execute"]); - return; - } - - // check for connection status - if(_connection==nil || [self state] != PGConnectionStateNone) { - callback(nil,YES,[self raiseError:nil code:PGClientErrorState]); - return; - } - - // check for transaction status - PGTransactionStatusType tstatus = PQtransactionStatus(_connection); - if([transaction transactional] && tstatus != PQTRANS_IDLE) { - callback(nil,YES,[self raiseError:nil code:PGClientErrorState reason:@"Already in a transaction"]); - return; - } - - if([transaction transactional]==NO) { - // queue zeroth query - [self _queue:transaction index:0 lastResult:nil lastError:nil whenQueryDone:callback]; - } else { - // queue up a start transaction, which triggers the first query - NSString* beginTransaction = [(PGTransaction* )transaction quoteBeginTransactionForConnection:self]; - NSParameterAssert(beginTransaction); - [self execute:beginTransaction whenDone:^(PGResult* result, NSError* error) { - // if the BEGIN transaction didn't work, then callback - if(error) { - callback(nil,YES,error); - } else { - // else queue up zeroth query - [self _queue:transaction index:0 lastResult:result lastError:error whenQueryDone:callback]; - } - }]; - } - } - - @end - - + // }); + +} +-(void)_queue:(PGTransaction* )transaction index:(NSUInteger)i lastResult:(PGResult* )result lastError:(NSError* )error whenQueryDone:(void(^)(PGResult* result,BOOL isLastQuery,NSError* error)) callback { + if(error) { + // rollback + if([transaction transactional]) { + NSString* rollbackTransaction = [(PGTransaction* )transaction quoteRollbackTransactionForConnection:self]; + NSParameterAssert(rollbackTransaction); + [self execute:rollbackTransaction whenDone:^(PGResult* result2,NSError* error2) { + callback(nil,YES,error); + }]; + } else { + callback(nil,YES,error); + } + } else if(i==[transaction count]) { + // commit + if([transaction transactional]) { + NSString* commitTransaction = [(PGTransaction* )transaction quoteCommitTransactionForConnection:self]; + NSParameterAssert(commitTransaction); + [self execute:commitTransaction whenDone:^(PGResult* result2, NSError* error2) { + callback(result,YES,error); + }]; + } else { + callback(result,YES,error); + } + } else { + // execute a single query + [self execute:[transaction queryAtIndex:i] whenDone:^(PGResult* result,NSError* error) { + if(i < [transaction count]) { + [self _queue:transaction index:(i+1) lastResult:result lastError:error whenQueryDone:callback]; + } + }]; + } +} + +-(void)queue:(PGTransaction* )transaction whenQueryDone:(void(^)(PGResult* result,BOOL isLastQuery,NSError* error)) callback { + NSParameterAssert(transaction && [transaction isKindOfClass:[PGTransaction class]]); + + // where there are no transactions to execute, raise error immediately + if([transaction count]==0) { + callback(nil,YES,[self raiseError:nil code:PGClientErrorExecute reason:@"No transactions to execute"]); + return; + } + + // check for connection status + if(_connection==nil || [self state] != PGConnectionStateNone) { + callback(nil,YES,[self raiseError:nil code:PGClientErrorState]); + return; + } + + // check for transaction status + PGTransactionStatusType transac_status = PQtransactionStatus(_connection); + if([transaction transactional] && transac_status != PQTRANS_IDLE) { + callback(nil,YES,[self raiseError:nil code:PGClientErrorState reason:@"Already in a transaction"]); + return; + } + + if([transaction transactional]==NO) { + // queue zeroth query + [self _queue:transaction index:0 lastResult:nil lastError:nil whenQueryDone:callback]; + } else { + // queue up a start transaction, which triggers the first query + NSString* beginTransaction = [(PGTransaction* )transaction quoteBeginTransactionForConnection:self]; + NSParameterAssert(beginTransaction); + [self execute:beginTransaction whenDone:^(PGResult* result, NSError* error) { + // if the BEGIN transaction didn't work, then callback + if(error) { + callback(nil,YES,error); + } else { + // else queue up zeroth query + [self _queue:transaction index:0 lastResult:result lastError:error whenQueryDone:callback]; + } + }]; + } +} + +@end + + diff --git a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m index 88acd50..cadfb0f 100644 --- a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m +++ b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m @@ -300,8 +300,9 @@ -(void)_socketConnect:(PGConnectionState)state { CFSocketSetSocketFlags(_socket,~kCFSocketCloseOnInvalidate & CFSocketGetSocketFlags(_socket)); // CFSocketEnableCallBacks(_socket, kCFSocketDataCallBack | kCFSocketReadCallBack | kCFSocketWriteCallBack); + dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); - dispatch_source_t dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_current_queue() ); + dispatch_source_t dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, qu_inRun ); dispatch_source_set_timer(dsrc, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC / 2, NSEC_PER_SEC); @@ -311,15 +312,15 @@ -(void)_socketConnect:(PGConnectionState)state { [self _updateStatus]; // add to run loop to begin polling - _runloopsource = CFSocketCreateRunLoopSource(NULL,_socket,128); + _runloopsource = CFSocketCreateRunLoopSource(NULL,_socket,1); NSParameterAssert(_runloopsource && CFRunLoopSourceIsValid(_runloopsource)); CFRunLoopAddSource( // CFRunLoopGetMain(), - CFRunLoopGetCurrent(), + CFRunLoopGetCurrent(), // One connection PER Thread _runloopsource,(CFStringRef)kCFRunLoopCommonModes); dispatch_semaphore_t semaphore_query_send = [[self masterPoolOperation] semaphore]; - [self dispathCall]; +// [self dispathCall]; #if defined DEBUG && defined DEBUG2 NSLog(@"%@ :: %@ :::: Socket created ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); #endif diff --git a/src/Frameworks/PGClientKit/PGConnection.m b/src/Frameworks/PGClientKit/PGConnection.m index 9ca56e0..93c51c9 100644 --- a/src/Frameworks/PGClientKit/PGConnection.m +++ b/src/Frameworks/PGClientKit/PGConnection.m @@ -392,6 +392,9 @@ -(id)invalidateOperation:(NSInteger)operationRefIndex if(indexInPool > 0 && indexInPool>=operationRefIndex && operationRefIndex !=0) { id obj = CFArrayGetValueAtIndex(_callbackOperationPool, operationRefIndex); + if([obj semaphore]) + dispatch_semaphore_signal( [obj semaphore] ); + #if defined DEBUG && defined DEBUG2 NSLog(@" %@::%@ :: REMOVED pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, [obj description]); #endif From 30358ee4a7553ed10813368cf33ca91a99ffddca Mon Sep 17 00:00:00 2001 From: "genose.org" Date: Tue, 8 Aug 2017 09:03:34 +0200 Subject: [PATCH 09/21] More nice step and result --- .../PGClientKit/PGConnection+Callbacks.m | 32 +++++++-- .../PGClientKit/PGConnection+Execute.m | 67 ++++++++++--------- .../PGConnection+PGConnectionSocket.m | 2 +- src/Frameworks/PGClientKit/PGConnection.m | 1 + .../PGClientKit/PGConnectionOperation.h | 1 + .../PGClientKit/PGConnectionOperation.m | 14 +++- 6 files changed, 75 insertions(+), 42 deletions(-) diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index fa08b43..de2519b 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -42,7 +42,9 @@ void _socketCallback(CFSocketRef s, CFSocketCallBackType callBackType,CFDataRef #endif PGConnection* connection = (PGConnection* ) ((__bridge PGConnection* )__self); // PGConnection* connection_cp = [ connection copy]; - dispatch_async(dispatch_get_main_queue(), ^{ + if(! connection) + return ; + dispatch_barrier_async(dispatch_get_main_queue(), ^{ [((PGConnection* )connection) _socketCallback:callBackType]; }); @@ -72,6 +74,8 @@ @implementation PGConnection (Callbacks) //////////////////////////////////////////////////////////////////////////////// -(void)_socketCallbackNotification { + @try + { NSParameterAssert(_connection); // consume input PQconsumeInput(_connection); @@ -98,6 +102,13 @@ -(void)_socketCallbackNotification { NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: free "); #endif } +@catch (NSException *exception) { + NSLog(@" %@ exeception .... %@",NSStringFromSelector(_cmd),exception); +} +@finally { + +} +} -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus { //:: NSParameterAssert(_callback!=nil); @@ -126,7 +137,7 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus // set up notice processor, set success condition PQsetNoticeProcessor(_connection,_noticeProcessor,(__bridge void *)(self)); if([[self currentPoolOperation] poolIdentifier] == 0){ - dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); + mach_port_t machTID = pthread_mach_thread_np(pthread_self()); @@ -147,8 +158,9 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus dispatch_async(queue_inRun,^ #endif { - + dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); callback(usedPassword ? YES : NO,nil); + [((PGConnectionOperation*)[self masterPoolOperation]) finish]; dispatch_semaphore_signal(ss); } @@ -161,9 +173,8 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus ; // dispatch_semaphore_wait(ss,DISPATCH_TIME_FOREVER); // [self wait_semaphore_read:ss]; - [self wait_semaphore_read: ss withQueue:queue_inRun]; -// - [((PGConnectionOperation*)[self masterPoolOperation]) validate]; + [self wait_semaphore_read: [((PGConnectionOperation*)[self masterPoolOperation]) semaphore] withQueue:queue_inRun]; +// [((PGConnectionOperation*)[self masterPoolOperation]) validate]; } // dispatch_destroy(queue); } else if(needsPassword) { @@ -402,7 +413,7 @@ -(void)_socketCallbackQueryWrite { * or notification socket callback */ -(void)_socketCallback:(CFSocketCallBackType)callBackType { - + @try{ #if defined DEBUG && defined DEBUG2 switch(callBackType) { case kCFSocketReadCallBack: @@ -467,6 +478,13 @@ -(void)_socketCallback:(CFSocketCallBackType)callBackType { } [self _updateStatus]; + } + @catch (NSException *exception) { + NSLog(@" %@ exeception .... %@",NSStringFromSelector(_cmd),exception); + } + @finally { + + } } @end diff --git a/src/Frameworks/PGClientKit/PGConnection+Execute.m b/src/Frameworks/PGClientKit/PGConnection+Execute.m index 1eb6165..4a91bdd 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Execute.m +++ b/src/Frameworks/PGClientKit/PGConnection+Execute.m @@ -337,14 +337,14 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ // } // // }); - + bool PG_busy = YES; // if([[self currentPoolOperation] poolIdentifier] == 0) - while( diispacthed && _runloopsource ) + while( diispacthed && _runloopsource && _socket ) { - bool PG_busy = PQisBusy(_connection); + PG_busy = PQisBusy(_connection); diispacthed = dispatch_semaphore_wait(sem,5UL); // dispatch_queue_t qq_qq = dispatch_get_current_queue(); dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); @@ -353,6 +353,7 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ if([[self currentPoolOperation] poolIdentifier] == 0) { // dispatch_barrier_sync(qu_inRun, ^{ +if([[self currentPoolOperation] valid] && [[self currentPoolOperation] getCallback]) [self performSelector:@selector(dispathCall) withObject:nil]; // }); // @@ -373,14 +374,14 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ } - id shared_info = (__bridge id)(_socket); - CFSocketCallBack shared_info_shared = (_socket->_callout); - const char * class_named = object_getClassName(shared_info); - - CFSocketNativeHandle sock = CFSocketGetNative(_socket); - - struct __shared_blob *shared_dd = malloc(sizeof(struct __shared_blob)); - +// id shared_info = (__bridge id)(_socket); +// CFSocketCallBack shared_info_shared = (_socket->_callout); +// const char * class_named = object_getClassName(shared_info); +// +// CFSocketNativeHandle sock = CFSocketGetNative(_socket); +// +// struct __shared_blob *shared_dd = malloc(sizeof(struct __shared_blob)); + // NSLog(@"%s", __CFFSocketCopyDescription(_socket)); // shared_dd->_rdsrc = (_socket->_shared)->_rdsrc; @@ -392,21 +393,21 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ // objc_mem(&shared_dd, *(_socket->_shared) , sizeof(struct __shared_blob)); - unsigned int outCount, i; - objc_property_t *objcProperties = class_copyPropertyList([shared_info class], &outCount); - for (i = 0; i < outCount; i++) { - objc_property_t property = objcProperties[i]; - const char *propName = property_getName(property); - if(propName) { - // const char * propType = getPropertyType(property); - NSString * propertyName = [NSString stringWithUTF8String:propName]; - - } - } - +// unsigned int outCount, i; +// objc_property_t *objcProperties = class_copyPropertyList([shared_info class], &outCount); +// for (i = 0; i < outCount; i++) { +// objc_property_t property = objcProperties[i]; +// const char *propName = property_getName(property); +// if(propName) { +// // const char * propType = getPropertyType(property); +// NSString * propertyName = [NSString stringWithUTF8String:propName]; +// +// } +// } +// // [((NSObject*)shared_info) shared]; - id sockk = (__bridge id)((_socket)->_shared); - +// id sockk = (__bridge id)((_socket)->_shared); + // typedef struct __CFSocket sockt; // // dispatch_object_t disp_obj = (dispatch_object_t) ((shared_info*)->_shared->_rdsrc); @@ -422,7 +423,7 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ // && [self connectionPoolOperationCount] > 1 // && ! PG_busy ) // break; - + if([self status] == PGConnectionStatusDisconnected || ! _connection) break; } NSLog(@" //// Clean **** :: %s ", queued_name); @@ -452,8 +453,9 @@ -(void)dispathCall NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; bool isRunningThreadMain = YES; bool isRunningThread = YES; - - while( _runloopsource && ( isRunningThreadMain || isRunningThread ) ){ + if([self status] == PGConnectionStatusDisconnected || ! _connection) return; +// while( _runloopsource && ( isRunningThreadMain || isRunningThread ) ) + { if(_runloopsource){ CFRunLoopSourceSignal(_runloopsource); } @@ -490,13 +492,16 @@ -(void)dispathCall // if(!isRunningThread) // { // bool isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; -// if(!isRunningThreadMain){ + if(!isRunningThread){ + [qq_loop runUntilDate:theNextDate]; - [qq_loop_main runUntilDate:theNextDate]; + -// } + }else{ + [qq_loop_main runUntilDate:theNextDate]; + } // } // }); diff --git a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m index cadfb0f..f59fc1b 100644 --- a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m +++ b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m @@ -331,7 +331,7 @@ -(void)_socketConnect:(PGConnectionState)state { // CFRunLoopRun();//(kCFRunLoopDefaultMode, 0.2 , NO); #if defined DEBUG && defined DEBUG2 - NSLog(@" ------- %@ :: %@ :::: Socket Runloop Started ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); + NSLog(@" ------- %@ :: %@ :::: Socket Runloop ENDED CLEAR ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); #endif } diff --git a/src/Frameworks/PGClientKit/PGConnection.m b/src/Frameworks/PGClientKit/PGConnection.m index 93c51c9..e7628f3 100644 --- a/src/Frameworks/PGClientKit/PGConnection.m +++ b/src/Frameworks/PGClientKit/PGConnection.m @@ -394,6 +394,7 @@ -(id)invalidateOperation:(NSInteger)operationRefIndex id obj = CFArrayGetValueAtIndex(_callbackOperationPool, operationRefIndex); if([obj semaphore]) dispatch_semaphore_signal( [obj semaphore] ); + [obj finish]; #if defined DEBUG && defined DEBUG2 NSLog(@" %@::%@ :: REMOVED pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, [obj description]); diff --git a/src/Frameworks/PGClientKit/PGConnectionOperation.h b/src/Frameworks/PGClientKit/PGConnectionOperation.h index e78fae2..84e9628 100644 --- a/src/Frameworks/PGClientKit/PGConnectionOperation.h +++ b/src/Frameworks/PGClientKit/PGConnectionOperation.h @@ -49,6 +49,7 @@ -(id)queryString; -(id)UTF8String; +-(void)finish; -(bool)valid; -(void)validate; -(void)invalidate; diff --git a/src/Frameworks/PGClientKit/PGConnectionOperation.m b/src/Frameworks/PGClientKit/PGConnectionOperation.m index 41131b0..21eca94 100644 --- a/src/Frameworks/PGClientKit/PGConnectionOperation.m +++ b/src/Frameworks/PGClientKit/PGConnectionOperation.m @@ -68,13 +68,21 @@ -(instancetype)initWithParametersDelegate:(id)connectionDelegate withRefPoolIden } -(bool)valid { - return !_invalidated; + return (_callbackWhenDone == nil) ? false : !_invalidated ; +} +-(void)finish +{ + _callbackWhenDone = nil; } -(void)invalidate { NSLog(@" %@::%@ :: INVALIDATE pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), _poolRefIdentifier, [self description]); - if(_poolRefIdentifier !=0) - [_operationConnectionClassRef invalidateOperation: _poolRefIdentifier]; + if(_poolRefIdentifier !=0){ + [_operationConnectionClassRef invalidateOperation: _poolRefIdentifier]; + [self finish]; + } + + _invalidated = TRUE; } From 3e3eb5df6134ba2fd27a6f58aa0ec63060838b41 Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Tue, 8 Aug 2017 17:32:41 +0200 Subject: [PATCH 10/21] Success : Mutithreaded Query, AUTO DISPATCH Now you can execute Imbriqued queries and parallel Queries bool cleared_status NO; PGQueryObject* query = [PGQuery queryWithString:@"SELECT datname FROM pg_database"]; PGQueryObject* query2 = [PGQuery queryWithString:[NSString stringWithFormat:@"SELECT user FROM %@", NSUserName()]]; PGQueryObject* query_DD = [PGQuery queryWithString:[NSString stringWithFormat:@"SELECT GG FROM %@", NSUserName()]]; NSString* username = NSUserName(); NSString* userpassword = @"pass"; NSString* dbname = NSUserName(); NSURL* urlBDD_test = [NSURL URLWithHost:@"localhost" port: 5432 ssl:NO username:username database:dbname params:nil]; // urlBDD_test = [NSURL URLWithSocketPath:nil port:(NSUInteger)5432 database:nil username:username params:nil]; urlBDD_test = [NSURL URLWithHost:@"localhost" ssl:NO username: username database:dbname params:[NSDictionary dictionaryWithObjectsAndKeys: @"5432", @"port", [NSString stringWithFormat:@"%d",20], @"connect_timeout", userpassword, @"password", nil] ]; NSLog(@" Start Connection with : %@ : %@", urlBDD_test, urlBDD); // :: has property :: PGConnection * SQLServ_db = [PGConnection new]; // [SQLServ_db connectWithURL:urlBDD_test usedPassword:&isConnected error:&cnxError]; [((PGConnection*)[self SQLServ_db]) connectWithURL: urlBDD_test whenDone:^(BOOL usedPassword, NSError *errorConnect) { NSLog(@" SQLServ_db :: .... :"); if(errorConnect) { NSLog(@" SQLServ_db :: connectWithURL: Error: %@",errorConnect); // [[self SQLServ_db] disconnect]; cleared_status = YES; }else { NSLog(@" SQLServ_db :: connectWithURL: connected .... : %@",errorConnect); [[self SQLServ_db] execute:query whenDone:^(PGResult* result, NSError* error) { NSLog(@" SQLServ_db :: query_1 :: pass "); NSLog(@" SQLServ_db :: query_1 :: obj execute: result :: %@ ", [result fetchRowAsDictionary]); if(error) { NSLog(@" SQLServ_db :: query_1 :: obj execute:error :: %@ :: %@", result, error); } [[self SQLServ_db] execute:query_DD whenDone:^(PGResult* result, NSError* error) { NSLog(@" SQLServ_db :: query_DD :: pass "); NSLog(@" SQLServ_db :: query_DD :: obj execute: result :: %@ ", [result fetchRowAsDictionary]); if(error) { NSLog(@" SQLServ_db :: query_DD :: obj execute:error :: %@ :: %@", result, error); } }]; }]; NSLog(@" SQLServ_db :: backmain end :: pass "); [[self SQLServ_db] execute:query2 whenDone:^(PGResult* result, NSError* error) { NSLog(@" SQLServ_db :: query_2 :: pass "); if(result) { NSLog(@" SQLServ_db :: query_2 :: obj execute: result :: %@ ", [result fetchRowAsDictionary]); } if(error) { NSLog(@" SQLServ_db :: query_2 :: obj execute:error :: %@ :: %@", result, error); } }]; } NSLog(@" SQLServ_db ..... DONE :: .... :"); [[self SQLServ_db] disconnect]; cleared_status = YES; }]; [NSThread sleepForTimeInterval:6.0]; [[self SQLServ_db] execute:query2 whenDone:^(PGResult* result, NSError* error) { // if(result) { NSLog(@" SQLServ_db :: query_LL :: pass "); NSLog(@" SQLServ_db :: query_LL :: obj execute: result :: %@ ", [result fetchRowAsDictionary]); // } if(error) { NSLog(@" SQLServ_db :: query_LL :: obj execute:error :: %@ :: %@", result, error); } [[self SQLServ_db] disconnect]; cleared_status = YES; }]; NSLog(@" SQLServ_db ..... exit :: .... :"); --- .../PGClientKit/PGConnection+Callbacks.m | 747 +++++++++--------- .../PGClientKit/PGConnection+Connect.m | 7 +- .../PGClientKit/PGConnection+Errors.m | 27 +- .../PGClientKit/PGConnection+Execute.m | 590 ++++++-------- .../PGConnection+PGConnectionSocket.m | 2 +- .../PGClientKit/PGConnectionOperation.m | 3 +- 6 files changed, 629 insertions(+), 747 deletions(-) diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index de2519b..8ded71a 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -36,21 +36,32 @@ * This method is called from the run loop upon new data being available to read * on the socket, or the socket being able to write more data to the socket */ +static int socketUsed_in = 0; void _socketCallback(CFSocketRef s, CFSocketCallBackType callBackType,CFDataRef address,const void* data,void* __self) { -#if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %s :::: Socket CALL ... %lu ", NSStringFromClass([((__bridge NSObject *)__self) class]), (__FUNCTION__), callBackType); -#endif + + + + [NSThread sleepForTimeInterval:.01];; + PGConnection* connection = (PGConnection* ) ((__bridge PGConnection* )__self); -// PGConnection* connection_cp = [ connection copy]; - if(! connection) + if(! connection +// || socketUsed_in > 20 + ) return ; - dispatch_barrier_async(dispatch_get_main_queue(), ^{ - [((PGConnection* )connection) _socketCallback:callBackType]; - }); - + socketUsed_in ++; +// dispatch_barrier_async(dispatch_get_main_queue(), ^{ +#if defined DEBUG && defined DEBUG2 + NSLog(@"%@ :: %s :::: Socket CALL ... %lu ", NSStringFromClass([((__bridge NSObject *)__self) class]), (__FUNCTION__), callBackType); +#endif + [((PGConnection* )connection) _socketCallback:callBackType]; #if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %s :::: Socket CALL END .... (%lu) ", NSStringFromClass([((__bridge NSObject *)__self) class]), (__FUNCTION__), callBackType); + NSLog(@"%@ :: %s :::: Socket CALL END .... (%lu) ", NSStringFromClass([((__bridge NSObject *)__self) class]), (__FUNCTION__), callBackType); #endif + socketUsed_in = 0; +// }); + +// [NSThread sleepForTimeInterval:.1];; + } /** @@ -58,12 +69,12 @@ void _socketCallback(CFSocketRef s, CFSocketCallBackType callBackType,CFDataRef * the libpq library */ void _noticeProcessor(void* arg,const char* cString) { - NSString* notice = [NSString stringWithUTF8String:cString]; - PGConnection* connection = (__bridge PGConnection* )arg; - NSCParameterAssert(connection && [connection isKindOfClass:[PGConnection class]]); - if([[connection delegate] respondsToSelector:@selector(connection:notice:)]) { - [[connection delegate] connection:connection notice:notice]; - } + NSString* notice = [NSString stringWithUTF8String:cString]; + PGConnection* connection = (__bridge PGConnection* )arg; + NSCParameterAssert(connection && [connection isKindOfClass:[PGConnection class]]); + if([[connection delegate] respondsToSelector:@selector(connection:notice:)]) { + [[connection delegate] connection:connection notice:notice]; + } } @@ -76,418 +87,418 @@ @implementation PGConnection (Callbacks) -(void)_socketCallbackNotification { @try { - NSParameterAssert(_connection); - // consume input - PQconsumeInput(_connection); - + NSParameterAssert(_connection); + // consume input + PQconsumeInput(_connection); + #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: loop "); + NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: loop "); #endif - - // loop for notifications - PGnotify* notify = nil; - while((notify = PQnotifies(_connection)) != nil) { - if([[self delegate] respondsToSelector:@selector(connection:notificationOnChannel:payload:)]) { + + // loop for notifications + PGnotify* notify = nil; + while((notify = PQnotifies(_connection)) != nil) { + if([[self delegate] respondsToSelector:@selector(connection:notificationOnChannel:payload:)]) { #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: call delegate (%@) (%@)", [self delegate], NSStringFromSelector(@selector(connection:notificationOnChannel:payload:))); + NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: call delegate (%@) (%@)", [self delegate], NSStringFromSelector(@selector(connection:notificationOnChannel:payload:))); #endif - - NSString* channel = [NSString stringWithUTF8String:notify->relname]; - NSString* payload = [NSString stringWithUTF8String:notify->extra]; - [[self delegate] connection:self notificationOnChannel:channel payload:payload]; + + NSString* channel = [NSString stringWithUTF8String:notify->relname]; + NSString* payload = [NSString stringWithUTF8String:notify->extra]; + [[self delegate] connection:self notificationOnChannel:channel payload:payload]; + } + PQfreemem(notify); } - PQfreemem(notify); - } #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: free "); + NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: free "); #endif -} -@catch (NSException *exception) { - NSLog(@" %@ exeception .... %@",NSStringFromSelector(_cmd),exception); -} -@finally { - -} + } + @catch (NSException *exception) { + NSLog(@" %@ exeception .... %@",NSStringFromSelector(_cmd),exception); + } + @finally { + + } } -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus { -//:: NSParameterAssert(_callback!=nil); -//:: void (^callback)(BOOL usedPassword,NSError* error) = (__bridge void (^)(BOOL,NSError* ))(_callback); + + //:: void (^callback)(BOOL usedPassword,NSError* error) = (__bridge void (^)(BOOL,NSError* ))(_callback); if( ![((PGConnectionOperation*)[self currentPoolOperation]) valid] || [[self currentPoolOperation] poolIdentifier] != 0) return; - pqstatus = PQconnectPoll(_connection); + pqstatus = PQconnectPoll(_connection); - _callbackOperation = [((PGConnectionOperation*)[self currentPoolOperation]) getCallback]; + _callbackOperation = [((PGConnectionOperation*)[self masterPoolOperation]) getCallback]; void (^callback)(BOOL usedPassword,NSError* error ) = (__bridge void (^)( BOOL,NSError* ))( _callbackOperation ); - - BOOL needsPassword = PQconnectionNeedsPassword(_connection) ? YES : NO; - BOOL usedPassword = PQconnectionUsedPassword(_connection) ? YES : NO; + + BOOL needsPassword = PQconnectionNeedsPassword(_connection) ? YES : NO; + BOOL usedPassword = PQconnectionUsedPassword(_connection) ? YES : NO; #if defined DEBUG && defined DEBUG2 NSLog(@"%@ (%p) :: BEGIN :: - Read::BEGIN - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); #endif - // update the status - [self setState:PGConnectionStateNone]; - [self _updateStatus]; // this also calls disconnect when rejected + // update the status + [self setState:PGConnectionStateNone]; + [self _updateStatus]; // this also calls disconnect when rejected + - - // callback - if(pqstatus==PGRES_POLLING_OK) { - // set up notice processor, set success condition - PQsetNoticeProcessor(_connection,_noticeProcessor,(__bridge void *)(self)); + // callback + if(pqstatus==PGRES_POLLING_OK) { + // set up notice processor, set success condition + PQsetNoticeProcessor(_connection,_noticeProcessor,(__bridge void *)(self)); if([[self currentPoolOperation] poolIdentifier] == 0){ - - - mach_port_t machTID = pthread_mach_thread_np(pthread_self()); - - const char * queued_name = [[NSString stringWithFormat:@"%s_%x_%@", "operation_dispacthed_threads", machTID, NSStringFromSelector(_cmd) ] cString]; - - NSLog(@" //// %s ", queued_name); - - dispatch_queue_t queue_inRun = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); - queue_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); - - + + + mach_port_t machTID = pthread_mach_thread_np(pthread_self()); + + const char * queued_name = [[NSString stringWithFormat:@"%s_%x_%@", "operation_dispacthed_threads", machTID, NSStringFromSelector(_cmd) ] cString]; + + NSLog(@" //// %s ", queued_name); + + dispatch_queue_t queue_inRun = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); + queue_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); + + #if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) - [NSThread detachNewThreadWithBlock:^ + [NSThread detachNewThreadWithBlock:^ #else - - [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; - - dispatch_async(queue_inRun,^ + + [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; + + dispatch_async(queue_inRun,^ #endif - { - dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); - callback(usedPassword ? YES : NO,nil); - [((PGConnectionOperation*)[self masterPoolOperation]) finish]; - dispatch_semaphore_signal(ss); - - } + { + dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); + callback(usedPassword ? YES : NO,nil); + [((PGConnectionOperation*)[self masterPoolOperation]) finish]; + dispatch_semaphore_signal(ss); + + } #if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) - ] + ] #else - - ) + + ) #endif - ; -// dispatch_semaphore_wait(ss,DISPATCH_TIME_FOREVER); -// [self wait_semaphore_read:ss]; - [self wait_semaphore_read: [((PGConnectionOperation*)[self masterPoolOperation]) semaphore] withQueue:queue_inRun]; -// [((PGConnectionOperation*)[self masterPoolOperation]) validate]; - } -// dispatch_destroy(queue); - } else if(needsPassword) { - // error callback - connection not made, needs password - callback(NO,[self raiseError:nil code:PGClientErrorNeedsPassword]); - } else if(usedPassword) { - // error callback - connection not made, password was invalid - callback(YES,[self raiseError:nil code:PGClientErrorInvalidPassword]); - } else { - // error callback - connection not made, some other kind of rejection - callback(YES,[self raiseError:nil code:PGClientErrorRejected]); - } - + ; + // dispatch_semaphore_wait(ss,DISPATCH_TIME_FOREVER); + // [self wait_semaphore_read:ss]; + [self wait_semaphore_read: [((PGConnectionOperation*)[self masterPoolOperation]) semaphore] withQueue:queue_inRun]; + // [((PGConnectionOperation*)[self masterPoolOperation]) validate]; + } + // dispatch_destroy(queue); + } else if(needsPassword) { + // error callback - connection not made, needs password + callback(NO,[self raiseError:nil code:PGClientErrorNeedsPassword]); + } else if(usedPassword) { + // error callback - connection not made, password was invalid + callback(YES,[self raiseError:nil code:PGClientErrorInvalidPassword]); + } else { + // error callback - connection not made, some other kind of rejection + callback(YES,[self raiseError:nil code:PGClientErrorRejected]); + } + #if defined DEBUG && defined DEBUG2 - NSLog(@"%@ (%p) :: END :: - Read::END - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); + NSLog(@"%@ (%p) :: END :: - Read::END - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); #endif - // :: TODO :: - //:: _callback = nil; -// -// [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; -// [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; -// [self pushPoolOperation]; -} - - --(void)_socketCallbackResetEndedWithStatus:(PostgresPollingStatusType)pqstatus { - NSParameterAssert([[self currentPoolOperation] valid]); -//:: void (^callback)(NSError* error) = (__bridge void (^)(NSError* ))(_callback); - void (^callback)(NSError* error) = (__bridge void (^)(NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); - if(pqstatus==PGRES_POLLING_OK) { - callback(nil); - } else { - callback([self raiseError:nil code:PGClientErrorRejected]); - } - //:: _callback = nil; - [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; - [self setState:PGConnectionStateNone]; - [self _updateStatus]; // this also calls disconnect when rejected -} - -/** - * The connect callback will continue to poll the connection for new data. When - * the poll status is either OK or FAILED, the application's callback block is - * run. - */ --(void)_socketCallbackConnect { - // ignore this call if either connection or callback are nil - - PGConnectionOperation* currentpoolOpe = [self currentPoolOperation]; - if(_connection==nil - || ![[self currentPoolOperation] valid] - || ( [currentpoolOpe poolIdentifier]) !=0 - ) { // || (_callback==nil) // && _callbackOperation == nil) - return; - } - - PostgresPollingStatusType pqstatus = PQconnectPoll(_connection); - switch(pqstatus) { - case PGRES_POLLING_READING: - case PGRES_POLLING_WRITING: - // still connecting - ask to call poll again in runloop - [self performSelector:@selector(_socketCallbackConnect) withObject:nil afterDelay:0.1]; - break; - case PGRES_POLLING_OK: - case PGRES_POLLING_FAILED: - if(( [currentpoolOpe poolIdentifier]) ==0 && [currentpoolOpe valid] ) - { - // finished connecting -// [self performSelectorInBackground:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; -// [self performSelector:@selector(_socketCallbackConnect) withObject:nil afterDelay:0.1]; - - [self performSelector:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; - } -// [self _socketCallbackConnectEndedWithStatus:pqstatus]; - break; - default: - break; - } -} - -/** - * The reset callback is very similar to the connect callback, and could probably - * be merged with that one. - */ --(void)_socketCallbackReset { - NSParameterAssert(_connection); - - PostgresPollingStatusType pqstatus = PQresetPoll(_connection); - switch(pqstatus) { - case PGRES_POLLING_READING: - case PGRES_POLLING_WRITING: - // still connecting - call poll again - PQresetPoll(_connection); - break; - case PGRES_POLLING_OK: - case PGRES_POLLING_FAILED: - // finished connecting - [self _socketCallbackResetEndedWithStatus:pqstatus]; - break; - default: - break; - } -} - -/** - * In the case of a query being processed, this method will consume any input - * then any results from the server - */ --(void)_socketCallbackQueryRead { - NSParameterAssert(_connection); - - PQconsumeInput(_connection); - - /* it seems that we don't really need to check for busy and it seems to - * create some issues, so ignore for now */ - // check for busy, return if more to do - if(PQisBusy(_connection)) { - return; - } - -// - NSParameterAssert([[self currentPoolOperation] valid]); - - PGConnectionOperation* currentPoolOperation = [self currentPoolOperation]; - -//:: void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); - - void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); - - #if defined DEBUG && defined DEBUG2 - NSLog(@":::: PGConnectionStateQuery(%@::%p) - Read BEGIN - Result - :: callback \n_callback :: (%@)\n ********************************* ",NSStringFromClass([self class]), self , callback ); - #endif - - - // consume results - PGresult* result = nil; - while(1) { - result = PQgetResult(_connection); - if(result==nil) { + // :: TODO :: + //:: _callback = nil; + // + // [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; + // [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; + // [self pushPoolOperation]; + } + + + -(void)_socketCallbackResetEndedWithStatus:(PostgresPollingStatusType)pqstatus { + NSParameterAssert([[self currentPoolOperation] valid]); + //:: void (^callback)(NSError* error) = (__bridge void (^)(NSError* ))(_callback); + void (^callback)(NSError* error) = (__bridge void (^)(NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); + if(pqstatus==PGRES_POLLING_OK) { + callback(nil); + } else { + callback([self raiseError:nil code:PGClientErrorRejected]); + } + //:: _callback = nil; + [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; + [self setState:PGConnectionStateNone]; + [self _updateStatus]; // this also calls disconnect when rejected + } + + /** + * The connect callback will continue to poll the connection for new data. When + * the poll status is either OK or FAILED, the application's callback block is + * run. + */ + -(void)_socketCallbackConnect { + // ignore this call if either connection or callback are nil + + PGConnectionOperation* currentpoolOpe = [self currentPoolOperation]; + if(_connection==nil + || ![[self currentPoolOperation] valid] + || ( [currentpoolOpe poolIdentifier]) !=0 + ) { + // || (_callback==nil) // && _callbackOperation == nil) + return; + } + + PostgresPollingStatusType pqstatus = PQconnectPoll(_connection); + switch(pqstatus) { + case PGRES_POLLING_READING: + case PGRES_POLLING_WRITING: + // still connecting - ask to call poll again in runloop + [self performSelector:@selector(_socketCallbackConnect) withObject:nil afterDelay:0.1]; + break; + case PGRES_POLLING_OK: + case PGRES_POLLING_FAILED: + if(( [currentpoolOpe poolIdentifier]) ==0 && [currentpoolOpe valid] ) + { + // finished connecting + // [self performSelectorInBackground:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; + [self performSelector:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil afterDelay:0.1]; + +// [self performSelector:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; + } + // [self _socketCallbackConnectEndedWithStatus:pqstatus]; + break; + default: + break; + } + } + + /** + * The reset callback is very similar to the connect callback, and could probably + * be merged with that one. + */ + -(void)_socketCallbackReset { + NSParameterAssert(_connection); + + PostgresPollingStatusType pqstatus = PQresetPoll(_connection); + switch(pqstatus) { + case PGRES_POLLING_READING: + case PGRES_POLLING_WRITING: + // still connecting - call poll again + PQresetPoll(_connection); + break; + case PGRES_POLLING_OK: + case PGRES_POLLING_FAILED: + // finished connecting + [self _socketCallbackResetEndedWithStatus:pqstatus]; + break; + default: + break; + } + } + + /** + * In the case of a query being processed, this method will consume any input + * then any results from the server + */ + -(void)_socketCallbackQueryRead { + NSParameterAssert(_connection); + + PQconsumeInput(_connection); + + /* it seems that we don't really need to check for busy and it seems to + * create some issues, so ignore for now */ + // check for busy, return if more to do + if(PQisBusy(_connection)) { + return; + } + + // + NSParameterAssert([[self currentPoolOperation] valid]); + + PGConnectionOperation* currentPoolOperation = [self currentPoolOperation]; + + //:: void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); + + void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); + #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Read - Result nil - End"); + NSLog(@":::: PGConnectionStateQuery(%@::%p) - Read BEGIN - Result - :: callback \n_callback :: (%@)\n ********************************* ",NSStringFromClass([self class]), self , callback ); #endif - break; - } - NSError* error = nil; - PGResult* r = nil; - - - // check for connection errors - if(PQresultStatus(result)==PGRES_EMPTY_QUERY) { + + + // consume results + PGresult* result = nil; + while(1) { + result = PQgetResult(_connection); + if(result==nil) { #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Read - Result - Empty Query"); + NSLog(@"PGConnectionStateQuery - Read - Result nil - End"); #endif - // callback empty query - error = [self raiseError:nil code:PGClientErrorQuery reason:@"Empty query"]; - PQclear(result); - } else if(PQresultStatus(result)==PGRES_BAD_RESPONSE || PQresultStatus(result)==PGRES_FATAL_ERROR) { + break; + } + NSError* error = nil; + PGResult* r = nil; + + + // check for connection errors + if(PQresultStatus(result)==PGRES_EMPTY_QUERY) { #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Read - Result - Client Error (%s)", PQresultErrorMessage(result)); + NSLog(@"PGConnectionStateQuery - Read - Result - Empty Query"); #endif - error = [self raiseError:nil code:PGClientErrorExecute reason:[NSString stringWithUTF8String:PQresultErrorMessage(result)]]; - PQclear(result); - } else { + // callback empty query + error = [self raiseError:nil code:PGClientErrorQuery reason:@"Empty query"]; + PQclear(result); + } else if(PQresultStatus(result)==PGRES_BAD_RESPONSE || PQresultStatus(result)==PGRES_FATAL_ERROR) { #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Read - Result - READ Query RESULT (%@)",[currentPoolOperation queryString] ); + NSLog(@"PGConnectionStateQuery - Read - Result - Client Error (%s)", PQresultErrorMessage(result)); #endif - // TODO: allocate a different kind of class - r = [[PGResult alloc] initWithResult:result format:[self tupleFormat]]; + error = [self raiseError:nil code:PGClientErrorExecute reason:[NSString stringWithUTF8String:PQresultErrorMessage(result)]]; + PQclear(result); + } else { #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Read - Result - READ END (%s)", PQresultErrorMessage(result)); + NSLog(@"PGConnectionStateQuery - Read - Result - READ Query RESULT (%@)",[currentPoolOperation queryString] ); #endif + // TODO: allocate a different kind of class + r = [[PGResult alloc] initWithResult:result format:[self tupleFormat]]; #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Read - Result - Done :: (%@)", r ); + NSLog(@"PGConnectionStateQuery - Read - Result - READ END (%s)", PQresultErrorMessage(result)); #endif - } - if(r || error) { - #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery(%@::%p) - Read - Result - Done :: callback \n ********************************* \nresult :: (%@)\n ********************************* \nerror :: (%@) \n_callback :: (%@)\n ********************************* ",NSStringFromClass([self class]), self, r, error, callback ); + NSLog(@"PGConnectionStateQuery - Read - Result - Done :: (%@)", r ); #endif - // queue up callback on nearest thread - - dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); - - dispatch_async( qu_inRun ,^{ + } + if(r || error) { + #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Read - callback %p ",callback); + NSLog(@"PGConnectionStateQuery(%@::%p) - Read - Result - Done :: callback \n ********************************* \nresult :: (%@)\n ********************************* \nerror :: (%@) \n_callback :: (%@)\n ********************************* ",NSStringFromClass([self class]), self, r, error, callback ); #endif - - callback(r,error); - [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; - [((PGConnectionOperation*)[self masterPoolOperation]) validate]; - }); - - break; - } - } + // queue up callback on nearest thread + + dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); + + dispatch_async( qu_inRun ,^{ #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Read - Result - Clear " ); + NSLog(@"PGConnectionStateQuery - Read - callback %p ",callback); #endif - // all results consumed - update state - [self setState:PGConnectionStateNone]; - -//:: _callback = nil; // release the callback - [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; -// [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; - - [self _updateStatus]; + + callback(r,error); + [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; + [((PGConnectionOperation*)[self masterPoolOperation]) validate]; + }); + + break; + } + } #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Read END - Result - Clear::End " ); + NSLog(@"PGConnectionStateQuery - Read - Result - Clear " ); #endif - _stateOperation = PGOperationStateNone; -} - -/** - * In the case of a query being processed, this method will consume any input - * flush the connection and consume any results which are being processed. - */ --(void)_socketCallbackQueryWrite { - NSParameterAssert(_connection); - // flush - int returnCode = PQflush(_connection); - if(returnCode==-1) { - // callback with error - NSParameterAssert([[self currentPoolOperation] valid]); -//:: void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); - void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); - NSError* error = [self raiseError:nil code:PGClientErrorState reason:@"Data flush failed during query"]; - callback(nil,error); - } -} - -/** - * This method is called from _socketCallback and depending on the - * current state of the connection, it will call the connect, reset, query - * or notification socket callback - */ --(void)_socketCallback:(CFSocketCallBackType)callBackType { - @try{ + // all results consumed - update state + [self setState:PGConnectionStateNone]; + + //:: _callback = nil; // release the callback + [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; + // [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; + + [self _updateStatus]; #if defined DEBUG && defined DEBUG2 - switch(callBackType) { - case kCFSocketReadCallBack: - NSLog(@"kCFSocketReadCallBack"); - break; - case kCFSocketAcceptCallBack: - NSLog(@"kCFSocketAcceptCallBack"); - break; - case kCFSocketDataCallBack: - NSLog(@"kCFSocketDataCallBack"); - break; - case kCFSocketConnectCallBack: - NSLog(@"kCFSocketConnectCallBack"); - break; - case kCFSocketWriteCallBack: - NSLog(@"kCFSocketWriteCallBack"); - break; - default: - NSLog(@"CFSocketCallBackType OTHER"); - break; - } + NSLog(@"PGConnectionStateQuery - Read END - Result - Clear::End " ); #endif - PGConnectionState state_on = [self state]; - switch(state_on) { - case PGConnectionStateConnect: + _stateOperation = PGOperationStateNone; + } + + /** + * In the case of a query being processed, this method will consume any input + * flush the connection and consume any results which are being processed. + */ + -(void)_socketCallbackQueryWrite { + NSParameterAssert(_connection); + // flush + int returnCode = PQflush(_connection); + if(returnCode==-1) { + // callback with error + NSParameterAssert([[self currentPoolOperation] valid]); + //:: void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); + void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); + NSError* error = [self raiseError:nil code:PGClientErrorState reason:@"Data flush failed during query"]; + callback(nil,error); + } + } + + /** + * This method is called from _socketCallback and depending on the + * current state of the connection, it will call the connect, reset, query + * or notification socket callback + */ + -(void)_socketCallback:(CFSocketCallBackType)callBackType { + @try{ #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateConnect"); + switch(callBackType) { + case kCFSocketReadCallBack: + NSLog(@"kCFSocketReadCallBack"); + break; + case kCFSocketAcceptCallBack: + NSLog(@"kCFSocketAcceptCallBack"); + break; + case kCFSocketDataCallBack: + NSLog(@"kCFSocketDataCallBack"); + break; + case kCFSocketConnectCallBack: + NSLog(@"kCFSocketConnectCallBack"); + break; + case kCFSocketWriteCallBack: + NSLog(@"kCFSocketWriteCallBack"); + break; + default: + NSLog(@"CFSocketCallBackType OTHER"); + break; + } #endif - [self _socketCallbackConnect]; - break; - case PGConnectionStateReset: + PGConnectionState state_on = [self state]; + switch(state_on) { + case PGConnectionStateConnect: #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateReset"); + NSLog(@"PGConnectionStateConnect"); #endif - [self _socketCallbackReset]; - break; - case PGConnectionStateQuery: - if(callBackType==kCFSocketReadCallBack) { + [self _socketCallbackConnect]; + break; + case PGConnectionStateReset: #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Read - _socketCallback :: _socketCallbackQueryRead :: callback (%p)",[[self currentPoolOperation] getCallback]); + NSLog(@"PGConnectionStateReset"); #endif -//:: _callback = _callbackOperation; -// _callback = [self currentPoolOperation]; - [self _socketCallbackQueryRead]; + [self _socketCallbackReset]; + break; + case PGConnectionStateQuery: + if(callBackType==kCFSocketReadCallBack) { #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Read - _socketCallback :: _socketCallbackNotification :: callback (%p)", [[self currentPoolOperation] getCallback]); + NSLog(@"PGConnectionStateQuery - Read - _socketCallback :: _socketCallbackQueryRead :: callback (%p)",[[self currentPoolOperation] getCallback]); #endif - [self _socketCallbackNotification]; - } else if(callBackType==kCFSocketWriteCallBack) { + [self _socketCallbackQueryRead]; #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateQuery - Write"); + NSLog(@"PGConnectionStateQuery - Read - _socketCallback :: _socketCallbackNotification :: callback (%p)", [[self currentPoolOperation] getCallback]); #endif - [self _socketCallbackQueryWrite]; - } - break; - default: + [self _socketCallbackNotification]; + + } else if(callBackType==kCFSocketWriteCallBack) { #if defined DEBUG && defined DEBUG2 - NSLog(@"PGConnectionStateOther"); + NSLog(@"PGConnectionStateQuery - Write"); #endif - [self _socketCallbackNotification]; - break; - } - - [self _updateStatus]; - } - @catch (NSException *exception) { - NSLog(@" %@ exeception .... %@",NSStringFromSelector(_cmd),exception); - } - @finally { - - } -} - -@end - - - + [self _socketCallbackQueryWrite]; + } + break; + default: +#if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateOther"); +#endif + [self _socketCallbackNotification]; + break; + } + + [self _updateStatus]; + } + @catch (NSException *exception) { + NSLog(@" %@ exeception .... %@",NSStringFromSelector(_cmd),exception); + } + @finally { + + } + } + + @end + + + diff --git a/src/Frameworks/PGClientKit/PGConnection+Connect.m b/src/Frameworks/PGClientKit/PGConnection+Connect.m index 43c45c8..aba2175 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Connect.m +++ b/src/Frameworks/PGClientKit/PGConnection+Connect.m @@ -168,6 +168,9 @@ -(void)connectWithURL:(NSURL* )url whenDone:(void(^)(BOOL usedPassword,NSError* // dispatch_async(dispatch_get_current_queue(),^ #endif { +#if defined DEBUG && defined DEBUG2 + NSLog(@" ------- %@ :: %@ :::: Connection Started ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); +#endif [self _socketConnect:PGConnectionStateConnect]; // CFRunLoopRun(); // [self performSelector:@selector(_waitingPoolOperationForResult) withObject:self ]; @@ -185,9 +188,7 @@ -(void)connectWithURL:(NSURL* )url whenDone:(void(^)(BOOL usedPassword,NSError* // ) #endif ; -#if defined DEBUG && defined DEBUG2 - NSLog(@" ------- %@ :: %@ :::: Connection Started ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); -#endif + } -(BOOL)connectWithURL:(NSURL* )url usedPassword:(BOOL* )usedPassword error:(NSError** )error { diff --git a/src/Frameworks/PGClientKit/PGConnection+Errors.m b/src/Frameworks/PGClientKit/PGConnection+Errors.m index 9024181..997f79b 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Errors.m +++ b/src/Frameworks/PGClientKit/PGConnection+Errors.m @@ -74,23 +74,17 @@ -(void)_raiseError:(NSError* )error { #endif // [[self delegate] connection:self error:error]; // @{@"connection":self, @"error":error} -#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) - [NSThread detachNewThreadWithBlock: -#else - dispatch_async(dispatch_get_main_queue(), -#endif -^{ +// dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); +// dispatch_barrier_sync(qu_inRun, ^ { [[self delegate] connection:self error:error]; -} -#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) -]; -#else -); +// [NSThread detachNewThreadSelector:@selector(connection:error:) toTarget:[self delegate] withObject:@{@"connection":self, @"error":error} ]; + #if defined DEBUG && defined DEBUG2 + NSLog(@"PGConnectionStateQuery - _raiseError :: send to delegate connection:error: END" ); #endif - -// [NSThread detachNewThreadSelector:@selector(connection:error:) toTarget:[self delegate] withObject:nil ]; - }else{ +//} ); + + }else{ #if defined DEBUG && defined DEBUG2 NSLog(@"PGConnectionStateQuery - _raiseError :: no delegate respondsto connection:error:" ); #endif @@ -116,7 +110,10 @@ -(NSError* )raiseError:(NSError** )error code:(PGClientErrorDomainCode)code reas #if defined DEBUG && defined DEBUG2 NSLog(@"PGConnectionStateQuery - _raiseError :: performSelectorOnMainThread :: (%@)", theError ); #endif - // [self performSelectorOnMainThread:@selector(_raiseError:) withObject:theError waitUntilDone:YES]; + + +// [self performSelectorOnMainThread:@selector(_raiseError:) withObject:theError waitUntilDone:YES]; + [self _raiseError:theError]; }else{ #if defined DEBUG && defined DEBUG2 diff --git a/src/Frameworks/PGClientKit/PGConnection+Execute.m b/src/Frameworks/PGClientKit/PGConnection+Execute.m index 4a91bdd..2c27ea3 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Execute.m +++ b/src/Frameworks/PGClientKit/PGConnection+Execute.m @@ -25,53 +25,6 @@ #import #import -#import -#import -#import - - - -#define INVALID_SOCKET (CFSocketNativeHandle)(-1) - -#define closesocket(a) close((a)) -#define ioctlsocket(a,b,c) ioctl((a),(b),(c)) - -CF_INLINE Boolean __CFSocketIsValid(CFSocketRef s); - -static CFStringRef __CFFSocketCopyDescription(CFTypeRef cf) { - CFSocketRef sock = (CFSocketRef)cf; - CFStringRef contextDesc = NULL; - if (NULL != sock->_context.info && NULL != sock->_context.copyDescription) { - contextDesc = sock->_context.copyDescription(sock->_context.info); - } - if (NULL == contextDesc) { - contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR(""), sock->_context.info); - } - Dl_info info; - void *addr = sock->_callout; - const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; - int avail = -1; - ioctlsocket(sock->_shared ? sock->_shared->_socket : -1, FIONREAD, &avail); - CFStringRef result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR( - "{valid = %s, socket = %d, " - "want connect = %s, connect disabled = %s, " - "want write = %s, reenable write = %s, write disabled = %s, " - "want read = %s, reenable read = %s, read disabled = %s, " - "leave errors = %s, close on invalidate = %s, connected = %s, " - "last error code = %d, bytes available for read = %d, " - "source = %p, callout = %s (%p), context = %@}"), - cf, CFGetAllocator(sock), (sock) ? "Yes" : "No", sock->_shared ? sock->_shared->_socket : -1, - sock->_wantConnect ? "Yes" : "No", sock->_connectDisabled ? "Yes" : "No", - sock->_wantWrite ? "Yes" : "No", sock->_reenableWrite ? "Yes" : "No", sock->_writeDisabled ? "Yes" : "No", - sock->_wantReadType ? "Yes" : "No", sock->_reenableRead ? "Yes" : "No", sock->_readDisabled? "Yes" : "No", - sock->_leaveErrors ? "Yes" : "No", sock->_closeOnInvalidate ? "Yes" : "No", sock->_connected ? "Yes" : "No", - sock->_error, avail, - sock->_shared ? sock->_shared->_source : NULL, name, addr, contextDesc); - if (NULL != contextDesc) { - CFRelease(contextDesc); - } - return result; -} @implementation PGConnection (Execute) //////////////////////////////////////////////////////////////////////////////// @@ -148,24 +101,21 @@ -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGR #endif } - // // set state, update status - // [self setState:PGConnectionStateQuery]; - // - // [self _updateStatus]; - -#if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %@ :: - execute - RETURN :: callback %p :: %p ", NSStringFromSelector(_cmd),NSStringFromClass([self class]), callback, _callbackOperation); -#endif NSParameterAssert(callback!=nil); - _callbackOperation = (__bridge_retained void* )[callback copy]; + // _callbackOperation = (__bridge_retained void* )[callback copy]; // if([self currentPoolOperation] != nil) [[self currentPoolOperation] invalidate]; [self addOperation:query withCallBackWhenDone: (__bridge_retained void* )callback withCallBackWhenError: (__bridge_retained void* )callback ]; - NSParameterAssert(_callbackOperation!=nil); + +#if defined DEBUG && defined DEBUG2 + NSLog(@"%@ :: %@ :: - execute - RETURN :: callback %p :: %p ", NSStringFromSelector(_cmd),NSStringFromClass([self class]), callback, _callbackOperation); +#endif + + // NSParameterAssert(_callbackOperation!=nil); // [NSThread sleepForTimeInterval: .2]; } @@ -176,261 +126,69 @@ -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGR -(void)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) callback { - - // if([((PGConnectionOperation*)[self currentPoolOperation]) valid]) - // if([((PGConnectionOperation*)[self currentPoolOperation]) poolIdentifier] !=0 ){ - - // [NSThread detachNewThreadSelector:_cmd toTarget:self withObject:nil ]; - // if([((PGConnectionOperation*)[self currentPoolOperation]) poolIdentifier] !=0 ) + NSParameterAssert([query isKindOfClass:[NSString class]] || [query isKindOfClass:[PGQuery class]]); + NSParameterAssert(callback); _stateOperation = PGOperationStatePrepare; - - // } - // dispatch_queue_t queue_inRun = ( ( dispatch_get_current_queue() == dispatch_get_main_queue() )? dispatch_get_main_queue() : dispatch_get_current_queue() ); - mach_port_t machTID = pthread_mach_thread_np(pthread_self()); - NSString * queued_name_STR = [NSString stringWithFormat:@"%s_%x", "query_operation_dispacthed_threads", machTID ]; + // mach_port_t machTID = pthread_mach_thread_np(pthread_self()); + NSString * queued_name_STR = [NSString stringWithFormat:@"%s_%ld :: %@", "query_operation_dispacthed_threads", (long)[self connectionPoolOperationCount], [NSThread currentThread] ]; const char * queued_name = [queued_name_STR UTF8String]; - NSLog(@" //// Query dispatch :: %@ ", queued_name_STR); + NSLog(@" //// -_-_-_-_ Query Dispatch START -_-_-_-_- :: %@ ", queued_name_STR); dispatch_queue_t queue_inRun = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); -#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) - [NSThread detachNewThreadWithBlock:^ -#else - - - // dispatch_barrier_sync(queue_inRun,^ + NSString* query2 = nil; + NSError* error = nil; + if([query isKindOfClass:[NSString class]]) { + query2 = query; + } else { + query2 = [(PGQuery* )query quoteForConnection:self error:&error]; + } + if(error) { +#if defined DEBUG && defined DEBUG2 + NSLog(@"%@ :: %@ - query ERROR - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); #endif - - { - // [self performSelectorOnMainThread:@selector(_waitingPoolOperationForResult) withObject:self waitUntilDone:YES ]; - - - NSParameterAssert([query isKindOfClass:[NSString class]] || [query isKindOfClass:[PGQuery class]]); - NSParameterAssert(callback); - NSString* query2 = nil; - NSError* error = nil; - if([query isKindOfClass:[NSString class]]) { - query2 = query; - } else { - query2 = [(PGQuery* )query quoteForConnection:self error:&error]; - } - if(error) { + callback(nil,error); + } else if(query2==nil) { + callback(nil,[self raiseError:nil code:PGClientErrorExecute reason:@"Query is nil"]); + } else { #if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %@ - query ERROR - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); + NSLog(@"%@ :: %@ - query - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); #endif - callback(nil,error); - } else if(query2==nil) { - callback(nil,[self raiseError:nil code:PGClientErrorExecute reason:@"Query is nil"]); - } else { + void (^callback_recall)(PGResult* result,NSError* error) = ^(PGResult* result_recall ,NSError* error_recall) + { #if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %@ - query - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); + NSLog(@" .... semaphore callback..... %@", [[self currentPoolOperation] semaphore]); #endif - void (^callback_recall)(PGResult* result,NSError* error) = ^(PGResult* result_recall ,NSError* error_recall) - { - NSLog(@" .... semaphore callback..... "); - callback(result_recall , error_recall); - NSLog(@" .... semaphore pass ..... "); -// dispatch_semaphore_signal( [[self currentPoolOperation] semaphore] ); - NSLog(@" .... semaphore signal end ..... "); - - }; - // dispatch_semaphore_signal(semaphore_query_send); - [self _execute:query2 values:nil whenDone: callback_recall]; - - } - } - -#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) - ] -#else - - // ) + + callback(result_recall , error_recall); + +#if defined DEBUG && defined DEBUG2 + NSLog(@" .... semaphore pass ..... "); + // dispatch_semaphore_signal( [[self currentPoolOperation] semaphore] ); + NSLog(@" .... semaphore signal end ..... %@", [[self currentPoolOperation] semaphore]); #endif - ; + + }; + // dispatch_semaphore_signal(semaphore_query_send); + [self _execute:query2 values:nil whenDone: callback_recall]; + + } - // [self performSelector:@selector(_waitingPoolOperationForResult) withObject:self ]; - // [self performSelector:@selector(_waitingPoolOperationForResultMaster) withObject:self ]; _stateOperation = PGOperationStateBusy; -// [NSThread sleepForTimeInterval:.2]; + // [NSThread sleepForTimeInterval:.2]; dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); - NSLog(@"Is main queue? : %d", qu_inRun == dispatch_get_main_queue()); - - - + // NSLog(@"+++ Is main queue? : %d", qu_inRun == dispatch_get_main_queue()); dispatch_semaphore_t semaphore_query_send = [[self currentPoolOperation] semaphore]; [self wait_semaphore_read: semaphore_query_send withQueue:queue_inRun]; - - NSLog(@"I will see this, after dispatch_semaphore_signal is called"); -} --(void)wait_semaphore_read:(dispatch_semaphore_t) sem { - dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); - dispatch_barrier_sync(qu_inRun, ^{ - [self wait_semaphore_read:sem withQueue:nil]; - }); - -} --(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_t)qq_in { - - mach_port_t machTID = pthread_mach_thread_np(pthread_self()); - - NSString *queued_name_STR = [NSString stringWithFormat:@"%@_%x :: %s :: %@ ", NSStringFromSelector(_cmd), machTID, - - dispatch_queue_get_label(dispatch_get_main_queue()), - sem ]; - const char * queued_name = [queued_name_STR UTF8String]; - - NSLog(@" //// Start :: %@ ", queued_name_STR); - - - // dispatch_barrier_async(dispatch_get_current_queue(), ^{ - - // NSLog(@" //// Start **** :: %s ", queued_name); - long diispacthed = YES; - - NSTimeInterval resolutionTimeOut = 0.05; - NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; - bool isRunningThreadMain = YES; - bool isRunningThread = YES; - - - - // dispatch_async(((qq_in)?qq_in : dispatch_get_main_queue()), ^{ - // - // bool isRunningThreadMain = YES; - // bool isRunningThread = YES; - // - // CFRunLoopSourceSignal(_runloopsource); - // CFRunLoopWakeUp(CFRunLoopGetMain()); - // - // - // isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; - // if(!isRunningThreadMain) - // { - // [NSThread sleepForTimeInterval:.01];; - // } - // - // isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; - // if(!isRunningThreadMain) - // { - // [NSThread sleepForTimeInterval:.01];; - // } - // - // CFRunLoopSourceSignal(_runloopsource); - // CFRunLoopWakeUp(CFRunLoopGetCurrent()); - // - // - // isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; - // if(!isRunningThread) - // { - // [NSThread sleepForTimeInterval:.01];; - // } - // - // isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; - // if(!isRunningThread) - // { - // [NSThread sleepForTimeInterval:.01];; - // } - // - // }); - bool PG_busy = YES; - - // if([[self currentPoolOperation] poolIdentifier] == 0) - while( diispacthed && _runloopsource && _socket ) - { - - - PG_busy = PQisBusy(_connection); - diispacthed = dispatch_semaphore_wait(sem,5UL); - // dispatch_queue_t qq_qq = dispatch_get_current_queue(); - dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); - - // [self performSelector:@selector(dispathCall) withObject:nil afterDelay:.1 inModes:[NSArray arrayWithObjects: kCFRunLoopCommonModes, kCFRunLoopDefaultMode, nil]]; - if([[self currentPoolOperation] poolIdentifier] == 0) - { -// dispatch_barrier_sync(qu_inRun, ^{ -if([[self currentPoolOperation] valid] && [[self currentPoolOperation] getCallback]) - [self performSelector:@selector(dispathCall) withObject:nil]; -// }); - // - // - // [self performSelectorInBackground:@selector(dispathCall) withObject:self]; - - [NSThread sleepForTimeInterval:.5]; - }else{ - - // [self performSelectorOnMainThread:@selector(dispathCall) withObject:self waitUntilDone:YES modes:@[NSRunLoopCommonModes, NSDefaultRunLoopMode] ]; - // [self performSelectorInBackground:@selector(dispathCall) withObject:self]; - // [self performSelector:@selector(dispathCall) withObject:nil]; -// isRunningThreadMain = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; - [self performSelector:@selector(dispathCall) withObject:nil]; - [NSThread sleepForTimeInterval:.5]; - if(!PG_busy) - break; - - } - -// id shared_info = (__bridge id)(_socket); -// CFSocketCallBack shared_info_shared = (_socket->_callout); -// const char * class_named = object_getClassName(shared_info); -// -// CFSocketNativeHandle sock = CFSocketGetNative(_socket); -// -// struct __shared_blob *shared_dd = malloc(sizeof(struct __shared_blob)); - - // NSLog(@"%s", __CFFSocketCopyDescription(_socket)); - - // shared_dd->_rdsrc = (_socket->_shared)->_rdsrc; - // shared_dd->_wrsrc = (_socket->_shared)->_wrsrc; - // shared_dd->_source = (_socket->_shared)->_source; - // shared_dd->_socket = (_socket->_shared)->_socket; - // shared_dd->_closeFD = (_socket->_shared)->_closeFD ; - // shared_dd->_refCnt = (_socket->_shared)->_refCnt; - - // objc_mem(&shared_dd, *(_socket->_shared) , sizeof(struct __shared_blob)); - -// unsigned int outCount, i; -// objc_property_t *objcProperties = class_copyPropertyList([shared_info class], &outCount); -// for (i = 0; i < outCount; i++) { -// objc_property_t property = objcProperties[i]; -// const char *propName = property_getName(property); -// if(propName) { -// // const char * propType = getPropertyType(property); -// NSString * propertyName = [NSString stringWithUTF8String:propName]; -// -// } -// } -// - // [((NSObject*)shared_info) shared]; -// id sockk = (__bridge id)((_socket)->_shared); - - // typedef struct __CFSocket sockt; - // - // dispatch_object_t disp_obj = (dispatch_object_t) ((shared_info*)->_shared->_rdsrc); - // dispatch_resume( ((dispatch_object_t) disp_obj) );; - if( diispacthed && !isRunningThreadMain && !isRunningThreadMain - && [[self currentPoolOperation] valid] - ) - [NSThread sleepForTimeInterval:.01]; - - // if( diispacthed - //// && !isRunningThreadMain && !isRunningThreadMain - // && [[self currentPoolOperation] valid] - // && [self connectionPoolOperationCount] > 1 - // && ! PG_busy ) - // break; - if([self status] == PGConnectionStatusDisconnected || ! _connection) break; - } - - NSLog(@" //// Clean **** :: %s ", queued_name); - // }); - // - [[NSThread currentThread] cancel]; - NSLog(@" //// END :: %s ", queued_name); +#if defined DEBUG && defined DEBUG2 + NSLog(@" -_-_-_-_ Query END -_-_-_-_- :: %@ ", queued_name_STR); +#endif + _stateOperation = PGOperationStateNone; } -(PGResult* )execute:(id)query error:(NSError** )error { @@ -446,75 +204,7 @@ -(PGResult* )execute:(id)query error:(NSError** )error { dispatch_semaphore_wait(s,DISPATCH_TIME_FOREVER); return result; } --(void)dispathCall -{ - // dispatch_async(dispatch_get_current_queue(), ^{ - NSTimeInterval resolutionTimeOut = 0.05; - NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; - bool isRunningThreadMain = YES; - bool isRunningThread = YES; - if([self status] == PGConnectionStatusDisconnected || ! _connection) return; -// while( _runloopsource && ( isRunningThreadMain || isRunningThread ) ) - { - if(_runloopsource){ - CFRunLoopSourceSignal(_runloopsource); - } - CFRunLoopWakeUp(CFRunLoopGetMain()); - - - - - if(_runloopsource){ - CFRunLoopSourceSignal(_runloopsource); - } - CFRunLoopWakeUp(CFRunLoopGetCurrent()); - - - isRunningThread = [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes beforeDate:theNextDate]; - if(!isRunningThread) - { - [NSThread sleepForTimeInterval:.01];; - } - dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); - NSRunLoop *qq_loop = [NSRunLoop currentRunLoop]; - NSRunLoop *qq_loop_main = [NSRunLoop mainRunLoop]; - if( qq_loop != [NSRunLoop mainRunLoop]){ - if([[self currentPoolOperation] poolIdentifier] == 0 ){ - [qq_loop runUntilDate:theNextDate]; - }else{ - [self performSelectorOnMainThread:@selector(dispathCall) withObject:self waitUntilDone:YES modes:@[NSRunLoopCommonModes, NSDefaultRunLoopMode] ]; - NSLog(@" END performSelectorOnMainThread :: %@", NSStringFromSelector(_cmd)); - } - } - if([[self currentPoolOperation] poolIdentifier] == 0 && [[self currentPoolOperation] valid]){ -// dispatch_async(dispatch_get_main_queue(), ^{ -// isRunningThread = [qq_loop runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; -// if(!isRunningThread) -// { -// bool isRunningThreadMain = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; - if(!isRunningThread){ - [qq_loop runUntilDate:theNextDate]; - - - - - }else{ - [qq_loop_main runUntilDate:theNextDate]; - } -// } -// }); - - - }else if([[self currentPoolOperation] poolIdentifier] != 0 && [[self currentPoolOperation] valid]){ - [qq_loop runUntilDate:theNextDate]; - [qq_loop_main runUntilDate:theNextDate]; - } - [NSThread sleepForTimeInterval:.01];; - } - // }); - -} -(void)_queue:(PGTransaction* )transaction index:(NSUInteger)i lastResult:(PGResult* )result lastError:(NSError* )error whenQueryDone:(void(^)(PGResult* result,BOOL isLastQuery,NSError* error)) callback { if(error) { // rollback @@ -589,6 +279,188 @@ -(void)queue:(PGTransaction* )transaction whenQueryDone:(void(^)(PGResult* resul } } + + +#pragma mark -------- Sync Thread and Semaphores +-(void)wait_semaphore_read:(dispatch_semaphore_t) sem { + dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); + + NSRunLoop *qq_loop = [NSRunLoop currentRunLoop]; + NSRunLoop *qq_loop_main = [NSRunLoop mainRunLoop]; + + + if( qq_loop != [NSRunLoop mainRunLoop]){ + + dispatch_barrier_sync(qu_inRun, ^{ + [self wait_semaphore_read:sem withQueue:nil]; + }); + }else{ +// dispatch_barrier_async(qu_inRun, ^{ + [self wait_semaphore_read:sem withQueue:nil]; +// }); + } + +} +-(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_t)qq_in { + + // mach_port_t machTID = pthread_mach_thread_np(pthread_self()); + + NSString *queued_name_STR = [NSString stringWithFormat:@"%@_%ld :: %s :: %@ ", NSStringFromSelector(_cmd), (long)[self connectionPoolOperationCount], + dispatch_queue_get_label(dispatch_get_main_queue()), + sem ]; + + // const char * queued_name = [queued_name_STR UTF8String]; +#if defined DEBUG && defined DEBUG2 + NSLog(@" //// Start :: %@ ", queued_name_STR); +#endif + // NSLog(@" //// Start **** :: %s ", queued_name); + + long diispacthed = YES; + + bool PG_busy = YES; + + while( + diispacthed + && _runloopsource + && _socket + && _connection ) + { + + + PG_busy = PQisBusy(_connection); + diispacthed = dispatch_semaphore_wait(sem,DISPATCH_TIME_NOW); + + if( nil == [[self currentPoolOperation] getCallback] || !diispacthed){ + [NSThread sleepForTimeInterval:.01]; + break; + } + + [NSThread sleepForTimeInterval:.01]; + + + if([[self currentPoolOperation] valid] ) + { +#if defined DEBUG && defined DEBUG2 + NSLog(@" //// STEP :: %@ ", queued_name_STR); +#endif + [self performSelector:@selector(dispathCall) withObject:nil]; + }else{ + break; + } + + if( diispacthed && ![[self currentPoolOperation] valid] ) + [NSThread sleepForTimeInterval:.01]; + + // if( diispacthed + //// && !isRunningThreadMain && !isRunningThreadMain + // && [[self currentPoolOperation] valid] + // && [self connectionPoolOperationCount] > 1 + // && ! PG_busy ) + // break; + + PGConnectionStatus con_status = [((PGConnection*)self) status]; + if( con_status == PGConnectionStatusDisconnected || ! _connection) + break; + } +#if defined DEBUG && defined DEBUG2 + NSLog(@" //// Clean **** :: %@ ", queued_name_STR); +#endif + [[NSThread currentThread] cancel]; +#if defined DEBUG && defined DEBUG2 + NSLog(@" //// END :: %@ ", queued_name_STR); +#endif + +} + +-(void)dispathCall +{ + + NSTimeInterval resolutionTimeOut = 0.05; + NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; + bool isRunningThreadMain = YES; + bool isRunningThread = YES; + + [NSThread sleepForTimeInterval:.01];; + PGConnectionStatus con_status = [((PGConnection*)self) status]; + if( + ( + con_status != PGConnectionStatusBusy && + con_status != PGConnectionStatusConnected && + con_status != PGConnectionStatusConnecting + + ) + || ! _connection || !_socket) + return; + + { + if(_runloopsource){ + CFRunLoopSourceSignal(_runloopsource); + }else{ + return; + } + + CFRunLoopWakeUp(CFRunLoopGetMain()); + + if(_runloopsource){ + CFRunLoopSourceSignal(_runloopsource); + } + + CFRunLoopWakeUp(CFRunLoopGetCurrent()); + + dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); + dispatch_queue_t qu_inRun_main = dispatch_get_main_queue(); + + NSRunLoop *qq_loop = [NSRunLoop currentRunLoop]; + NSRunLoop *qq_loop_main = [NSRunLoop mainRunLoop]; + + isRunningThread = [qq_loop runMode:NSRunLoopCommonModes beforeDate:theNextDate]; + if(!isRunningThread) + { + [NSThread sleepForTimeInterval:.1];; + } + + if( qq_loop != [NSRunLoop mainRunLoop]){ + if([[self currentPoolOperation] poolIdentifier] == 0 ){ + [qq_loop runUntilDate:theNextDate]; + if(!isRunningThread){ + [qq_loop_main runUntilDate:theNextDate]; + [NSThread sleepForTimeInterval:.1];; + } + +// [qq_loop_main runUntilDate:theNextDate]; +// +// isRunningThread = [qq_loop_main runMode:NSRunLoopCommonModes beforeDate:theNextDate]; +// if(!isRunningThread) +// { +// [NSThread sleepForTimeInterval:.1];; +// [self performSelectorOnMainThread:@selector(dispathCall) withObject:self waitUntilDone:YES modes:@[NSRunLoopCommonModes, NSDefaultRunLoopMode] ]; +// } +// + }else{ + + { + [qq_loop_main runUntilDate:theNextDate]; + [qq_loop runUntilDate:theNextDate]; + + } +#if defined DEBUG && defined DEBUG2 + NSLog(@" END performSelectorOnMainThread :: %@", NSStringFromSelector(_cmd)); +#endif + return; // don t care + } + }else + if([[self currentPoolOperation] valid]) + { + if(!isRunningThread){ + [qq_loop runUntilDate:theNextDate]; + }else{ + [qq_loop_main runUntilDate:theNextDate]; + } + } + + } +} + @end diff --git a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m index f59fc1b..01cc579 100644 --- a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m +++ b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m @@ -328,7 +328,7 @@ -(void)_socketConnect:(PGConnectionState)state { [self wait_semaphore_read: semaphore_query_send ]; - + [[NSThread currentThread] cancel]; // CFRunLoopRun();//(kCFRunLoopDefaultMode, 0.2 , NO); #if defined DEBUG && defined DEBUG2 NSLog(@" ------- %@ :: %@ :::: Socket Runloop ENDED CLEAR ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); diff --git a/src/Frameworks/PGClientKit/PGConnectionOperation.m b/src/Frameworks/PGClientKit/PGConnectionOperation.m index 21eca94..e71af60 100644 --- a/src/Frameworks/PGClientKit/PGConnectionOperation.m +++ b/src/Frameworks/PGClientKit/PGConnectionOperation.m @@ -68,7 +68,8 @@ -(instancetype)initWithParametersDelegate:(id)connectionDelegate withRefPoolIden } -(bool)valid { - return (_callbackWhenDone == nil) ? false : !_invalidated ; + bool ret_valid = (_callbackWhenDone == nil) ? false : !_invalidated ; + return ret_valid; } -(void)finish { From 9efc909c654438a4db655c390745e7345315267b Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Tue, 8 Aug 2017 18:08:03 +0200 Subject: [PATCH 11/21] Some Debug Cleaning --- postgresql-kit.xcodeproj/project.pbxproj | 4 +- .../PGClientKit/PGConnection+Callbacks.m | 122 +++++++++--------- .../PGClientKit/PGConnection+Connect.m | 4 +- .../PGClientKit/PGConnection+Errors.m | 12 +- .../PGClientKit/PGConnection+Execute.m | 86 ++++++------ .../PGConnection+PGConnectionSocket.m | 4 +- src/Frameworks/PGClientKit/PGConnection.m | 15 ++- .../PGClientKit/PGConnectionOperation.m | 4 + 8 files changed, 128 insertions(+), 123 deletions(-) diff --git a/postgresql-kit.xcodeproj/project.pbxproj b/postgresql-kit.xcodeproj/project.pbxproj index aa89a05..98d006e 100644 --- a/postgresql-kit.xcodeproj/project.pbxproj +++ b/postgresql-kit.xcodeproj/project.pbxproj @@ -2868,8 +2868,8 @@ CLANG_ENABLE_OBJC_ARC = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG2=1", - "DEBUG=1", + "DEBUG2=0", + "DEBUG=0", ); ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "-I/usr/local/include"; diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index 8ded71a..173effa 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -38,30 +38,30 @@ */ static int socketUsed_in = 0; void _socketCallback(CFSocketRef s, CFSocketCallBackType callBackType,CFDataRef address,const void* data,void* __self) { - + [NSThread sleepForTimeInterval:.01];; - + PGConnection* connection = (PGConnection* ) ((__bridge PGConnection* )__self); if(! connection -// || socketUsed_in > 20 + // || socketUsed_in > 20 ) return ; socketUsed_in ++; -// dispatch_barrier_async(dispatch_get_main_queue(), ^{ -#if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %s :::: Socket CALL ... %lu ", NSStringFromClass([((__bridge NSObject *)__self) class]), (__FUNCTION__), callBackType); + // dispatch_barrier_async(dispatch_get_main_queue(), ^{ +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 + NSLog(@"%@ :: %s :::: Socket CALL ... %lu ", NSStringFromClass([((__bridge NSObject *)__self) class]), (__FUNCTION__), callBackType); #endif - [((PGConnection* )connection) _socketCallback:callBackType]; -#if defined DEBUG && defined DEBUG2 - NSLog(@"%@ :: %s :::: Socket CALL END .... (%lu) ", NSStringFromClass([((__bridge NSObject *)__self) class]), (__FUNCTION__), callBackType); + [((PGConnection* )connection) _socketCallback:callBackType]; +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 + NSLog(@"%@ :: %s :::: Socket CALL END .... (%lu) ", NSStringFromClass([((__bridge NSObject *)__self) class]), (__FUNCTION__), callBackType); #endif - socketUsed_in = 0; -// }); + socketUsed_in = 0; + // }); + + // [NSThread sleepForTimeInterval:.1];; -// [NSThread sleepForTimeInterval:.1];; - } /** @@ -91,7 +91,7 @@ -(void)_socketCallbackNotification { // consume input PQconsumeInput(_connection); -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: loop "); #endif @@ -99,7 +99,7 @@ -(void)_socketCallbackNotification { PGnotify* notify = nil; while((notify = PQnotifies(_connection)) != nil) { if([[self delegate] respondsToSelector:@selector(connection:notificationOnChannel:payload:)]) { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: call delegate (%@) (%@)", [self delegate], NSStringFromSelector(@selector(connection:notificationOnChannel:payload:))); #endif @@ -109,7 +109,7 @@ -(void)_socketCallbackNotification { } PQfreemem(notify); } -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: free "); #endif } @@ -135,7 +135,7 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus BOOL needsPassword = PQconnectionNeedsPassword(_connection) ? YES : NO; BOOL usedPassword = PQconnectionUsedPassword(_connection) ? YES : NO; -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"%@ (%p) :: BEGIN :: - Read::BEGIN - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); #endif // update the status @@ -153,9 +153,9 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus mach_port_t machTID = pthread_mach_thread_np(pthread_self()); const char * queued_name = [[NSString stringWithFormat:@"%s_%x_%@", "operation_dispacthed_threads", machTID, NSStringFromSelector(_cmd) ] cString]; - +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" //// %s ", queued_name); - +#endif dispatch_queue_t queue_inRun = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); queue_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); @@ -199,7 +199,7 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus callback(YES,[self raiseError:nil code:PGClientErrorRejected]); } -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"%@ (%p) :: END :: - Read::END - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); #endif // :: TODO :: @@ -226,11 +226,11 @@ -(void)_socketCallbackResetEndedWithStatus:(PostgresPollingStatusType)pqstatus { [self _updateStatus]; // this also calls disconnect when rejected } - /** - * The connect callback will continue to poll the connection for new data. When - * the poll status is either OK or FAILED, the application's callback block is - * run. - */ + /** + * The connect callback will continue to poll the connection for new data. When + * the poll status is either OK or FAILED, the application's callback block is + * run. + */ -(void)_socketCallbackConnect { // ignore this call if either connection or callback are nil @@ -258,7 +258,7 @@ -(void)_socketCallbackConnect { // [self performSelectorInBackground:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; [self performSelector:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil afterDelay:0.1]; -// [self performSelector:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; + // [self performSelector:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; } // [self _socketCallbackConnectEndedWithStatus:pqstatus]; break; @@ -267,10 +267,10 @@ -(void)_socketCallbackConnect { } } - /** - * The reset callback is very similar to the connect callback, and could probably - * be merged with that one. - */ + /** + * The reset callback is very similar to the connect callback, and could probably + * be merged with that one. + */ -(void)_socketCallbackReset { NSParameterAssert(_connection); @@ -291,10 +291,10 @@ -(void)_socketCallbackReset { } } - /** - * In the case of a query being processed, this method will consume any input - * then any results from the server - */ + /** + * In the case of a query being processed, this method will consume any input + * then any results from the server + */ -(void)_socketCallbackQueryRead { NSParameterAssert(_connection); @@ -316,7 +316,7 @@ -(void)_socketCallbackQueryRead { void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@":::: PGConnectionStateQuery(%@::%p) - Read BEGIN - Result - :: callback \n_callback :: (%@)\n ********************************* ",NSStringFromClass([self class]), self , callback ); #endif @@ -326,7 +326,7 @@ -(void)_socketCallbackQueryRead { while(1) { result = PQgetResult(_connection); if(result==nil) { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - Result nil - End"); #endif break; @@ -337,34 +337,34 @@ -(void)_socketCallbackQueryRead { // check for connection errors if(PQresultStatus(result)==PGRES_EMPTY_QUERY) { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - Result - Empty Query"); #endif // callback empty query error = [self raiseError:nil code:PGClientErrorQuery reason:@"Empty query"]; PQclear(result); } else if(PQresultStatus(result)==PGRES_BAD_RESPONSE || PQresultStatus(result)==PGRES_FATAL_ERROR) { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - Result - Client Error (%s)", PQresultErrorMessage(result)); #endif error = [self raiseError:nil code:PGClientErrorExecute reason:[NSString stringWithUTF8String:PQresultErrorMessage(result)]]; PQclear(result); } else { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - Result - READ Query RESULT (%@)",[currentPoolOperation queryString] ); #endif // TODO: allocate a different kind of class r = [[PGResult alloc] initWithResult:result format:[self tupleFormat]]; -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - Result - READ END (%s)", PQresultErrorMessage(result)); #endif -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - Result - Done :: (%@)", r ); #endif } if(r || error) { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery(%@::%p) - Read - Result - Done :: callback \n ********************************* \nresult :: (%@)\n ********************************* \nerror :: (%@) \n_callback :: (%@)\n ********************************* ",NSStringFromClass([self class]), self, r, error, callback ); #endif // queue up callback on nearest thread @@ -372,7 +372,7 @@ -(void)_socketCallbackQueryRead { dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); dispatch_async( qu_inRun ,^{ -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - callback %p ",callback); #endif @@ -384,7 +384,7 @@ -(void)_socketCallbackQueryRead { break; } } -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - Result - Clear " ); #endif // all results consumed - update state @@ -395,16 +395,16 @@ -(void)_socketCallbackQueryRead { // [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; [self _updateStatus]; -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read END - Result - Clear::End " ); #endif _stateOperation = PGOperationStateNone; } - /** - * In the case of a query being processed, this method will consume any input - * flush the connection and consume any results which are being processed. - */ + /** + * In the case of a query being processed, this method will consume any input + * flush the connection and consume any results which are being processed. + */ -(void)_socketCallbackQueryWrite { NSParameterAssert(_connection); // flush @@ -419,14 +419,14 @@ -(void)_socketCallbackQueryWrite { } } - /** - * This method is called from _socketCallback and depending on the - * current state of the connection, it will call the connect, reset, query - * or notification socket callback - */ + /** + * This method is called from _socketCallback and depending on the + * current state of the connection, it will call the connect, reset, query + * or notification socket callback + */ -(void)_socketCallback:(CFSocketCallBackType)callBackType { @try{ -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 switch(callBackType) { case kCFSocketReadCallBack: NSLog(@"kCFSocketReadCallBack"); @@ -451,37 +451,37 @@ -(void)_socketCallback:(CFSocketCallBackType)callBackType { PGConnectionState state_on = [self state]; switch(state_on) { case PGConnectionStateConnect: -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateConnect"); #endif [self _socketCallbackConnect]; break; case PGConnectionStateReset: -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateReset"); #endif [self _socketCallbackReset]; break; case PGConnectionStateQuery: if(callBackType==kCFSocketReadCallBack) { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - _socketCallback :: _socketCallbackQueryRead :: callback (%p)",[[self currentPoolOperation] getCallback]); #endif [self _socketCallbackQueryRead]; -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - _socketCallback :: _socketCallbackNotification :: callback (%p)", [[self currentPoolOperation] getCallback]); #endif [self _socketCallbackNotification]; } else if(callBackType==kCFSocketWriteCallBack) { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Write"); #endif [self _socketCallbackQueryWrite]; } break; default: -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateOther"); #endif [self _socketCallbackNotification]; diff --git a/src/Frameworks/PGClientKit/PGConnection+Connect.m b/src/Frameworks/PGClientKit/PGConnection+Connect.m index aba2175..2d8ef11 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Connect.m +++ b/src/Frameworks/PGClientKit/PGConnection+Connect.m @@ -168,7 +168,7 @@ -(void)connectWithURL:(NSURL* )url whenDone:(void(^)(BOOL usedPassword,NSError* // dispatch_async(dispatch_get_current_queue(),^ #endif { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" ------- %@ :: %@ :::: Connection Started ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); #endif [self _socketConnect:PGConnectionStateConnect]; @@ -176,7 +176,7 @@ -(void)connectWithURL:(NSURL* )url whenDone:(void(^)(BOOL usedPassword,NSError* // [self performSelector:@selector(_waitingPoolOperationForResult) withObject:self ]; // [self performSelector:@selector(_waitingPoolOperationForResultMaster) withObject:self ]; -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" ------- %@ :: %@ :::: Connection STOPPed ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); #endif diff --git a/src/Frameworks/PGClientKit/PGConnection+Errors.m b/src/Frameworks/PGClientKit/PGConnection+Errors.m index 997f79b..0e1feeb 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Errors.m +++ b/src/Frameworks/PGClientKit/PGConnection+Errors.m @@ -69,7 +69,7 @@ -(void)_raiseError:(NSError* )error { NSParameterAssert(error); // perform selector if([[self delegate] respondsToSelector:@selector(connection:error:)]) { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - _raiseError :: send to delegate connection:error:" ); #endif // [[self delegate] connection:self error:error]; @@ -79,13 +79,13 @@ -(void)_raiseError:(NSError* )error { // dispatch_barrier_sync(qu_inRun, ^ { [[self delegate] connection:self error:error]; // [NSThread detachNewThreadSelector:@selector(connection:error:) toTarget:[self delegate] withObject:@{@"connection":self, @"error":error} ]; - #if defined DEBUG && defined DEBUG2 + #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - _raiseError :: send to delegate connection:error: END" ); #endif //} ); }else{ -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - _raiseError :: no delegate respondsto connection:error:" ); #endif } @@ -107,7 +107,7 @@ -(NSError* )raiseError:(NSError** )error code:(PGClientErrorDomainCode)code reas } // raise the error with the delegate if([self delegate]) { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - _raiseError :: performSelectorOnMainThread :: (%@)", theError ); #endif @@ -116,11 +116,11 @@ -(NSError* )raiseError:(NSError** )error code:(PGClientErrorDomainCode)code reas [self _raiseError:theError]; }else{ -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - _raiseError:code: :: no delegate avail" ); #endif } -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - _raiseError :: return " ); #endif return theError; diff --git a/src/Frameworks/PGClientKit/PGConnection+Execute.m b/src/Frameworks/PGClientKit/PGConnection+Execute.m index 2c27ea3..381824d 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Execute.m +++ b/src/Frameworks/PGClientKit/PGConnection+Execute.m @@ -90,13 +90,13 @@ -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGR int returnCode = PQsendQueryParams(_connection,[query UTF8String],(int)params->size,params->types,(const char** )params->values,params->lengths,params->formats,resultFormat); _paramFree(params); if(!returnCode) { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"%@ :: %@ :: - execute - ERROR :: callback %p :: While EXECUTE (%@)", NSStringFromSelector(_cmd),NSStringFromClass([self class]), callback, query); #endif callback(nil,[self raiseError:nil code:PGClientErrorExecute reason:[NSString stringWithUTF8String:PQerrorMessage(_connection)]]); return; }else{ -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"%@ :: %@ :: - execute - PASSED :: callback %p :: While EXECUTE (%@)", NSStringFromSelector(_cmd),NSStringFromClass([self class]), callback, query); #endif } @@ -111,7 +111,7 @@ -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGR [self addOperation:query withCallBackWhenDone: (__bridge_retained void* )callback withCallBackWhenError: (__bridge_retained void* )callback ]; -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"%@ :: %@ :: - execute - RETURN :: callback %p :: %p ", NSStringFromSelector(_cmd),NSStringFromClass([self class]), callback, _callbackOperation); #endif @@ -134,9 +134,9 @@ -(void)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) cal // mach_port_t machTID = pthread_mach_thread_np(pthread_self()); NSString * queued_name_STR = [NSString stringWithFormat:@"%s_%ld :: %@", "query_operation_dispacthed_threads", (long)[self connectionPoolOperationCount], [NSThread currentThread] ]; const char * queued_name = [queued_name_STR UTF8String]; - +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" //// -_-_-_-_ Query Dispatch START -_-_-_-_- :: %@ ", queued_name_STR); - +#endif dispatch_queue_t queue_inRun = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); NSString* query2 = nil; @@ -147,25 +147,25 @@ -(void)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) cal query2 = [(PGQuery* )query quoteForConnection:self error:&error]; } if(error) { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"%@ :: %@ - query ERROR - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); #endif callback(nil,error); } else if(query2==nil) { callback(nil,[self raiseError:nil code:PGClientErrorExecute reason:@"Query is nil"]); } else { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"%@ :: %@ - query - callback %p :: \n query :: %@ :::::",NSStringFromClass([self class]), NSStringFromSelector(_cmd), callback, query2); #endif void (^callback_recall)(PGResult* result,NSError* error) = ^(PGResult* result_recall ,NSError* error_recall) { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" .... semaphore callback..... %@", [[self currentPoolOperation] semaphore]); #endif callback(result_recall , error_recall); -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" .... semaphore pass ..... "); // dispatch_semaphore_signal( [[self currentPoolOperation] semaphore] ); NSLog(@" .... semaphore signal end ..... %@", [[self currentPoolOperation] semaphore]); @@ -185,7 +185,7 @@ -(void)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) cal dispatch_semaphore_t semaphore_query_send = [[self currentPoolOperation] semaphore]; [self wait_semaphore_read: semaphore_query_send withQueue:queue_inRun]; -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" -_-_-_-_ Query END -_-_-_-_- :: %@ ", queued_name_STR); #endif _stateOperation = PGOperationStateNone; @@ -291,13 +291,13 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem { if( qq_loop != [NSRunLoop mainRunLoop]){ - dispatch_barrier_sync(qu_inRun, ^{ - [self wait_semaphore_read:sem withQueue:nil]; - }); - }else{ -// dispatch_barrier_async(qu_inRun, ^{ + dispatch_barrier_sync(qu_inRun, ^{ [self wait_semaphore_read:sem withQueue:nil]; -// }); + }); + }else{ + // dispatch_barrier_async(qu_inRun, ^{ + [self wait_semaphore_read:sem withQueue:nil]; + // }); } } @@ -310,7 +310,7 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ sem ]; // const char * queued_name = [queued_name_STR UTF8String]; -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" //// Start :: %@ ", queued_name_STR); #endif // NSLog(@" //// Start **** :: %s ", queued_name); @@ -331,7 +331,7 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ diispacthed = dispatch_semaphore_wait(sem,DISPATCH_TIME_NOW); if( nil == [[self currentPoolOperation] getCallback] || !diispacthed){ - [NSThread sleepForTimeInterval:.01]; + [NSThread sleepForTimeInterval:.01]; break; } @@ -340,12 +340,12 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ if([[self currentPoolOperation] valid] ) { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" //// STEP :: %@ ", queued_name_STR); #endif [self performSelector:@selector(dispathCall) withObject:nil]; }else{ - break; + break; } if( diispacthed && ![[self currentPoolOperation] valid] ) @@ -358,15 +358,15 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ // && ! PG_busy ) // break; - PGConnectionStatus con_status = [((PGConnection*)self) status]; + PGConnectionStatus con_status = [((PGConnection*)self) status]; if( con_status == PGConnectionStatusDisconnected || ! _connection) break; } -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" //// Clean **** :: %@ ", queued_name_STR); #endif [[NSThread currentThread] cancel]; -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" //// END :: %@ ", queued_name_STR); #endif @@ -383,12 +383,12 @@ -(void)dispathCall [NSThread sleepForTimeInterval:.01];; PGConnectionStatus con_status = [((PGConnection*)self) status]; if( - ( - con_status != PGConnectionStatusBusy && - con_status != PGConnectionStatusConnected && - con_status != PGConnectionStatusConnecting - - ) + ( + con_status != PGConnectionStatusBusy && + con_status != PGConnectionStatusConnected && + con_status != PGConnectionStatusConnecting + + ) || ! _connection || !_socket) return; @@ -424,26 +424,26 @@ -(void)dispathCall [qq_loop runUntilDate:theNextDate]; if(!isRunningThread){ [qq_loop_main runUntilDate:theNextDate]; - [NSThread sleepForTimeInterval:.1];; + [NSThread sleepForTimeInterval:.1];; } - -// [qq_loop_main runUntilDate:theNextDate]; -// -// isRunningThread = [qq_loop_main runMode:NSRunLoopCommonModes beforeDate:theNextDate]; -// if(!isRunningThread) -// { -// [NSThread sleepForTimeInterval:.1];; -// [self performSelectorOnMainThread:@selector(dispathCall) withObject:self waitUntilDone:YES modes:@[NSRunLoopCommonModes, NSDefaultRunLoopMode] ]; -// } -// + + // [qq_loop_main runUntilDate:theNextDate]; + // + // isRunningThread = [qq_loop_main runMode:NSRunLoopCommonModes beforeDate:theNextDate]; + // if(!isRunningThread) + // { + // [NSThread sleepForTimeInterval:.1];; + // [self performSelectorOnMainThread:@selector(dispathCall) withObject:self waitUntilDone:YES modes:@[NSRunLoopCommonModes, NSDefaultRunLoopMode] ]; + // } + // }else{ - + { [qq_loop_main runUntilDate:theNextDate]; - [qq_loop runUntilDate:theNextDate]; + [qq_loop runUntilDate:theNextDate]; } -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" END performSelectorOnMainThread :: %@", NSStringFromSelector(_cmd)); #endif return; // don t care diff --git a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m index 01cc579..f1a56ff 100644 --- a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m +++ b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m @@ -321,7 +321,7 @@ -(void)_socketConnect:(PGConnectionState)state { dispatch_semaphore_t semaphore_query_send = [[self masterPoolOperation] semaphore]; // [self dispathCall]; -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"%@ :: %@ :::: Socket created ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); #endif @@ -330,7 +330,7 @@ -(void)_socketConnect:(PGConnectionState)state { [[NSThread currentThread] cancel]; // CFRunLoopRun();//(kCFRunLoopDefaultMode, 0.2 , NO); -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" ------- %@ :: %@ :::: Socket Runloop ENDED CLEAR ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); #endif } diff --git a/src/Frameworks/PGClientKit/PGConnection.m b/src/Frameworks/PGClientKit/PGConnection.m index e7628f3..6df06b0 100644 --- a/src/Frameworks/PGClientKit/PGConnection.m +++ b/src/Frameworks/PGClientKit/PGConnection.m @@ -253,7 +253,7 @@ -(void)_updateStatusDelayed:(NSArray* )arguments { } -(void)_updateStatus { -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnection (%p) - _updateStatus ",self); #endif static PGConnectionStatus oldStatus = PGConnectionStatusDisconnected; @@ -278,7 +278,8 @@ -(void)_updateStatus { // from continuing NSNumber* key = [NSNumber numberWithInt:oldStatus]; NSString* description = [PGConnectionStatusDescription objectForKey:key]; - [self performSelectorOnMainThread:@selector(_updateStatusDelayed:) withObject:@[ key,description ] waitUntilDone:NO]; +// [self performSelectorOnMainThread:@selector(_updateStatusDelayed:) withObject:@[ key,description ] waitUntilDone:NO]; + [self performSelector:@selector(_updateStatusDelayed:) withObject:@[ key,description ] ]; #ifdef DEBUG2 NSLog(@"status => %@ %@",key,description); #endif @@ -316,7 +317,7 @@ -(PGConnectionOperation*)masterPoolOperation }else{ NSLog(@" ERROR :: NO master pool .... "); } -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 // NSLog(@" %@::%@ :: FETCH cureent pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, masterPoolOperation); #endif @@ -335,7 +336,7 @@ -(PGConnectionOperation*)currentPoolOperation }else{ NSLog(@" ERROR :: NO pool .... "); } -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 // NSLog(@" %@::%@ :: FETCH cureent pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, masterPoolOperation); #endif @@ -356,7 +357,7 @@ -(PGConnectionOperation*)prevPoolOperation NSLog(@" ERROR :: NO PREV pool .... "); return [self currentPoolOperation]; } -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 // NSLog(@" %@::%@ :: FETCH prev pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, masterPoolOperation); #endif @@ -380,7 +381,7 @@ -(id)addOperation: (id)operationClass withCallBackWhenDone:(void*)callBackWhenDo indexInPool = CFArrayGetCount(_callbackOperationPool); id obj = CFArrayGetValueAtIndex(_callbackOperationPool, indexInPool-1); -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" %@::%@ :: ADDED pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, [obj description]); #endif @@ -396,7 +397,7 @@ -(id)invalidateOperation:(NSInteger)operationRefIndex dispatch_semaphore_signal( [obj semaphore] ); [obj finish]; -#if defined DEBUG && defined DEBUG2 +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" %@::%@ :: REMOVED pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, [obj description]); #endif CFArrayRemoveValueAtIndex(_callbackOperationPool, operationRefIndex); diff --git a/src/Frameworks/PGClientKit/PGConnectionOperation.m b/src/Frameworks/PGClientKit/PGConnectionOperation.m index e71af60..8b4a4c3 100644 --- a/src/Frameworks/PGClientKit/PGConnectionOperation.m +++ b/src/Frameworks/PGClientKit/PGConnectionOperation.m @@ -77,7 +77,9 @@ -(void)finish } -(void)invalidate { +#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" %@::%@ :: INVALIDATE pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), _poolRefIdentifier, [self description]); +#endif if(_poolRefIdentifier !=0){ [_operationConnectionClassRef invalidateOperation: _poolRefIdentifier]; [self finish]; @@ -89,7 +91,9 @@ -(void)invalidate -(void)validate { + #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" %@::%@ :: REACTIVATE pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), _poolRefIdentifier, [self description]); +#endif if(_poolRefIdentifier !=0) [_operationConnectionClassRef invalidateOperation: _poolRefIdentifier]; _invalidated = NO; From e089651e4c955cd329c60d283e06f32238af2a5e Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Tue, 8 Aug 2017 18:50:50 +0200 Subject: [PATCH 12/21] Disconnect Multithread Error patch --- .../PGClientKit/PGConnection+Disconnect.m | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/Frameworks/PGClientKit/PGConnection+Disconnect.m b/src/Frameworks/PGClientKit/PGConnection+Disconnect.m index f56749d..b1809ed 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Disconnect.m +++ b/src/Frameworks/PGClientKit/PGConnection+Disconnect.m @@ -18,14 +18,19 @@ @implementation PGConnection (Disconnect) -(void)disconnect { - [self _cancelDestroy]; - [self _socketDisconnect]; - if(_connection) { - PQfinish(_connection); - _connection = nil; - _parameters = nil; - } - [self _updateStatus]; + @synchronized (self) { + [self _cancelDestroy]; + [self _socketDisconnect]; + if(_connection != NULL) { + + + PQfinish(_connection); + _connection = nil; + _parameters = nil; + + } + } + [self _updateStatus]; } @end From ef931d5b5f5d701cd9e02ceda407162d1e56f49b Mon Sep 17 00:00:00 2001 From: "genose.org" Date: Wed, 9 Aug 2017 10:10:01 +0200 Subject: [PATCH 13/21] some Preprocessor and dealloc corrections --- src/Apps/Foundation/PGFoundationClient.m | 4 +- .../PGClientKit/PGClientKit+Private.h | 2 +- .../PGClientKit/PGConnection+Callbacks.m | 739 +++++++++--------- src/Frameworks/PGClientKit/PGConnection.m | 4 +- src/Frameworks/PGClientKit/PGResult.m | 258 +++--- 5 files changed, 503 insertions(+), 504 deletions(-) diff --git a/src/Apps/Foundation/PGFoundationClient.m b/src/Apps/Foundation/PGFoundationClient.m index 706abc6..0a525ad 100644 --- a/src/Apps/Foundation/PGFoundationClient.m +++ b/src/Apps/Foundation/PGFoundationClient.m @@ -69,7 +69,7 @@ -(NSString* )prompt { // PGConnectionDelegate delegate implementation -(void)connection:(PGConnection* )connection willOpenWithParameters:(NSMutableDictionary* )dictionary { -#ifdef DEBUG2 +#ifdef DEBUG2 && DEBUG2 == 1 [[self term] printf:@"connection:willOpenWithParameters:%@",dictionary]; #endif // if there is a password in the parameters, then store it @@ -89,7 +89,7 @@ -(NSString* )connection:(PGConnection* )connection willExecute:(NSString *)query } -(void)connection:(PGConnection* )connection statusChange:(PGConnectionStatus)status description:(NSString *)description { -#ifdef DEBUG2 +#ifdef DEBUG2 && DEBUG2 == 1 [[self term] printf:@"StatusChange: %@ (%d)",description,status]; #endif // disconnected diff --git a/src/Frameworks/PGClientKit/PGClientKit+Private.h b/src/Frameworks/PGClientKit/PGClientKit+Private.h index d6b32d1..63288ae 100644 --- a/src/Frameworks/PGClientKit/PGClientKit+Private.h +++ b/src/Frameworks/PGClientKit/PGClientKit+Private.h @@ -63,7 +63,7 @@ PGKVPairs* makeKVPairs(NSDictionary* dict); void freeKVPairs(PGKVPairs* pairs); // profiling macros -#ifdef DEBUG2 +#ifdef DEBUG2 && DEBUG2 == 1 #include #define TIME_TICK(name) NSLog(@"TICK: %@",(name)); \ uint64_t tick_time = mach_absolute_time(); \ diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index 173effa..d7ea6ed 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -1,55 +1,55 @@ -// Copyright 2009-2015 David Thorpe -// https://github.com/djthorpe/postgresql-kit -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy -// of the License at http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -// ************************************* -// -// Copyright 2017 - ?? Sebastien Cotillard - Genose.org -// 07/2017 Sebastien Cotillard -// https://github.com/genose -// -// ************************************* -// ADDING Pool concurrent operation -// ************************************* + // Copyright 2009-2015 David Thorpe + // https://github.com/djthorpe/postgresql-kit + // + // Licensed under the Apache License, Version 2.0 (the "License"); you may not + // use this file except in compliance with the License. You may obtain a copy + // of the License at http://www.apache.org/licenses/LICENSE-2.0 + // + // Unless required by applicable law or agreed to in writing, software + // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + // License for the specific language governing permissions and limitations + // under the License. + + // ************************************* + // + // Copyright 2017 - ?? Sebastien Cotillard - Genose.org + // 07/2017 Sebastien Cotillard + // https://github.com/genose + // + // ************************************* + // ADDING Pool concurrent operation + // ************************************* #import #import #include -//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// #pragma mark C callback functions -//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// -//typedef struct __shared_blob soctted ; + //typedef struct __shared_blob soctted ; /** * This method is called from the run loop upon new data being available to read * on the socket, or the socket being able to write more data to the socket */ static int socketUsed_in = 0; void _socketCallback(CFSocketRef s, CFSocketCallBackType callBackType,CFDataRef address,const void* data,void* __self) { - - - + + + [NSThread sleepForTimeInterval:.01];; - + PGConnection* connection = (PGConnection* ) ((__bridge PGConnection* )__self); if(! connection // || socketUsed_in > 20 ) return ; socketUsed_in ++; - // dispatch_barrier_async(dispatch_get_main_queue(), ^{ + // dispatch_barrier_async(dispatch_get_main_queue(), ^{ #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"%@ :: %s :::: Socket CALL ... %lu ", NSStringFromClass([((__bridge NSObject *)__self) class]), (__FUNCTION__), callBackType); #endif @@ -58,10 +58,10 @@ void _socketCallback(CFSocketRef s, CFSocketCallBackType callBackType,CFDataRef NSLog(@"%@ :: %s :::: Socket CALL END .... (%lu) ", NSStringFromClass([((__bridge NSObject *)__self) class]), (__FUNCTION__), callBackType); #endif socketUsed_in = 0; - // }); - - // [NSThread sleepForTimeInterval:.1];; - + // }); + + // [NSThread sleepForTimeInterval:.1];; + } /** @@ -80,425 +80,420 @@ void _noticeProcessor(void* arg,const char* cString) { @implementation PGConnection (Callbacks) -//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// #pragma mark private methods - socket callbacks -//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// -(void)_socketCallbackNotification { @try { - NSParameterAssert(_connection); + NSParameterAssert(_connection); // consume input - PQconsumeInput(_connection); - + PQconsumeInput(_connection); + #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: loop "); + NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: loop "); #endif - + // loop for notifications - PGnotify* notify = nil; - while((notify = PQnotifies(_connection)) != nil) { - if([[self delegate] respondsToSelector:@selector(connection:notificationOnChannel:payload:)]) { + PGnotify* notify = nil; + while((notify = PQnotifies(_connection)) != nil) { + if([[self delegate] respondsToSelector:@selector(connection:notificationOnChannel:payload:)]) { #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: call delegate (%@) (%@)", [self delegate], NSStringFromSelector(@selector(connection:notificationOnChannel:payload:))); + NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: call delegate (%@) (%@)", [self delegate], NSStringFromSelector(@selector(connection:notificationOnChannel:payload:))); #endif - - NSString* channel = [NSString stringWithUTF8String:notify->relname]; - NSString* payload = [NSString stringWithUTF8String:notify->extra]; - [[self delegate] connection:self notificationOnChannel:channel payload:payload]; - } - PQfreemem(notify); + + NSString* channel = [NSString stringWithUTF8String:notify->relname]; + NSString* payload = [NSString stringWithUTF8String:notify->extra]; + [[self delegate] connection:self notificationOnChannel:channel payload:payload]; } + PQfreemem(notify); + } #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: free "); + NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: free "); #endif } @catch (NSException *exception) { NSLog(@" %@ exeception .... %@",NSStringFromSelector(_cmd),exception); } @finally { - + } } -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus { - - //:: void (^callback)(BOOL usedPassword,NSError* error) = (__bridge void (^)(BOOL,NSError* ))(_callback); + + //:: void (^callback)(BOOL usedPassword,NSError* error) = (__bridge void (^)(BOOL,NSError* ))(_callback); if( ![((PGConnectionOperation*)[self currentPoolOperation]) valid] || [[self currentPoolOperation] poolIdentifier] != 0) return; - + pqstatus = PQconnectPoll(_connection); - + _callbackOperation = [((PGConnectionOperation*)[self masterPoolOperation]) getCallback]; void (^callback)(BOOL usedPassword,NSError* error ) = (__bridge void (^)( BOOL,NSError* ))( _callbackOperation ); - + BOOL needsPassword = PQconnectionNeedsPassword(_connection) ? YES : NO; BOOL usedPassword = PQconnectionUsedPassword(_connection) ? YES : NO; #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"%@ (%p) :: BEGIN :: - Read::BEGIN - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); #endif - // update the status + // update the status [self setState:PGConnectionStateNone]; [self _updateStatus]; // this also calls disconnect when rejected - - - // callback + + + // callback if(pqstatus==PGRES_POLLING_OK) { - // set up notice processor, set success condition + // set up notice processor, set success condition PQsetNoticeProcessor(_connection,_noticeProcessor,(__bridge void *)(self)); if([[self currentPoolOperation] poolIdentifier] == 0){ - - + + mach_port_t machTID = pthread_mach_thread_np(pthread_self()); - + const char * queued_name = [[NSString stringWithFormat:@"%s_%x_%@", "operation_dispacthed_threads", machTID, NSStringFromSelector(_cmd) ] cString]; #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" //// %s ", queued_name); #endif dispatch_queue_t queue_inRun = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); queue_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); - - -#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) - [NSThread detachNewThreadWithBlock:^ -#else - - [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; - - dispatch_async(queue_inRun,^ -#endif - { - dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); - callback(usedPassword ? YES : NO,nil); - [((PGConnectionOperation*)[self masterPoolOperation]) finish]; - dispatch_semaphore_signal(ss); - - } -#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) - ] -#else - - ) -#endif - ; - // dispatch_semaphore_wait(ss,DISPATCH_TIME_FOREVER); - // [self wait_semaphore_read:ss]; - [self wait_semaphore_read: [((PGConnectionOperation*)[self masterPoolOperation]) semaphore] withQueue:queue_inRun]; - // [((PGConnectionOperation*)[self masterPoolOperation]) validate]; - } - // dispatch_destroy(queue); - } else if(needsPassword) { - // error callback - connection not made, needs password - callback(NO,[self raiseError:nil code:PGClientErrorNeedsPassword]); - } else if(usedPassword) { - // error callback - connection not made, password was invalid - callback(YES,[self raiseError:nil code:PGClientErrorInvalidPassword]); - } else { - // error callback - connection not made, some other kind of rejection - callback(YES,[self raiseError:nil code:PGClientErrorRejected]); - } - + + + + + [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; + + dispatch_async(queue_inRun,^ + + { + dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); + callback(usedPassword ? YES : NO,nil); + [((PGConnectionOperation*)[self masterPoolOperation]) finish]; + dispatch_semaphore_signal(ss); + + } + + + ); + + // dispatch_semaphore_wait(ss,DISPATCH_TIME_FOREVER); + // [self wait_semaphore_read:ss]; + [self wait_semaphore_read: [((PGConnectionOperation*)[self masterPoolOperation]) semaphore] withQueue:queue_inRun]; + // [((PGConnectionOperation*)[self masterPoolOperation]) validate]; + } + // dispatch_destroy(queue); + } else if(needsPassword) { + // error callback - connection not made, needs password + callback(NO,[self raiseError:nil code:PGClientErrorNeedsPassword]); + } else if(usedPassword) { + // error callback - connection not made, password was invalid + callback(YES,[self raiseError:nil code:PGClientErrorInvalidPassword]); + } else { + // error callback - connection not made, some other kind of rejection + callback(YES,[self raiseError:nil code:PGClientErrorRejected]); + } + #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"%@ (%p) :: END :: - Read::END - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); + NSLog(@"%@ (%p) :: END :: - Read::END - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); #endif - // :: TODO :: - //:: _callback = nil; - // - // [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; - // [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; - // [self pushPoolOperation]; - } - - - -(void)_socketCallbackResetEndedWithStatus:(PostgresPollingStatusType)pqstatus { - NSParameterAssert([[self currentPoolOperation] valid]); - //:: void (^callback)(NSError* error) = (__bridge void (^)(NSError* ))(_callback); - void (^callback)(NSError* error) = (__bridge void (^)(NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); - if(pqstatus==PGRES_POLLING_OK) { - callback(nil); - } else { - callback([self raiseError:nil code:PGClientErrorRejected]); - } - //:: _callback = nil; - [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; - [self setState:PGConnectionStateNone]; - [self _updateStatus]; // this also calls disconnect when rejected - } - - /** - * The connect callback will continue to poll the connection for new data. When - * the poll status is either OK or FAILED, the application's callback block is - * run. - */ - -(void)_socketCallbackConnect { - // ignore this call if either connection or callback are nil - - PGConnectionOperation* currentpoolOpe = [self currentPoolOperation]; - if(_connection==nil - || ![[self currentPoolOperation] valid] - || ( [currentpoolOpe poolIdentifier]) !=0 - ) { - // || (_callback==nil) // && _callbackOperation == nil) - return; - } - - PostgresPollingStatusType pqstatus = PQconnectPoll(_connection); - switch(pqstatus) { - case PGRES_POLLING_READING: - case PGRES_POLLING_WRITING: - // still connecting - ask to call poll again in runloop - [self performSelector:@selector(_socketCallbackConnect) withObject:nil afterDelay:0.1]; - break; - case PGRES_POLLING_OK: - case PGRES_POLLING_FAILED: - if(( [currentpoolOpe poolIdentifier]) ==0 && [currentpoolOpe valid] ) - { - // finished connecting - // [self performSelectorInBackground:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; - [self performSelector:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil afterDelay:0.1]; - - // [self performSelector:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; - } - // [self _socketCallbackConnectEndedWithStatus:pqstatus]; - break; - default: - break; - } - } - - /** - * The reset callback is very similar to the connect callback, and could probably - * be merged with that one. - */ - -(void)_socketCallbackReset { - NSParameterAssert(_connection); - - PostgresPollingStatusType pqstatus = PQresetPoll(_connection); - switch(pqstatus) { - case PGRES_POLLING_READING: - case PGRES_POLLING_WRITING: - // still connecting - call poll again - PQresetPoll(_connection); - break; - case PGRES_POLLING_OK: - case PGRES_POLLING_FAILED: - // finished connecting - [self _socketCallbackResetEndedWithStatus:pqstatus]; - break; - default: - break; - } - } - - /** - * In the case of a query being processed, this method will consume any input - * then any results from the server - */ - -(void)_socketCallbackQueryRead { - NSParameterAssert(_connection); - - PQconsumeInput(_connection); - - /* it seems that we don't really need to check for busy and it seems to - * create some issues, so ignore for now */ - // check for busy, return if more to do - if(PQisBusy(_connection)) { - return; - } - - // - NSParameterAssert([[self currentPoolOperation] valid]); - - PGConnectionOperation* currentPoolOperation = [self currentPoolOperation]; - - //:: void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); - - void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); - + // :: TODO :: + //:: _callback = nil; + // + // [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; + // [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; + // [self pushPoolOperation]; +} + + +-(void)_socketCallbackResetEndedWithStatus:(PostgresPollingStatusType)pqstatus { + NSParameterAssert([[self currentPoolOperation] valid]); + //:: void (^callback)(NSError* error) = (__bridge void (^)(NSError* ))(_callback); + void (^callback)(NSError* error) = (__bridge void (^)(NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); + if(pqstatus==PGRES_POLLING_OK) { + callback(nil); + } else { + callback([self raiseError:nil code:PGClientErrorRejected]); + } + //:: _callback = nil; + [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; + [self setState:PGConnectionStateNone]; + [self _updateStatus]; // this also calls disconnect when rejected +} + +/** + * The connect callback will continue to poll the connection for new data. When + * the poll status is either OK or FAILED, the application's callback block is + * run. + */ +-(void)_socketCallbackConnect { + // ignore this call if either connection or callback are nil + + PGConnectionOperation* currentpoolOpe = [self currentPoolOperation]; + if(_connection==nil + || ![[self currentPoolOperation] valid] + || ( [currentpoolOpe poolIdentifier]) !=0 + ) { + // || (_callback==nil) // && _callbackOperation == nil) + return; + } + + PostgresPollingStatusType pqstatus = PQconnectPoll(_connection); + switch(pqstatus) { + case PGRES_POLLING_READING: + case PGRES_POLLING_WRITING: + // still connecting - ask to call poll again in runloop + [self performSelector:@selector(_socketCallbackConnect) withObject:nil afterDelay:0.1]; + break; + case PGRES_POLLING_OK: + case PGRES_POLLING_FAILED: + if(( [currentpoolOpe poolIdentifier]) ==0 && [currentpoolOpe valid] ) + { + // finished connecting + // [self performSelectorInBackground:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; + [self performSelector:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil afterDelay:0.1]; + + // [self performSelector:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; + } + // [self _socketCallbackConnectEndedWithStatus:pqstatus]; + break; + default: + break; + } +} + +/** + * The reset callback is very similar to the connect callback, and could probably + * be merged with that one. + */ +-(void)_socketCallbackReset { + NSParameterAssert(_connection); + + PostgresPollingStatusType pqstatus = PQresetPoll(_connection); + switch(pqstatus) { + case PGRES_POLLING_READING: + case PGRES_POLLING_WRITING: + // still connecting - call poll again + PQresetPoll(_connection); + break; + case PGRES_POLLING_OK: + case PGRES_POLLING_FAILED: + // finished connecting + [self _socketCallbackResetEndedWithStatus:pqstatus]; + break; + default: + break; + } +} + +/** + * In the case of a query being processed, this method will consume any input + * then any results from the server + */ +-(void)_socketCallbackQueryRead { + NSParameterAssert(_connection); + + PQconsumeInput(_connection); + + /* it seems that we don't really need to check for busy and it seems to + * create some issues, so ignore for now */ + // check for busy, return if more to do + if(PQisBusy(_connection)) { + return; + } + + // + NSParameterAssert([[self currentPoolOperation] valid]); + + PGConnectionOperation* currentPoolOperation = [self currentPoolOperation]; + + //:: void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); + + void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); + #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@":::: PGConnectionStateQuery(%@::%p) - Read BEGIN - Result - :: callback \n_callback :: (%@)\n ********************************* ",NSStringFromClass([self class]), self , callback ); + NSLog(@":::: PGConnectionStateQuery(%@::%p) - Read BEGIN - Result - :: callback \n_callback :: (%@)\n ********************************* ",NSStringFromClass([self class]), self , callback ); #endif - - - // consume results - PGresult* result = nil; - while(1) { - result = PQgetResult(_connection); - if(result==nil) { + + + // consume results + PGresult* result = nil; + while(1) { + result = PQgetResult(_connection); + if(result==nil) { #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read - Result nil - End"); + NSLog(@"PGConnectionStateQuery - Read - Result nil - End"); #endif - break; - } - NSError* error = nil; - PGResult* r = nil; - - - // check for connection errors - if(PQresultStatus(result)==PGRES_EMPTY_QUERY) { + break; + } + NSError* error = nil; + PGResult* r = nil; + + + // check for connection errors + if(PQresultStatus(result)==PGRES_EMPTY_QUERY) { #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read - Result - Empty Query"); + NSLog(@"PGConnectionStateQuery - Read - Result - Empty Query"); #endif - // callback empty query - error = [self raiseError:nil code:PGClientErrorQuery reason:@"Empty query"]; - PQclear(result); - } else if(PQresultStatus(result)==PGRES_BAD_RESPONSE || PQresultStatus(result)==PGRES_FATAL_ERROR) { + // callback empty query + error = [self raiseError:nil code:PGClientErrorQuery reason:@"Empty query"]; + PQclear(result); + } else if(PQresultStatus(result)==PGRES_BAD_RESPONSE || PQresultStatus(result)==PGRES_FATAL_ERROR) { #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read - Result - Client Error (%s)", PQresultErrorMessage(result)); + NSLog(@"PGConnectionStateQuery - Read - Result - Client Error (%s)", PQresultErrorMessage(result)); #endif - error = [self raiseError:nil code:PGClientErrorExecute reason:[NSString stringWithUTF8String:PQresultErrorMessage(result)]]; - PQclear(result); - } else { + error = [self raiseError:nil code:PGClientErrorExecute reason:[NSString stringWithUTF8String:PQresultErrorMessage(result)]]; + PQclear(result); + } else { #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read - Result - READ Query RESULT (%@)",[currentPoolOperation queryString] ); + NSLog(@"PGConnectionStateQuery - Read - Result - READ Query RESULT (%@)",[currentPoolOperation queryString] ); #endif - // TODO: allocate a different kind of class - r = [[PGResult alloc] initWithResult:result format:[self tupleFormat]]; + // TODO: allocate a different kind of class + r = [[PGResult alloc] initWithResult:result format:[self tupleFormat]]; #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read - Result - READ END (%s)", PQresultErrorMessage(result)); + NSLog(@"PGConnectionStateQuery - Read - Result - READ END (%s)", PQresultErrorMessage(result)); #endif #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read - Result - Done :: (%@)", r ); + NSLog(@"PGConnectionStateQuery - Read - Result - Done :: (%@)", r ); #endif - } - if(r || error) { - + } + if(r || error) { + #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery(%@::%p) - Read - Result - Done :: callback \n ********************************* \nresult :: (%@)\n ********************************* \nerror :: (%@) \n_callback :: (%@)\n ********************************* ",NSStringFromClass([self class]), self, r, error, callback ); + NSLog(@"PGConnectionStateQuery(%@::%p) - Read - Result - Done :: callback \n ********************************* \nresult :: (%@)\n ********************************* \nerror :: (%@) \n_callback :: (%@)\n ********************************* ",NSStringFromClass([self class]), self, r, error, callback ); #endif - // queue up callback on nearest thread - - dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); - - dispatch_async( qu_inRun ,^{ + // queue up callback on nearest thread + + dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); + + dispatch_async( qu_inRun ,^{ #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read - callback %p ",callback); + NSLog(@"PGConnectionStateQuery - Read - callback %p ",callback); #endif - - callback(r,error); - [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; - [((PGConnectionOperation*)[self masterPoolOperation]) validate]; - }); - - break; - } - } + + callback(r,error); + [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; + [((PGConnectionOperation*)[self masterPoolOperation]) validate]; + }); + + break; + } + } #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read - Result - Clear " ); + NSLog(@"PGConnectionStateQuery - Read - Result - Clear " ); #endif - // all results consumed - update state - [self setState:PGConnectionStateNone]; - - //:: _callback = nil; // release the callback - [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; - // [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; - - [self _updateStatus]; + // all results consumed - update state + [self setState:PGConnectionStateNone]; + + //:: _callback = nil; // release the callback + [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; + // [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; + + [self _updateStatus]; #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read END - Result - Clear::End " ); + NSLog(@"PGConnectionStateQuery - Read END - Result - Clear::End " ); #endif - _stateOperation = PGOperationStateNone; - } - - /** - * In the case of a query being processed, this method will consume any input - * flush the connection and consume any results which are being processed. - */ - -(void)_socketCallbackQueryWrite { - NSParameterAssert(_connection); - // flush - int returnCode = PQflush(_connection); - if(returnCode==-1) { - // callback with error - NSParameterAssert([[self currentPoolOperation] valid]); - //:: void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); - void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); - NSError* error = [self raiseError:nil code:PGClientErrorState reason:@"Data flush failed during query"]; - callback(nil,error); - } - } - - /** - * This method is called from _socketCallback and depending on the - * current state of the connection, it will call the connect, reset, query - * or notification socket callback - */ - -(void)_socketCallback:(CFSocketCallBackType)callBackType { - @try{ + _stateOperation = PGOperationStateNone; +} + +/** + * In the case of a query being processed, this method will consume any input + * flush the connection and consume any results which are being processed. + */ +-(void)_socketCallbackQueryWrite { + NSParameterAssert(_connection); + // flush + int returnCode = PQflush(_connection); + if(returnCode==-1) { + // callback with error + NSParameterAssert([[self currentPoolOperation] valid]); + //:: void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); + void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); + NSError* error = [self raiseError:nil code:PGClientErrorState reason:@"Data flush failed during query"]; + callback(nil,error); + } +} + +/** + * This method is called from _socketCallback and depending on the + * current state of the connection, it will call the connect, reset, query + * or notification socket callback + */ +-(void)_socketCallback:(CFSocketCallBackType)callBackType { + @try{ #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - switch(callBackType) { - case kCFSocketReadCallBack: - NSLog(@"kCFSocketReadCallBack"); - break; - case kCFSocketAcceptCallBack: - NSLog(@"kCFSocketAcceptCallBack"); - break; - case kCFSocketDataCallBack: - NSLog(@"kCFSocketDataCallBack"); - break; - case kCFSocketConnectCallBack: - NSLog(@"kCFSocketConnectCallBack"); - break; - case kCFSocketWriteCallBack: - NSLog(@"kCFSocketWriteCallBack"); - break; - default: - NSLog(@"CFSocketCallBackType OTHER"); - break; - } + switch(callBackType) { + case kCFSocketReadCallBack: + NSLog(@"kCFSocketReadCallBack"); + break; + case kCFSocketAcceptCallBack: + NSLog(@"kCFSocketAcceptCallBack"); + break; + case kCFSocketDataCallBack: + NSLog(@"kCFSocketDataCallBack"); + break; + case kCFSocketConnectCallBack: + NSLog(@"kCFSocketConnectCallBack"); + break; + case kCFSocketWriteCallBack: + NSLog(@"kCFSocketWriteCallBack"); + break; + default: + NSLog(@"CFSocketCallBackType OTHER"); + break; + } #endif - PGConnectionState state_on = [self state]; - switch(state_on) { - case PGConnectionStateConnect: + PGConnectionState state_on = [self state]; + switch(state_on) { + case PGConnectionStateConnect: #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateConnect"); + NSLog(@"PGConnectionStateConnect"); #endif - [self _socketCallbackConnect]; - break; - case PGConnectionStateReset: + [self _socketCallbackConnect]; + break; + case PGConnectionStateReset: #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateReset"); + NSLog(@"PGConnectionStateReset"); #endif - [self _socketCallbackReset]; - break; - case PGConnectionStateQuery: - if(callBackType==kCFSocketReadCallBack) { + [self _socketCallbackReset]; + break; + case PGConnectionStateQuery: + if(callBackType==kCFSocketReadCallBack) { #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read - _socketCallback :: _socketCallbackQueryRead :: callback (%p)",[[self currentPoolOperation] getCallback]); + NSLog(@"PGConnectionStateQuery - Read - _socketCallback :: _socketCallbackQueryRead :: callback (%p)",[[self currentPoolOperation] getCallback]); #endif - [self _socketCallbackQueryRead]; + [self _socketCallbackQueryRead]; #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read - _socketCallback :: _socketCallbackNotification :: callback (%p)", [[self currentPoolOperation] getCallback]); + NSLog(@"PGConnectionStateQuery - Read - _socketCallback :: _socketCallbackNotification :: callback (%p)", [[self currentPoolOperation] getCallback]); #endif - [self _socketCallbackNotification]; - - } else if(callBackType==kCFSocketWriteCallBack) { + [self _socketCallbackNotification]; + + } else if(callBackType==kCFSocketWriteCallBack) { #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Write"); + NSLog(@"PGConnectionStateQuery - Write"); #endif - [self _socketCallbackQueryWrite]; - } - break; - default: + [self _socketCallbackQueryWrite]; + } + break; + default: #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateOther"); + NSLog(@"PGConnectionStateOther"); #endif - [self _socketCallbackNotification]; - break; - } - - [self _updateStatus]; - } - @catch (NSException *exception) { - NSLog(@" %@ exeception .... %@",NSStringFromSelector(_cmd),exception); - } - @finally { - - } - } - - @end - - - + [self _socketCallbackNotification]; + break; + } + + [self _updateStatus]; + } + @catch (NSException *exception) { + NSLog(@" %@ exeception .... %@",NSStringFromSelector(_cmd),exception); + } + @finally { + + } +} + +@end + + + diff --git a/src/Frameworks/PGClientKit/PGConnection.m b/src/Frameworks/PGClientKit/PGConnection.m index 6df06b0..bced2ee 100644 --- a/src/Frameworks/PGClientKit/PGConnection.m +++ b/src/Frameworks/PGClientKit/PGConnection.m @@ -280,13 +280,13 @@ -(void)_updateStatus { NSString* description = [PGConnectionStatusDescription objectForKey:key]; // [self performSelectorOnMainThread:@selector(_updateStatusDelayed:) withObject:@[ key,description ] waitUntilDone:NO]; [self performSelector:@selector(_updateStatusDelayed:) withObject:@[ key,description ] ]; -#ifdef DEBUG2 +#ifdef DEBUG2 && DEBUG2 == 1 NSLog(@"status => %@ %@",key,description); #endif // if connection is rejected, then call disconnect if(oldStatus==PGConnectionStatusRejected) { -#ifdef DEBUG2 +#ifdef DEBUG2 && DEBUG2 == 1 NSLog(@"_updateStatus => disconnect/rejected :: %@ %@",key,description); #endif [self disconnect]; diff --git a/src/Frameworks/PGClientKit/PGResult.m b/src/Frameworks/PGClientKit/PGResult.m index d309437..97c17a1 100644 --- a/src/Frameworks/PGClientKit/PGResult.m +++ b/src/Frameworks/PGClientKit/PGResult.m @@ -1,16 +1,16 @@ -// Copyright 2009-2015 David Thorpe -// https://github.com/djthorpe/postgresql-kit -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy -// of the License at http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. + // Copyright 2009-2015 David Thorpe + // https://github.com/djthorpe/postgresql-kit + // + // Licensed under the Apache License, Version 2.0 (the "License"); you may not + // use this file except in compliance with the License. You may obtain a copy + // of the License at http://www.apache.org/licenses/LICENSE-2.0 + // + // Unless required by applicable law or agreed to in writing, software + // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + // License for the specific language governing permissions and limitations + // under the License. #import #import @@ -19,171 +19,175 @@ @implementation PGResult @dynamic size, numberOfColumns, affectedRows, dataReturned, columnNames, rowNumber, format; -//////////////////////////////////////////////////////////////////////////////// -// initialization + //////////////////////////////////////////////////////////////////////////////// + // initialization -(id)init { - return nil; + return nil; } -(id)initWithResult:(PGresult* )theResult format:(PGClientTupleFormat)format encoding:(NSStringEncoding)encoding { - self = [super init]; - if(self) { - NSParameterAssert(theResult); - _result = theResult; - _format = format; - _encoding = encoding; - _cachedData = [NSMutableDictionary dictionaryWithCapacity:PQntuples(_result)]; - } - return self; + self = [super init]; + if(self) { + NSParameterAssert(theResult); + _result = theResult; + _format = format; + _encoding = encoding; + _cachedData = [NSMutableDictionary dictionaryWithCapacity:PQntuples(_result)]; + } + return self; } -(id)initWithResult:(PGresult* )theResult format:(PGClientTupleFormat)format { - return [self initWithResult:theResult format:format encoding:NSUTF8StringEncoding]; + return [self initWithResult:theResult format:format encoding:NSUTF8StringEncoding]; } -(void)dealloc { - [NSThread sleepForTimeInterval:1.0]; - [_cachedData removeAllObjects]; - PQclear((PGresult* )_result); + @synchronized(self) { + + + [NSThread sleepForTimeInterval:1.0]; + [_cachedData removeAllObjects]; + PQclear((PGresult* )_result); + } } -//////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////// -(PGClientTupleFormat)format { - return _format; + return _format; } -(NSUInteger)size { - NSUInteger _number = NSIntegerMax; - if(_number==NSIntegerMax) { - _number = PQntuples(_result); - } - return _number; + NSUInteger _number = NSIntegerMax; + if(_number==NSIntegerMax) { + _number = PQntuples(_result); + } + return _number; } -(NSUInteger)numberOfColumns { - NSUInteger _number = NSIntegerMax; - if(_number==NSIntegerMax) { - _number = PQnfields(_result); - } - return _number; + NSUInteger _number = NSIntegerMax; + if(_number==NSIntegerMax) { + _number = PQnfields(_result); + } + return _number; } -(NSUInteger)affectedRows { - NSUInteger _number = NSIntegerMax; - if(_number==NSIntegerMax) { - NSString* affectedRows = [NSString stringWithUTF8String:PQcmdTuples(_result)]; - _number = [affectedRows integerValue]; - } - return _number; + NSUInteger _number = NSIntegerMax; + if(_number==NSIntegerMax) { + NSString* affectedRows = [NSString stringWithUTF8String:PQcmdTuples(_result)]; + _number = [affectedRows integerValue]; + } + return _number; } -(BOOL)dataReturned { - return PQresultStatus(_result)==PGRES_TUPLES_OK ? YES : NO; + return PQresultStatus(_result)==PGRES_TUPLES_OK ? YES : NO; } -(NSArray* )columnNames { - NSUInteger numberOfColumns = [self numberOfColumns]; - NSMutableArray* theColumns = [NSMutableArray arrayWithCapacity:numberOfColumns]; - for(NSUInteger i = 0; i < numberOfColumns; i++) { - [theColumns addObject:[NSString stringWithUTF8String:PQfname(_result,(int)i)]]; - } - return theColumns; + NSUInteger numberOfColumns = [self numberOfColumns]; + NSMutableArray* theColumns = [NSMutableArray arrayWithCapacity:numberOfColumns]; + for(NSUInteger i = 0; i < numberOfColumns; i++) { + [theColumns addObject:[NSString stringWithUTF8String:PQfname(_result,(int)i)]]; + } + return theColumns; } -(void)setRowNumber:(NSUInteger)rowNumber { - NSParameterAssert(rowNumber < [self size]); - _rowNumber = rowNumber; + NSParameterAssert(rowNumber < [self size]); + _rowNumber = rowNumber; } -(NSUInteger)rowNumber { - return _rowNumber; + return _rowNumber; } -//////////////////////////////////////////////////////////////////////////////// -// private methods + //////////////////////////////////////////////////////////////////////////////// + // private methods -(NSObject* )_tupleForRow:(NSUInteger)r column:(NSUInteger)c { - // check for null - if(PQgetisnull(_result,(int)r,(int)c)) { - return [NSNull null]; - } - // get bytes, length - const void* bytes = PQgetvalue(_result,(int)r,(int)c); - NSUInteger size = PQgetlength(_result,(int)r,(int)c); - NSParameterAssert(bytes); -// NSParameterAssert(size); - - switch(_format) { - case PGClientTupleFormatText: - return pgdata_text2obj(PQftype(_result,(int)c),bytes,size,_encoding); - case PGClientTupleFormatBinary: - return pgdata_bin2obj(PQftype(_result,(int)c),bytes,size,_encoding); - default: - return nil; - } -} - -//////////////////////////////////////////////////////////////////////////////// - -// return the current row as an array of NSObject values + // check for null + if(PQgetisnull(_result,(int)r,(int)c)) { + return [NSNull null]; + } + // get bytes, length + const void* bytes = PQgetvalue(_result,(int)r,(int)c); + NSUInteger size = PQgetlength(_result,(int)r,(int)c); + NSParameterAssert(bytes); + // NSParameterAssert(size); + + switch(_format) { + case PGClientTupleFormatText: + return pgdata_text2obj(PQftype(_result,(int)c),bytes,size,_encoding); + case PGClientTupleFormatBinary: + return pgdata_bin2obj(PQftype(_result,(int)c),bytes,size,_encoding); + default: + return nil; + } +} + + //////////////////////////////////////////////////////////////////////////////// + + // return the current row as an array of NSObject values -(NSArray* )fetchRowAsArray { - if(_rowNumber >= [self size]) { - return nil; - } - NSNumber* key = [NSNumber numberWithUnsignedInteger:_rowNumber]; - NSMutableArray* theArray = [_cachedData objectForKey:key]; - if(theArray==nil) { - // create the array - NSUInteger numberOfColumns = [self numberOfColumns]; - theArray = [NSMutableArray arrayWithCapacity:numberOfColumns]; - // fill in the columns - for(NSUInteger i = 0; i < numberOfColumns; i++) { - id obj = [self _tupleForRow:_rowNumber column:i]; - NSParameterAssert(obj); - [theArray addObject:obj]; - } - // cache the array - [_cachedData setObject:theArray forKey:key]; - } - // increment to next row, return - _rowNumber++; - return theArray; + if(_rowNumber >= [self size]) { + return nil; + } + NSNumber* key = [NSNumber numberWithUnsignedInteger:_rowNumber]; + NSMutableArray* theArray = [_cachedData objectForKey:key]; + if(theArray==nil) { + // create the array + NSUInteger numberOfColumns = [self numberOfColumns]; + theArray = [NSMutableArray arrayWithCapacity:numberOfColumns]; + // fill in the columns + for(NSUInteger i = 0; i < numberOfColumns; i++) { + id obj = [self _tupleForRow:_rowNumber column:i]; + NSParameterAssert(obj); + [theArray addObject:obj]; + } + // cache the array + [_cachedData setObject:theArray forKey:key]; + } + // increment to next row, return + _rowNumber++; + return theArray; } -(NSDictionary* )fetchRowAsDictionary { - return [NSDictionary dictionaryWithObjects:[self fetchRowAsArray] forKeys:[self columnNames]]; + return [NSDictionary dictionaryWithObjects:[self fetchRowAsArray] forKeys:[self columnNames]]; } -(NSArray* )arrayForColumn:(NSString* )columnName { - NSParameterAssert(columnName); - NSInteger c = [[self columnNames] indexOfObject:columnName]; - if(c < 0 || c >= [self numberOfColumns]) { - return nil; - } - NSUInteger size = [self size]; - if(size==0) { - return @[ ]; - } - NSMutableArray* array = [NSMutableArray arrayWithCapacity:size]; - for(NSUInteger i = 0; i < size; i++) { - [array addObject:[self _tupleForRow:i column:c]]; - } - return array; -} - -//////////////////////////////////////////////////////////////////////////////// + NSParameterAssert(columnName); + NSInteger c = [[self columnNames] indexOfObject:columnName]; + if(c < 0 || c >= [self numberOfColumns]) { + return nil; + } + NSUInteger size = [self size]; + if(size==0) { + return @[ ]; + } + NSMutableArray* array = [NSMutableArray arrayWithCapacity:size]; + for(NSUInteger i = 0; i < size; i++) { + [array addObject:[self _tupleForRow:i column:c]]; + } + return array; +} + + //////////////////////////////////////////////////////////////////////////////// -(NSString* )description { - NSDictionary* theValues = - [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithUnsignedInteger:[self size]],@"size", - [NSNumber numberWithUnsignedInteger:[self affectedRows]],@"affectedRows", - [NSNumber numberWithBool:[self dataReturned]],@"dataReturned", - [self columnNames],@"columnNames",nil]; - return [theValues description]; + NSDictionary* theValues = + [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithUnsignedInteger:[self size]],@"size", + [NSNumber numberWithUnsignedInteger:[self affectedRows]],@"affectedRows", + [NSNumber numberWithBool:[self dataReturned]],@"dataReturned", + [self columnNames],@"columnNames",nil]; + return [theValues description]; } @end From b2458d61f5d6b8f71cab331409a6fddb1de3ba9d Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Wed, 9 Aug 2017 18:14:12 +0200 Subject: [PATCH 14/21] Some High Load Threads corrections --- src/Apps/Foundation/PGFoundationClient.m | 4 +- .../PGClientKit/PGClientKit+Private.h | 2 +- .../PGClientKit/PGConnection+Callbacks.m | 307 +++++++++--------- .../PGClientKit/PGConnection+Execute.m | 58 +++- src/Frameworks/PGClientKit/PGConnection.m | 69 ++-- src/Frameworks/PGClientKit/PGResult.m | 1 + 6 files changed, 246 insertions(+), 195 deletions(-) diff --git a/src/Apps/Foundation/PGFoundationClient.m b/src/Apps/Foundation/PGFoundationClient.m index 0a525ad..0769398 100644 --- a/src/Apps/Foundation/PGFoundationClient.m +++ b/src/Apps/Foundation/PGFoundationClient.m @@ -69,7 +69,7 @@ -(NSString* )prompt { // PGConnectionDelegate delegate implementation -(void)connection:(PGConnection* )connection willOpenWithParameters:(NSMutableDictionary* )dictionary { -#ifdef DEBUG2 && DEBUG2 == 1 +#if defined(DEBUG2) && DEBUG2 == 1 [[self term] printf:@"connection:willOpenWithParameters:%@",dictionary]; #endif // if there is a password in the parameters, then store it @@ -89,7 +89,7 @@ -(NSString* )connection:(PGConnection* )connection willExecute:(NSString *)query } -(void)connection:(PGConnection* )connection statusChange:(PGConnectionStatus)status description:(NSString *)description { -#ifdef DEBUG2 && DEBUG2 == 1 +#if defined(DEBUG2) && DEBUG2 == 1 [[self term] printf:@"StatusChange: %@ (%d)",description,status]; #endif // disconnected diff --git a/src/Frameworks/PGClientKit/PGClientKit+Private.h b/src/Frameworks/PGClientKit/PGClientKit+Private.h index 63288ae..788af96 100644 --- a/src/Frameworks/PGClientKit/PGClientKit+Private.h +++ b/src/Frameworks/PGClientKit/PGClientKit+Private.h @@ -63,7 +63,7 @@ PGKVPairs* makeKVPairs(NSDictionary* dict); void freeKVPairs(PGKVPairs* pairs); // profiling macros -#ifdef DEBUG2 && DEBUG2 == 1 +#if defined(DEBUG2) && DEBUG2 == 1 #include #define TIME_TICK(name) NSLog(@"TICK: %@",(name)); \ uint64_t tick_time = mach_absolute_time(); \ diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index d7ea6ed..1e75f0a 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -1,55 +1,55 @@ - // Copyright 2009-2015 David Thorpe - // https://github.com/djthorpe/postgresql-kit - // - // Licensed under the Apache License, Version 2.0 (the "License"); you may not - // use this file except in compliance with the License. You may obtain a copy - // of the License at http://www.apache.org/licenses/LICENSE-2.0 - // - // Unless required by applicable law or agreed to in writing, software - // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - // License for the specific language governing permissions and limitations - // under the License. - - // ************************************* - // - // Copyright 2017 - ?? Sebastien Cotillard - Genose.org - // 07/2017 Sebastien Cotillard - // https://github.com/genose - // - // ************************************* - // ADDING Pool concurrent operation - // ************************************* +// Copyright 2009-2015 David Thorpe +// https://github.com/djthorpe/postgresql-kit +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +// ************************************* +// +// Copyright 2017 - ?? Sebastien Cotillard - Genose.org +// 07/2017 Sebastien Cotillard +// https://github.com/genose +// +// ************************************* +// ADDING Pool concurrent operation +// ************************************* #import #import #include - //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// #pragma mark C callback functions - //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// - //typedef struct __shared_blob soctted ; +//typedef struct __shared_blob soctted ; /** * This method is called from the run loop upon new data being available to read * on the socket, or the socket being able to write more data to the socket */ static int socketUsed_in = 0; void _socketCallback(CFSocketRef s, CFSocketCallBackType callBackType,CFDataRef address,const void* data,void* __self) { - - - + + + [NSThread sleepForTimeInterval:.01];; - + PGConnection* connection = (PGConnection* ) ((__bridge PGConnection* )__self); if(! connection // || socketUsed_in > 20 ) return ; socketUsed_in ++; - // dispatch_barrier_async(dispatch_get_main_queue(), ^{ + // dispatch_barrier_async(dispatch_get_main_queue(), ^{ #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"%@ :: %s :::: Socket CALL ... %lu ", NSStringFromClass([((__bridge NSObject *)__self) class]), (__FUNCTION__), callBackType); #endif @@ -58,10 +58,10 @@ void _socketCallback(CFSocketRef s, CFSocketCallBackType callBackType,CFDataRef NSLog(@"%@ :: %s :::: Socket CALL END .... (%lu) ", NSStringFromClass([((__bridge NSObject *)__self) class]), (__FUNCTION__), callBackType); #endif socketUsed_in = 0; - // }); - - // [NSThread sleepForTimeInterval:.1];; - + // }); + + // [NSThread sleepForTimeInterval:.1];; + } /** @@ -80,142 +80,142 @@ void _noticeProcessor(void* arg,const char* cString) { @implementation PGConnection (Callbacks) - //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// #pragma mark private methods - socket callbacks - //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// -(void)_socketCallbackNotification { @try { - NSParameterAssert(_connection); + NSParameterAssert(_connection); // consume input - PQconsumeInput(_connection); - + PQconsumeInput(_connection); + #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: loop "); + NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: loop "); #endif - + // loop for notifications - PGnotify* notify = nil; - while((notify = PQnotifies(_connection)) != nil) { - if([[self delegate] respondsToSelector:@selector(connection:notificationOnChannel:payload:)]) { + PGnotify* notify = nil; + while((notify = PQnotifies(_connection)) != nil) { + if([[self delegate] respondsToSelector:@selector(connection:notificationOnChannel:payload:)]) { #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: call delegate (%@) (%@)", [self delegate], NSStringFromSelector(@selector(connection:notificationOnChannel:payload:))); + NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: call delegate (%@) (%@)", [self delegate], NSStringFromSelector(@selector(connection:notificationOnChannel:payload:))); #endif - - NSString* channel = [NSString stringWithUTF8String:notify->relname]; - NSString* payload = [NSString stringWithUTF8String:notify->extra]; - [[self delegate] connection:self notificationOnChannel:channel payload:payload]; + + NSString* channel = [NSString stringWithUTF8String:notify->relname]; + NSString* payload = [NSString stringWithUTF8String:notify->extra]; + [[self delegate] connection:self notificationOnChannel:channel payload:payload]; + } + PQfreemem(notify); } - PQfreemem(notify); - } #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: free "); + NSLog(@"PGConnectionStateQuery - Read - _socketCallbackNotification :: free "); #endif } @catch (NSException *exception) { NSLog(@" %@ exeception .... %@",NSStringFromSelector(_cmd),exception); } @finally { - + } } -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus { - - //:: void (^callback)(BOOL usedPassword,NSError* error) = (__bridge void (^)(BOOL,NSError* ))(_callback); + + //:: void (^callback)(BOOL usedPassword,NSError* error) = (__bridge void (^)(BOOL,NSError* ))(_callback); if( ![((PGConnectionOperation*)[self currentPoolOperation]) valid] || [[self currentPoolOperation] poolIdentifier] != 0) return; - + pqstatus = PQconnectPoll(_connection); - + _callbackOperation = [((PGConnectionOperation*)[self masterPoolOperation]) getCallback]; void (^callback)(BOOL usedPassword,NSError* error ) = (__bridge void (^)( BOOL,NSError* ))( _callbackOperation ); - + BOOL needsPassword = PQconnectionNeedsPassword(_connection) ? YES : NO; BOOL usedPassword = PQconnectionUsedPassword(_connection) ? YES : NO; #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"%@ (%p) :: BEGIN :: - Read::BEGIN - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); #endif - // update the status + // update the status [self setState:PGConnectionStateNone]; [self _updateStatus]; // this also calls disconnect when rejected - - - // callback + + + // callback if(pqstatus==PGRES_POLLING_OK) { - // set up notice processor, set success condition + // set up notice processor, set success condition PQsetNoticeProcessor(_connection,_noticeProcessor,(__bridge void *)(self)); if([[self currentPoolOperation] poolIdentifier] == 0){ - - + + mach_port_t machTID = pthread_mach_thread_np(pthread_self()); - + const char * queued_name = [[NSString stringWithFormat:@"%s_%x_%@", "operation_dispacthed_threads", machTID, NSStringFromSelector(_cmd) ] cString]; #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" //// %s ", queued_name); #endif dispatch_queue_t queue_inRun = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); queue_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); - - - - + + + + [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; - + dispatch_async(queue_inRun,^ - + { - dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); - callback(usedPassword ? YES : NO,nil); - [((PGConnectionOperation*)[self masterPoolOperation]) finish]; - dispatch_semaphore_signal(ss); - + dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); + callback(usedPassword ? YES : NO,nil); + [((PGConnectionOperation*)[self masterPoolOperation]) finish]; + dispatch_semaphore_signal(ss); + } - - + + ); - - // dispatch_semaphore_wait(ss,DISPATCH_TIME_FOREVER); - // [self wait_semaphore_read:ss]; + + // dispatch_semaphore_wait(ss,DISPATCH_TIME_FOREVER); + // [self wait_semaphore_read:ss]; [self wait_semaphore_read: [((PGConnectionOperation*)[self masterPoolOperation]) semaphore] withQueue:queue_inRun]; - // [((PGConnectionOperation*)[self masterPoolOperation]) validate]; + // [((PGConnectionOperation*)[self masterPoolOperation]) validate]; } - // dispatch_destroy(queue); + // dispatch_destroy(queue); } else if(needsPassword) { - // error callback - connection not made, needs password + // error callback - connection not made, needs password callback(NO,[self raiseError:nil code:PGClientErrorNeedsPassword]); } else if(usedPassword) { - // error callback - connection not made, password was invalid + // error callback - connection not made, password was invalid callback(YES,[self raiseError:nil code:PGClientErrorInvalidPassword]); } else { - // error callback - connection not made, some other kind of rejection + // error callback - connection not made, some other kind of rejection callback(YES,[self raiseError:nil code:PGClientErrorRejected]); } - + #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"%@ (%p) :: END :: - Read::END - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); #endif - // :: TODO :: - //:: _callback = nil; - // - // [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; - // [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; - // [self pushPoolOperation]; + // :: TODO :: + //:: _callback = nil; + // + // [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; + // [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; + // [self pushPoolOperation]; } -(void)_socketCallbackResetEndedWithStatus:(PostgresPollingStatusType)pqstatus { NSParameterAssert([[self currentPoolOperation] valid]); - //:: void (^callback)(NSError* error) = (__bridge void (^)(NSError* ))(_callback); + //:: void (^callback)(NSError* error) = (__bridge void (^)(NSError* ))(_callback); void (^callback)(NSError* error) = (__bridge void (^)(NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); if(pqstatus==PGRES_POLLING_OK) { callback(nil); } else { callback([self raiseError:nil code:PGClientErrorRejected]); } - //:: _callback = nil; + //:: _callback = nil; [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; [self setState:PGConnectionStateNone]; [self _updateStatus]; // this also calls disconnect when rejected @@ -227,35 +227,35 @@ -(void)_socketCallbackResetEndedWithStatus:(PostgresPollingStatusType)pqstatus { * run. */ -(void)_socketCallbackConnect { - // ignore this call if either connection or callback are nil - + // ignore this call if either connection or callback are nil + PGConnectionOperation* currentpoolOpe = [self currentPoolOperation]; if(_connection==nil || ![[self currentPoolOperation] valid] || ( [currentpoolOpe poolIdentifier]) !=0 ) { - // || (_callback==nil) // && _callbackOperation == nil) + // || (_callback==nil) // && _callbackOperation == nil) return; } - + PostgresPollingStatusType pqstatus = PQconnectPoll(_connection); switch(pqstatus) { case PGRES_POLLING_READING: case PGRES_POLLING_WRITING: - // still connecting - ask to call poll again in runloop + // still connecting - ask to call poll again in runloop [self performSelector:@selector(_socketCallbackConnect) withObject:nil afterDelay:0.1]; break; case PGRES_POLLING_OK: case PGRES_POLLING_FAILED: if(( [currentpoolOpe poolIdentifier]) ==0 && [currentpoolOpe valid] ) - { - // finished connecting - // [self performSelectorInBackground:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; + { + // finished connecting + // [self performSelectorInBackground:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; [self performSelector:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil afterDelay:0.1]; - - // [self performSelector:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; - } - // [self _socketCallbackConnectEndedWithStatus:pqstatus]; + + // [self performSelector:@selector(_socketCallbackConnectEndedWithStatus:) withObject:nil]; + } + // [self _socketCallbackConnectEndedWithStatus:pqstatus]; break; default: break; @@ -268,17 +268,17 @@ -(void)_socketCallbackConnect { */ -(void)_socketCallbackReset { NSParameterAssert(_connection); - + PostgresPollingStatusType pqstatus = PQresetPoll(_connection); switch(pqstatus) { case PGRES_POLLING_READING: case PGRES_POLLING_WRITING: - // still connecting - call poll again + // still connecting - call poll again PQresetPoll(_connection); break; case PGRES_POLLING_OK: case PGRES_POLLING_FAILED: - // finished connecting + // finished connecting [self _socketCallbackResetEndedWithStatus:pqstatus]; break; default: @@ -292,31 +292,40 @@ -(void)_socketCallbackReset { */ -(void)_socketCallbackQueryRead { NSParameterAssert(_connection); - - PQconsumeInput(_connection); - - /* it seems that we don't really need to check for busy and it seems to - * create some issues, so ignore for now */ + + bool pgBusy = false; + + @synchronized (self) { + + + PQconsumeInput(_connection); + + /* it seems that we don't really need to check for busy and it seems to + * create some issues, so ignore for now */ // check for busy, return if more to do - if(PQisBusy(_connection)) { + + pgBusy = PQisBusy(_connection); + } + + if(pgBusy) { return; } - - // + + // NSParameterAssert([[self currentPoolOperation] valid]); - + PGConnectionOperation* currentPoolOperation = [self currentPoolOperation]; - - //:: void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); - + + //:: void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); + void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); - + #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@":::: PGConnectionStateQuery(%@::%p) - Read BEGIN - Result - :: callback \n_callback :: (%@)\n ********************************* ",NSStringFromClass([self class]), self , callback ); #endif - - - // consume results + + + // consume results PGresult* result = nil; while(1) { result = PQgetResult(_connection); @@ -328,14 +337,14 @@ -(void)_socketCallbackQueryRead { } NSError* error = nil; PGResult* r = nil; - - - // check for connection errors + + + // check for connection errors if(PQresultStatus(result)==PGRES_EMPTY_QUERY) { #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - Result - Empty Query"); #endif - // callback empty query + // callback empty query error = [self raiseError:nil code:PGClientErrorQuery reason:@"Empty query"]; PQclear(result); } else if(PQresultStatus(result)==PGRES_BAD_RESPONSE || PQresultStatus(result)==PGRES_FATAL_ERROR) { @@ -348,7 +357,7 @@ -(void)_socketCallbackQueryRead { #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - Result - READ Query RESULT (%@)",[currentPoolOperation queryString] ); #endif - // TODO: allocate a different kind of class + // TODO: allocate a different kind of class r = [[PGResult alloc] initWithResult:result format:[self tupleFormat]]; #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - Result - READ END (%s)", PQresultErrorMessage(result)); @@ -358,37 +367,37 @@ -(void)_socketCallbackQueryRead { #endif } if(r || error) { - + #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery(%@::%p) - Read - Result - Done :: callback \n ********************************* \nresult :: (%@)\n ********************************* \nerror :: (%@) \n_callback :: (%@)\n ********************************* ",NSStringFromClass([self class]), self, r, error, callback ); #endif - // queue up callback on nearest thread - + // queue up callback on nearest thread + dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); - + dispatch_async( qu_inRun ,^{ #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - callback %p ",callback); #endif - + callback(r,error); [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; [((PGConnectionOperation*)[self masterPoolOperation]) validate]; }); - + break; } } #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - Result - Clear " ); #endif - // all results consumed - update state + // all results consumed - update state [self setState:PGConnectionStateNone]; - - //:: _callback = nil; // release the callback + + //:: _callback = nil; // release the callback [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; - // [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; - + // [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; + [self _updateStatus]; #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read END - Result - Clear::End " ); @@ -402,12 +411,12 @@ -(void)_socketCallbackQueryRead { */ -(void)_socketCallbackQueryWrite { NSParameterAssert(_connection); - // flush + // flush int returnCode = PQflush(_connection); if(returnCode==-1) { - // callback with error + // callback with error NSParameterAssert([[self currentPoolOperation] valid]); - //:: void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); + //:: void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))(_callback); void (^callback)(PGResult* result,NSError* error) = (__bridge void (^)(PGResult* ,NSError* ))( [((PGConnectionOperation*)[self currentPoolOperation]) getCallback] ); NSError* error = [self raiseError:nil code:PGClientErrorState reason:@"Data flush failed during query"]; callback(nil,error); @@ -467,7 +476,7 @@ -(void)_socketCallback:(CFSocketCallBackType)callBackType { NSLog(@"PGConnectionStateQuery - Read - _socketCallback :: _socketCallbackNotification :: callback (%p)", [[self currentPoolOperation] getCallback]); #endif [self _socketCallbackNotification]; - + } else if(callBackType==kCFSocketWriteCallBack) { #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Write"); @@ -482,14 +491,14 @@ -(void)_socketCallback:(CFSocketCallBackType)callBackType { [self _socketCallbackNotification]; break; } - + [self _updateStatus]; } @catch (NSException *exception) { NSLog(@" %@ exeception .... %@",NSStringFromSelector(_cmd),exception); } @finally { - + } } diff --git a/src/Frameworks/PGClientKit/PGConnection+Execute.m b/src/Frameworks/PGClientKit/PGConnection+Execute.m index 381824d..8cd76b4 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Execute.m +++ b/src/Frameworks/PGClientKit/PGConnection+Execute.m @@ -79,16 +79,24 @@ -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGR className = [[self delegate] connection:self willExecute:query]; } - - // set state, update status - [self setState:PGConnectionStateQuery]; - - [self _updateStatus]; - // execute the command, free parameters - int resultFormat = ([self tupleFormat]==PGClientTupleFormatBinary) ? 1 : 0; - int returnCode = PQsendQueryParams(_connection,[query UTF8String],(int)params->size,params->types,(const char** )params->values,params->lengths,params->formats,resultFormat); + int resultFormat = 0; + int returnCode = 0; + @synchronized(self) + { + // set state, update status + [self setState:PGConnectionStateQuery]; + + [self _updateStatus]; + + // execute the command, free parameters + resultFormat = ([self tupleFormat]==PGClientTupleFormatBinary) ? 1 : 0; + returnCode = PQsendQueryParams(_connection,[query UTF8String],(int)params->size,params->types,(const char** )params->values,params->lengths,params->formats,resultFormat); + + } + _paramFree(params); + if(!returnCode) { #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"%@ :: %@ :: - execute - ERROR :: callback %p :: While EXECUTE (%@)", NSStringFromSelector(_cmd),NSStringFromClass([self class]), callback, query); @@ -292,11 +300,16 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem { if( qq_loop != [NSRunLoop mainRunLoop]){ dispatch_barrier_sync(qu_inRun, ^{ - [self wait_semaphore_read:sem withQueue:nil]; +// @synchronized (self) { + [self wait_semaphore_read:sem withQueue:nil]; +// } + }); }else{ +// @synchronized (self) { // dispatch_barrier_async(qu_inRun, ^{ [self wait_semaphore_read:sem withQueue:nil]; +// } // }); } @@ -318,7 +331,8 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ long diispacthed = YES; bool PG_busy = YES; - + @try { + while( diispacthed && _runloopsource @@ -327,9 +341,16 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ { - PG_busy = PQisBusy(_connection); +// PG_busy = PQisBusy(_connection); diispacthed = dispatch_semaphore_wait(sem,DISPATCH_TIME_NOW); + CFIndex indexInPool = CFArrayGetCount(_callbackOperationPool); + if(!indexInPool) + { + [NSException raise:NSInvalidArgumentException format:@" Warning :: Pool was sudently cleaned .... "]; + + break; + } if( nil == [[self currentPoolOperation] getCallback] || !diispacthed){ [NSThread sleepForTimeInterval:.01]; break; @@ -347,7 +368,13 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ }else{ break; } - + indexInPool = CFArrayGetCount(_callbackOperationPool); + if(!indexInPool) + { + [NSException raise:NSInvalidArgumentException format:@" Warning @2 :: Pool was sudently cleaned .... "]; + + break; + } if( diispacthed && ![[self currentPoolOperation] valid] ) [NSThread sleepForTimeInterval:.01]; @@ -365,6 +392,13 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" //// Clean **** :: %@ ", queued_name_STR); #endif + + } @catch (NSException *exception) { + NSLog(@"**************************** \n ERROR :: %@ :: \n **************************** \n [ %@ ] \n **************************** \n ", NSStringFromSelector(_cmd), exception); + dispatch_semaphore_signal(sem); + } @finally { + + } [[NSThread currentThread] cancel]; #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" //// END :: %@ ", queued_name_STR); diff --git a/src/Frameworks/PGClientKit/PGConnection.m b/src/Frameworks/PGClientKit/PGConnection.m index bced2ee..f124019 100644 --- a/src/Frameworks/PGClientKit/PGConnection.m +++ b/src/Frameworks/PGClientKit/PGConnection.m @@ -75,7 +75,7 @@ -(instancetype)init { _connection = nil; _cancel = nil; // _callback = nil; - _stateOperation = PGOperationStateNone; + _stateOperation = PGOperationStateNone; _callbackOperation = nil; _callbackOperationPool = CFArrayCreateMutable(NULL, 64, &kCFTypeArrayCallBacks); // (NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); @@ -278,15 +278,15 @@ -(void)_updateStatus { // from continuing NSNumber* key = [NSNumber numberWithInt:oldStatus]; NSString* description = [PGConnectionStatusDescription objectForKey:key]; -// [self performSelectorOnMainThread:@selector(_updateStatusDelayed:) withObject:@[ key,description ] waitUntilDone:NO]; + // [self performSelectorOnMainThread:@selector(_updateStatusDelayed:) withObject:@[ key,description ] waitUntilDone:NO]; [self performSelector:@selector(_updateStatusDelayed:) withObject:@[ key,description ] ]; -#ifdef DEBUG2 && DEBUG2 == 1 +#if defined(DEBUG2) && DEBUG2 == 1 NSLog(@"status => %@ %@",key,description); #endif // if connection is rejected, then call disconnect if(oldStatus==PGConnectionStatusRejected) { -#ifdef DEBUG2 && DEBUG2 == 1 +#if defined(DEBUG2) && DEBUG2 == 1 NSLog(@"_updateStatus => disconnect/rejected :: %@ %@",key,description); #endif [self disconnect]; @@ -310,12 +310,16 @@ -(PGConnectionOperation*)masterPoolOperation { PGConnectionOperation* masterPoolOperation = nil; - CFIndex indexInPool = CFArrayGetCount(_callbackOperationPool); - if(indexInPool > 0 ) - { - masterPoolOperation = (__bridge PGConnectionOperation*) CFArrayGetValueAtIndex(_callbackOperationPool, 0); - }else{ - NSLog(@" ERROR :: NO master pool .... "); + @synchronized (self) { + + CFIndex indexInPool = CFArrayGetCount(_callbackOperationPool); + if(indexInPool > 0 ) + { + masterPoolOperation = (__bridge PGConnectionOperation*) CFArrayGetValueAtIndex(_callbackOperationPool, 0); + }else{ + NSLog(@" ERROR :: NO master pool .... "); + } + } #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 // NSLog(@" %@::%@ :: FETCH cureent pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, masterPoolOperation); @@ -328,18 +332,21 @@ -(PGConnectionOperation*)masterPoolOperation -(PGConnectionOperation*)currentPoolOperation { PGConnectionOperation* masterPoolOperation = nil; - - CFIndex indexInPool = CFArrayGetCount(_callbackOperationPool); - if(indexInPool > 0 ) - { - masterPoolOperation = (__bridge PGConnectionOperation*) CFArrayGetValueAtIndex(_callbackOperationPool, indexInPool-1); - }else{ - NSLog(@" ERROR :: NO pool .... "); + @synchronized (self) { + + CFIndex indexInPool = CFArrayGetCount(_callbackOperationPool); + if(indexInPool > 0 ) + { + masterPoolOperation = (__bridge PGConnectionOperation*) CFArrayGetValueAtIndex(_callbackOperationPool, ((indexInPool-1) >=0 ? indexInPool-1 : 0) ); + }else{ + NSLog(@" ERROR :: NO pool .... "); + } + } #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 -// NSLog(@" %@::%@ :: FETCH cureent pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, masterPoolOperation); + // NSLog(@" %@::%@ :: FETCH cureent pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, masterPoolOperation); #endif - + return masterPoolOperation; } @@ -367,10 +374,10 @@ -(PGConnectionOperation*)prevPoolOperation -(id)addOperation: (id)operationClass withCallBackWhenDone:(void*)callBackWhenDone withCallBackWhenError:(void*)callBackWhenError { void * recall_callbackDone = (__bridge void *)((__bridge void (^)(void* result, void* error)) (callBackWhenDone)); - - -// callBackWhenDone(result, error); -// [[ ((PGConnectionOperation*)self) getConnectionDelegate] invalidateOperation: [((PGConnectionOperation*)self) poolIdentifier] ]; + + + // callBackWhenDone(result, error); + // [[ ((PGConnectionOperation*)self) getConnectionDelegate] invalidateOperation: [((PGConnectionOperation*)self) poolIdentifier] ]; CFIndex indexInPool = CFArrayGetCount(_callbackOperationPool); @@ -421,12 +428,12 @@ -(void)_waitingPoolOperationForResult currentPoolOpe = [self currentPoolOperation]; - + if( ([((PGConnectionOperation*)currentPoolOpe) valid] && [((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0 ) -// && [((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0 + // && [((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0 || (_stateOperation) ) { @@ -434,9 +441,9 @@ -(void)_waitingPoolOperationForResult isRunning = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; isRunning = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; [NSThread sleepForTimeInterval:.1]; -// NSLog(@" >>>>> :::: %@ .... %d",NSStringFromSelector(_cmd),isRunning); + // NSLog(@" >>>>> :::: %@ .... %d",NSStringFromSelector(_cmd),isRunning); -// return; + // return; }else{ break; @@ -453,7 +460,7 @@ -(void)_waitingPoolOperationForResultMaster PGConnectionOperation* currentPoolOpe = [self currentPoolOperation]; while ([((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0) { - + prevPoolOpe = [self prevPoolOperation]; currentPoolOpe = [self currentPoolOperation]; @@ -464,8 +471,8 @@ -(void)_waitingPoolOperationForResultMaster && [((PGConnectionOperation*)currentPoolOpe) valid] ) { -// NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; -// isRunning = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; + // NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; + // isRunning = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; [NSThread sleepForTimeInterval:.1]; NSLog(@" >>>>> master wait :::: %@ .... %d",NSStringFromSelector(_cmd),isRunning); @@ -475,7 +482,7 @@ -(void)_waitingPoolOperationForResultMaster break; } } - + } diff --git a/src/Frameworks/PGClientKit/PGResult.m b/src/Frameworks/PGClientKit/PGResult.m index 97c17a1..a07df47 100644 --- a/src/Frameworks/PGClientKit/PGResult.m +++ b/src/Frameworks/PGClientKit/PGResult.m @@ -49,6 +49,7 @@ -(void)dealloc { [NSThread sleepForTimeInterval:1.0]; [_cachedData removeAllObjects]; PQclear((PGresult* )_result); + [NSThread sleepForTimeInterval:1.0]; } } From 43f6060bd5e99b985442ce80a622b91ad46dc250 Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Thu, 10 Aug 2017 18:22:49 +0200 Subject: [PATCH 15/21] Correcting concurrent thread relative BAD_EXC_ACCESS --- .../PGClientKit/PGConnection+Callbacks.m | 151 +++++++++++------- .../PGClientKit/PGConnection+Execute.m | 13 +- src/Frameworks/PGClientKit/PGConnection.h | 6 +- .../PGClientKit/PGConnectionOperation.h | 6 +- .../PGClientKit/PGConnectionOperation.m | 21 +++ src/Frameworks/PGClientKit/PGResult.h | 16 ++ src/Frameworks/PGClientKit/PGResult.m | 132 ++++++++++++++- 7 files changed, 280 insertions(+), 65 deletions(-) diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index 1e75f0a..6479f64 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -130,8 +130,7 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus pqstatus = PQconnectPoll(_connection); - _callbackOperation = [((PGConnectionOperation*)[self masterPoolOperation]) getCallback]; - void (^callback)(BOOL usedPassword,NSError* error ) = (__bridge void (^)( BOOL,NSError* ))( _callbackOperation ); + BOOL needsPassword = PQconnectionNeedsPassword(_connection) ? YES : NO; BOOL usedPassword = PQconnectionUsedPassword(_connection) ? YES : NO; @@ -142,67 +141,106 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus [self setState:PGConnectionStateNone]; [self _updateStatus]; // this also calls disconnect when rejected - - // callback - if(pqstatus==PGRES_POLLING_OK) { - // set up notice processor, set success condition - PQsetNoticeProcessor(_connection,_noticeProcessor,(__bridge void *)(self)); - if([[self currentPoolOperation] poolIdentifier] == 0){ - - - mach_port_t machTID = pthread_mach_thread_np(pthread_self()); + @try { + // callback + + + _callbackOperation = [((PGConnectionOperation*)[self masterPoolOperation]) getCallback]; + void (^callback)(BOOL usedPassword,NSError* error ) = nil; + if(_callbackOperation != nil) + { + callback = (__bridge void (^)( BOOL,NSError* ))( _callbackOperation ); - const char * queued_name = [[NSString stringWithFormat:@"%s_%x_%@", "operation_dispacthed_threads", machTID, NSStringFromSelector(_cmd) ] cString]; + }else{ + [NSException raise:NSInvalidArgumentException format:@" Warning :: Master Pool callback was sudently cleaned .... "]; + } + + + + if(pqstatus==PGRES_POLLING_OK) { + // set up notice processor, set success condition + PQsetNoticeProcessor(_connection,_noticeProcessor,(__bridge void *)(self)); + if([[self currentPoolOperation] poolIdentifier] == 0){ + + + mach_port_t machTID = pthread_mach_thread_np(pthread_self()); + + const char * queued_name = [[NSString stringWithFormat:@"%s_%x_%@", "operation_dispacthed_threads", machTID, NSStringFromSelector(_cmd) ] cString]; #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@" //// %s ", queued_name); + NSLog(@" //// %s ", queued_name); #endif - dispatch_queue_t queue_inRun = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); - queue_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); - - - - - [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; - - dispatch_async(queue_inRun,^ - - { - dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); - callback(usedPassword ? YES : NO,nil); - [((PGConnectionOperation*)[self masterPoolOperation]) finish]; - dispatch_semaphore_signal(ss); + dispatch_queue_t queue_inRun = dispatch_queue_create(queued_name, DISPATCH_QUEUE_CONCURRENT); + queue_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); + + + + + [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; + + dispatch_async(queue_inRun,^{ + @try{ + + dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); + _callbackOperation = [((PGConnectionOperation*)[self masterPoolOperation]) getCallback]; + if(_callbackOperation != nil) + { + void (^callback_master)(BOOL usedPassword,NSError* error ) = (__bridge void (^)( BOOL,NSError* ))( _callbackOperation ); + + callback_master(usedPassword ? YES : NO,nil); + + }else{ + [NSException raise:NSInvalidArgumentException format:@" Warning :: Master Pool callback (async) was sudently cleaned .... "]; + } + dispatch_semaphore_signal(ss); + [((PGConnectionOperation*)[self masterPoolOperation]) finish]; + } @catch (NSException *exception) { + NSLog(@"**************************** \n ERROR :: %@ :: \n **************************** \n [ %@ ] \n **************************** \n ", NSStringFromSelector(_cmd), exception); + dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); + dispatch_semaphore_signal(ss); + } @finally { + + } + + } - } - - - ); - - // dispatch_semaphore_wait(ss,DISPATCH_TIME_FOREVER); - // [self wait_semaphore_read:ss]; - [self wait_semaphore_read: [((PGConnectionOperation*)[self masterPoolOperation]) semaphore] withQueue:queue_inRun]; - // [((PGConnectionOperation*)[self masterPoolOperation]) validate]; + + ); + + // dispatch_semaphore_wait(ss,DISPATCH_TIME_FOREVER); + // [self wait_semaphore_read:ss]; + [self wait_semaphore_read: [((PGConnectionOperation*)[self masterPoolOperation]) semaphore] withQueue:queue_inRun]; + // [((PGConnectionOperation*)[self masterPoolOperation]) validate]; + } + // dispatch_destroy(queue); + } else if(needsPassword) { + // error callback - connection not made, needs password + callback(NO,[self raiseError:nil code:PGClientErrorNeedsPassword]); + } else if(usedPassword) { + // error callback - connection not made, password was invalid + callback(YES,[self raiseError:nil code:PGClientErrorInvalidPassword]); + } else { + // error callback - connection not made, some other kind of rejection + callback(YES,[self raiseError:nil code:PGClientErrorRejected]); } - // dispatch_destroy(queue); - } else if(needsPassword) { - // error callback - connection not made, needs password - callback(NO,[self raiseError:nil code:PGClientErrorNeedsPassword]); - } else if(usedPassword) { - // error callback - connection not made, password was invalid - callback(YES,[self raiseError:nil code:PGClientErrorInvalidPassword]); - } else { - // error callback - connection not made, some other kind of rejection - callback(YES,[self raiseError:nil code:PGClientErrorRejected]); - } - + #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@"%@ (%p) :: END :: - Read::END - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); + NSLog(@"%@ (%p) :: END :: - Read::END - %@ :: free (callback %p)", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), callback); #endif - // :: TODO :: - //:: _callback = nil; - // - // [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; - // [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; - // [self pushPoolOperation]; + // :: TODO :: + //:: _callback = nil; + // + // [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; + // [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; + // [self pushPoolOperation]; + + + } @catch (NSException *exception) { + NSLog(@"**************************** \n ERROR :: %@ :: \n **************************** \n [ %@ ] \n **************************** \n ", NSStringFromSelector(_cmd), exception); + dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); + dispatch_semaphore_signal(ss); + } @finally { + + } } @@ -382,6 +420,7 @@ -(void)_socketCallbackQueryRead { callback(r,error); [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; + [((PGConnectionOperation*)[self currentPoolOperation]) finish]; [((PGConnectionOperation*)[self masterPoolOperation]) validate]; }); diff --git a/src/Frameworks/PGClientKit/PGConnection+Execute.m b/src/Frameworks/PGClientKit/PGConnection+Execute.m index 8cd76b4..d0969e5 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Execute.m +++ b/src/Frameworks/PGClientKit/PGConnection+Execute.m @@ -132,7 +132,7 @@ -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGR #pragma mark public methods - execution //////////////////////////////////////////////////////////////////////////////// --(void)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) callback { +-(id)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) callback { NSParameterAssert([query isKindOfClass:[NSString class]] || [query isKindOfClass:[PGQuery class]]); NSParameterAssert(callback); @@ -149,6 +149,8 @@ -(void)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) cal NSString* query2 = nil; NSError* error = nil; + __block id queryResults = nil; + if([query isKindOfClass:[NSString class]]) { query2 = query; } else { @@ -170,7 +172,8 @@ -(void)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) cal #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" .... semaphore callback..... %@", [[self currentPoolOperation] semaphore]); #endif - + queryResults = [[self currentPoolOperation] setResults: result_recall ]; +// [result_recall fetchRowAsDictionary] callback(result_recall , error_recall); #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 @@ -193,10 +196,14 @@ -(void)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) cal dispatch_semaphore_t semaphore_query_send = [[self currentPoolOperation] semaphore]; [self wait_semaphore_read: semaphore_query_send withQueue:queue_inRun]; + +// NSLog(@" RESULTS ::\n Query : %@ \n:: Result : %@ ", query2, queryResults); + #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@" -_-_-_-_ Query END -_-_-_-_- :: %@ ", queued_name_STR); + NSLog(@" -_-_-_-_ Query END -_-_-_-_- :: Query : %@ :: %@ ", query2, queued_name_STR); #endif _stateOperation = PGOperationStateNone; + return (queryResults)?[queryResults copy] : nil; } -(PGResult* )execute:(id)query error:(NSError** )error { diff --git a/src/Frameworks/PGClientKit/PGConnection.h b/src/Frameworks/PGClientKit/PGConnection.h index ad05584..4c3bc8e 100644 --- a/src/Frameworks/PGClientKit/PGConnection.h +++ b/src/Frameworks/PGClientKit/PGConnection.h @@ -294,8 +294,10 @@ typedef enum { * * @param query Either an NSString or PGQuery object * @param callback The callback which is called on completion of the execution + * + * @return The (id ?? shall be Transversable ?? ) object containing results of the query */ --(void)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) callback; +-(id)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) callback; /** * This method execute a statement on the server syncronously, then returns @@ -306,7 +308,7 @@ typedef enum { * @param query Either an NSString or PGQuery object * @param error A pointer to an error object to be returned on error * - * @return The RGResult object containing results of the query + * @return The PGResult object containing results of the query */ -(PGResult* )execute:(id)query error:(NSError** )error; diff --git a/src/Frameworks/PGClientKit/PGConnectionOperation.h b/src/Frameworks/PGClientKit/PGConnectionOperation.h index 84e9628..aa727bb 100644 --- a/src/Frameworks/PGClientKit/PGConnectionOperation.h +++ b/src/Frameworks/PGClientKit/PGConnectionOperation.h @@ -29,7 +29,7 @@ id _operationConnectionClassRef; void * _callbackWhenDone; - void* _callbackWhenError; + void * _callbackWhenError; id _operation; id _operationInfo; id _operationType; @@ -37,6 +37,7 @@ NSInteger _operationStatus; bool _invalidated; dispatch_semaphore_t semaphore; + id resultsSet; } //(void(^)(id result,NSError* error)) -(instancetype)initWithParametersDelegate:(id)connectionDelegate withRefPoolIdentifier:(NSInteger)poolIdentifier refClassOperation:(id)operation callWhenDone:(void*) callBackBlockDone callWhenError:(void(^)(id result,NSError* error)) callBackBlockError; @@ -55,4 +56,7 @@ -(void)invalidate; -(void *)getCallback; +-(id)setResults:(id)results; +-(id)results; + @end diff --git a/src/Frameworks/PGClientKit/PGConnectionOperation.m b/src/Frameworks/PGClientKit/PGConnectionOperation.m index 8b4a4c3..87dff24 100644 --- a/src/Frameworks/PGClientKit/PGConnectionOperation.m +++ b/src/Frameworks/PGClientKit/PGConnectionOperation.m @@ -119,6 +119,25 @@ -(void *)getCallback // }; return _callbackWhenDone; } +#pragma mark results +-(id)setResults:(id)results +{ +// if(results && [results respondsToSelector:@selector(copyWithZone:)]) +// { +// resultsSet = [results copy]; +// }else +// { + resultsSet = results; +// } + + return resultsSet; +} +-(id)results +{ + return resultsSet; +} + +#pragma mark String Readable -(id)UTF8String { if([_operation respondsToSelector:@selector(UTF8String)]) @@ -128,6 +147,7 @@ -(id)UTF8String return nil; } + -(id)queryString { if([_operation respondsToSelector:@selector(queryString)]) @@ -137,6 +157,7 @@ -(id)queryString return nil; } + -(id)string { id queryStringDescription = [self queryString]; diff --git a/src/Frameworks/PGClientKit/PGResult.h b/src/Frameworks/PGClientKit/PGResult.h index 794394c..a1f6de3 100644 --- a/src/Frameworks/PGClientKit/PGResult.h +++ b/src/Frameworks/PGClientKit/PGResult.h @@ -47,4 +47,20 @@ */ -(NSArray* )arrayForColumn:(NSString* )columnName; + +/* Transverseable object as Array */ + +-(instancetype)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys; // :: unimplemented + + +-(NSArray *)allKeys; +-(NSEnumerator *)keyEnumerator; + +-(id _Nullable )valueForKeyPath:(NSString * _Nonnull)keyPath ; + +-(id _Nullable )valueForKey:(NSString *_Nonnull)key ; +-(id _Nullable )valueForUndefinedKey:(NSString * _Nonnull)key ; +-(BOOL)keyExists:(NSString * _Nonnull)keyPath; + +-(NSInteger)count; @end diff --git a/src/Frameworks/PGClientKit/PGResult.m b/src/Frameworks/PGClientKit/PGResult.m index a07df47..d8705bf 100644 --- a/src/Frameworks/PGClientKit/PGResult.m +++ b/src/Frameworks/PGClientKit/PGResult.m @@ -46,10 +46,14 @@ -(void)dealloc { @synchronized(self) { - [NSThread sleepForTimeInterval:1.0]; + [NSThread sleepForTimeInterval:0.1]; [_cachedData removeAllObjects]; - PQclear((PGresult* )_result); - [NSThread sleepForTimeInterval:1.0]; +// _result = ((PGresult* )_result); + if( _result != NULL ){ + PQclear((PGresult* )_result); + } + _result = NULL; + [NSThread sleepForTimeInterval:0.1]; } } @@ -60,6 +64,7 @@ -(PGClientTupleFormat)format { } -(NSUInteger)size { + NSParameterAssert(_result); NSUInteger _number = NSIntegerMax; if(_number==NSIntegerMax) { _number = PQntuples(_result); @@ -68,6 +73,7 @@ -(NSUInteger)size { } -(NSUInteger)numberOfColumns { + NSParameterAssert(_result); NSUInteger _number = NSIntegerMax; if(_number==NSIntegerMax) { _number = PQnfields(_result); @@ -76,6 +82,7 @@ -(NSUInteger)numberOfColumns { } -(NSUInteger)affectedRows { + NSParameterAssert(_result); NSUInteger _number = NSIntegerMax; if(_number==NSIntegerMax) { NSString* affectedRows = [NSString stringWithUTF8String:PQcmdTuples(_result)]; @@ -89,6 +96,7 @@ -(BOOL)dataReturned { } -(NSArray* )columnNames { + NSParameterAssert(_result); NSUInteger numberOfColumns = [self numberOfColumns]; NSMutableArray* theColumns = [NSMutableArray arrayWithCapacity:numberOfColumns]; for(NSUInteger i = 0; i < numberOfColumns; i++) { @@ -179,6 +187,124 @@ -(NSArray* )arrayForColumn:(NSString* )columnName { return array; } + +#pragma mark ********* KVC Protocol ******** + + +-(void)setValue:(id)value forUndefinedKey:(NSString *)key +{ + NSLog(@" :::: \n :: %@ :: %@ \n :: %@ \n :::::",NSStringFromSelector(_cmd), key, self ); + NSMutableDictionary * dictTmp = [((NSMutableDictionary*)_cachedData) mutableCopy]; + [((NSMutableDictionary*)dictTmp) setValue:value forKey: key]; + [((NSMutableDictionary*)_cachedData) setDictionary: dictTmp]; + +} +- (void)setObject:(id)anObject forKey:(NSString * _Nonnull)key +{ + NSLog(@" :::: \n :: %@ :: %@ \n :: %@ \n :::::",NSStringFromSelector(_cmd), key, self ); + NSMutableDictionary * dictTmp = [((NSMutableDictionary*)_cachedData) mutableCopy]; + [((NSMutableDictionary*)dictTmp) setValue:anObject forKey: key]; + [((NSMutableDictionary*)_cachedData) setDictionary: dictTmp]; +} + +-(BOOL)keyExists:(NSString*)keyPath +{ + return ((BOOL)[((NSMutableDictionary*)_cachedData) valueForKeyPath: keyPath]); +} + +-(id)valueForKeyPath:(NSString *)keyPath +{ + return [_cachedData valueForKeyPath:keyPath]; +} + +-(id)valueForKey:(NSString *)key +{ + NSLog(@" :::: \n :: %@ :: %@ \n :: %@ \n :::::",NSStringFromSelector(_cmd), key, self ); + id value = nil; + if ( ! [key containsString: @"resultDetail."]) { + value = [_cachedData objectForKey:key]; + + if( nil == value ) + { + + value = [_cachedData valueForKeyPath:[NSString stringWithFormat:@"resultDetail.%@",key]]; + + + } + } + + return value; +} + +-(id)valueForUndefinedKey:(NSString *)key +{ + NSLog(@" :::: \n :: %@ :: %@ \n :: %@ \n :::::",NSStringFromSelector(_cmd), key, self ); + id value = [((NSMutableDictionary*)_cachedData) valueForKey:key]; + return value; +} + +-(id)objectForKey:(id)key +{ + // :: + NSLog(@" :::: \n :: %@ :: %@ \n :: %@ \n :::::",NSStringFromSelector(_cmd), key, self ); + id value = nil; + + value = [((NSMutableDictionary*)_cachedData) objectForKey:key]; + + if( nil == value ) + { +// if(![key respondsToSelector:@selector(UTF8String)]) +// { +// key = [NSString stringWithFormat:@"%ld",key]; +// } + + value = [((NSMutableDictionary*)_cachedData) valueForKeyPath:[NSString stringWithFormat:@"%@",key]]; + } + + + return value; +} + +-(NSUInteger)count +{ + +// bool cnt = [ _cachedData isKindOfClass:[NSDictionary class]] && [self dataReturned]; +// if(!cnt) +// { +// return 0; +// } +// +// id keysC = [((NSMutableDictionary*)_cachedData) allKeys]; +// NSUInteger allkeysC = [keysC count]; + NSInteger cnt = ( _result ) ? (long) PQntuples(_result): 0; + return cnt; +} + +-(NSArray *)allKeys +{ + + id keysC = [((NSMutableDictionary*)_cachedData) allKeys]; + return keysC ; +} + +-(NSEnumerator *)keyEnumerator +{ + return (([_cachedData respondsToSelector: @selector(keyEnumerator) ]) ? [_cachedData keyEnumerator] : nil); +} +-(instancetype)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys +{ + [NSException raise:NSInvocationOperationCancelledException format:@"\n ************ \n ********** \n ERROR :: Unimplemented :: %@ :: \n >>> args / keys :: %@ \n >>>> keys :: %@ \n ************ \n ********** \n ",NSStringFromSelector(_cmd), keys, objects]; + return self; +} + +-(id)copyWithZone:(NSZone *)zone +{ + + PGResult* newClass = [[[self class] allocWithZone:zone] initWithResult: _result format: [self format] encoding: _encoding ]; + + return newClass; + +} //////////////////////////////////////////////////////////////////////////////// -(NSString* )description { From e7eb56007b558afbfe6226a52f34315faa18f436 Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Tue, 22 Aug 2017 18:58:28 +0200 Subject: [PATCH 16/21] Performance tunning and connection debug Performance tunning and connection debug --- .../PGClientKit/PGConnection+Callbacks.m | 2 +- .../PGClientKit/PGConnection+Execute.m | 30 ++++++++++++++----- src/Frameworks/PGClientKit/PGConnection.m | 4 +-- src/Frameworks/PGClientKit/PGResult.m | 4 +-- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index 6479f64..d6dde1d 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -41,7 +41,7 @@ void _socketCallback(CFSocketRef s, CFSocketCallBackType callBackType,CFDataRef - [NSThread sleepForTimeInterval:.01];; + [NSThread sleepForTimeInterval:0.01];; PGConnection* connection = (PGConnection* ) ((__bridge PGConnection* )__self); if(! connection diff --git a/src/Frameworks/PGClientKit/PGConnection+Execute.m b/src/Frameworks/PGClientKit/PGConnection+Execute.m index d0969e5..247cf4b 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Execute.m +++ b/src/Frameworks/PGClientKit/PGConnection+Execute.m @@ -338,6 +338,9 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ long diispacthed = YES; bool PG_busy = YES; + + long timeoutThread = 600; // .05 * 600 = 30s + @try { while( @@ -347,6 +350,7 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ && _connection ) { + timeoutThread -= 0.05; // PG_busy = PQisBusy(_connection); diispacthed = dispatch_semaphore_wait(sem,DISPATCH_TIME_NOW); @@ -358,12 +362,22 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ break; } + + [NSThread sleepForTimeInterval:0.05]; + + if( timeoutThread <= 0) + { + NSLog(@" //// STEP :: %@ :: Thread Time OUT %@ ",NSStringFromSelector(_cmd), queued_name_STR); + break; + } + + if( nil == [[self currentPoolOperation] getCallback] || !diispacthed){ - [NSThread sleepForTimeInterval:.01]; +// [NSThread sleepForTimeInterval:0.1]; break; } - [NSThread sleepForTimeInterval:.01]; + if([[self currentPoolOperation] valid] ) @@ -376,14 +390,16 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ break; } indexInPool = CFArrayGetCount(_callbackOperationPool); + if(!indexInPool) { [NSException raise:NSInvalidArgumentException format:@" Warning @2 :: Pool was sudently cleaned .... "]; break; } - if( diispacthed && ![[self currentPoolOperation] valid] ) - [NSThread sleepForTimeInterval:.01]; + +// if( diispacthed && ![[self currentPoolOperation] valid] ) +// [NSThread sleepForTimeInterval:0.01]; // if( diispacthed //// && !isRunningThreadMain && !isRunningThreadMain @@ -421,7 +437,7 @@ -(void)dispathCall bool isRunningThreadMain = YES; bool isRunningThread = YES; - [NSThread sleepForTimeInterval:.01];; +// [NSThread sleepForTimeInterval:0.05];; PGConnectionStatus con_status = [((PGConnection*)self) status]; if( ( @@ -457,7 +473,7 @@ -(void)dispathCall isRunningThread = [qq_loop runMode:NSRunLoopCommonModes beforeDate:theNextDate]; if(!isRunningThread) { - [NSThread sleepForTimeInterval:.1];; + [NSThread sleepForTimeInterval:0.01];; } if( qq_loop != [NSRunLoop mainRunLoop]){ @@ -465,7 +481,7 @@ -(void)dispathCall [qq_loop runUntilDate:theNextDate]; if(!isRunningThread){ [qq_loop_main runUntilDate:theNextDate]; - [NSThread sleepForTimeInterval:.1];; + [NSThread sleepForTimeInterval:0.01];; } // [qq_loop_main runUntilDate:theNextDate]; diff --git a/src/Frameworks/PGClientKit/PGConnection.m b/src/Frameworks/PGClientKit/PGConnection.m index f124019..1783ea3 100644 --- a/src/Frameworks/PGClientKit/PGConnection.m +++ b/src/Frameworks/PGClientKit/PGConnection.m @@ -440,7 +440,7 @@ -(void)_waitingPoolOperationForResult NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; isRunning = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; isRunning = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; - [NSThread sleepForTimeInterval:.1]; + [NSThread sleepForTimeInterval:0.02]; // NSLog(@" >>>>> :::: %@ .... %d",NSStringFromSelector(_cmd),isRunning); // return; @@ -473,7 +473,7 @@ -(void)_waitingPoolOperationForResultMaster { // NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; // isRunning = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; - [NSThread sleepForTimeInterval:.1]; + [NSThread sleepForTimeInterval:0.02]; NSLog(@" >>>>> master wait :::: %@ .... %d",NSStringFromSelector(_cmd),isRunning); // return; diff --git a/src/Frameworks/PGClientKit/PGResult.m b/src/Frameworks/PGClientKit/PGResult.m index d8705bf..5708185 100644 --- a/src/Frameworks/PGClientKit/PGResult.m +++ b/src/Frameworks/PGClientKit/PGResult.m @@ -46,14 +46,14 @@ -(void)dealloc { @synchronized(self) { - [NSThread sleepForTimeInterval:0.1]; + [NSThread sleepForTimeInterval:0.01]; [_cachedData removeAllObjects]; // _result = ((PGresult* )_result); if( _result != NULL ){ PQclear((PGresult* )_result); } _result = NULL; - [NSThread sleepForTimeInterval:0.1]; + [NSThread sleepForTimeInterval:0.01]; } } From 429b45692f43503f40b067d7467e1ac72e2cecbd Mon Sep 17 00:00:00 2001 From: "genose.org" Date: Wed, 23 Aug 2017 10:55:55 +0200 Subject: [PATCH 17/21] some tunning --- .../PGClientKit/PGConnection+Callbacks.m | 20 ++- .../PGClientKit/PGConnection+Execute.m | 4 +- src/Frameworks/PGClientKit/PGConnection.m | 150 +++++++++--------- src/Frameworks/PGClientKit/PGResult.m | 4 +- 4 files changed, 95 insertions(+), 83 deletions(-) diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index d6dde1d..0592ba9 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -41,8 +41,8 @@ void _socketCallback(CFSocketRef s, CFSocketCallBackType callBackType,CFDataRef - [NSThread sleepForTimeInterval:0.01];; - +// [NSThread sleepForTimeInterval:0.01]; + PGConnection* connection = (PGConnection* ) ((__bridge PGConnection* )__self); if(! connection // || socketUsed_in > 20 @@ -124,8 +124,12 @@ -(void)_socketCallbackNotification { -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus { //:: void (^callback)(BOOL usedPassword,NSError* error) = (__bridge void (^)(BOOL,NSError* ))(_callback); - if( ![((PGConnectionOperation*)[self currentPoolOperation]) valid] - || [[self currentPoolOperation] poolIdentifier] != 0) + PGConnectionOperation* currentPool = ((PGConnectionOperation*)[self currentPoolOperation]); + if( + !_connection || + !currentPool || + ![currentPool valid] || + [currentPool poolIdentifier] != 0) return; pqstatus = PQconnectPoll(_connection); @@ -160,7 +164,13 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus if(pqstatus==PGRES_POLLING_OK) { // set up notice processor, set success condition PQsetNoticeProcessor(_connection,_noticeProcessor,(__bridge void *)(self)); - if([[self currentPoolOperation] poolIdentifier] == 0){ + currentPool = [self currentPoolOperation]; + if(!currentPool) { + + return; + } + + if([currentPool poolIdentifier] == 0){ mach_port_t machTID = pthread_mach_thread_np(pthread_self()); diff --git a/src/Frameworks/PGClientKit/PGConnection+Execute.m b/src/Frameworks/PGClientKit/PGConnection+Execute.m index 247cf4b..4900e38 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Execute.m +++ b/src/Frameworks/PGClientKit/PGConnection+Execute.m @@ -473,7 +473,7 @@ -(void)dispathCall isRunningThread = [qq_loop runMode:NSRunLoopCommonModes beforeDate:theNextDate]; if(!isRunningThread) { - [NSThread sleepForTimeInterval:0.01];; + [NSThread sleepForTimeInterval:0.1];; } if( qq_loop != [NSRunLoop mainRunLoop]){ @@ -481,7 +481,7 @@ -(void)dispathCall [qq_loop runUntilDate:theNextDate]; if(!isRunningThread){ [qq_loop_main runUntilDate:theNextDate]; - [NSThread sleepForTimeInterval:0.01];; + [NSThread sleepForTimeInterval:0.1];; } // [qq_loop_main runUntilDate:theNextDate]; diff --git a/src/Frameworks/PGClientKit/PGConnection.m b/src/Frameworks/PGClientKit/PGConnection.m index 1783ea3..74bb5f1 100644 --- a/src/Frameworks/PGClientKit/PGConnection.m +++ b/src/Frameworks/PGClientKit/PGConnection.m @@ -317,7 +317,8 @@ -(PGConnectionOperation*)masterPoolOperation { masterPoolOperation = (__bridge PGConnectionOperation*) CFArrayGetValueAtIndex(_callbackOperationPool, 0); }else{ - NSLog(@" ERROR :: NO master pool .... "); +// NSLog(@" ERROR :: NO master pool .... "); + [NSException raise:NSInvalidArgumentException format:@" ERROR :: NO master pool .... "]; } } @@ -339,7 +340,8 @@ -(PGConnectionOperation*)currentPoolOperation { masterPoolOperation = (__bridge PGConnectionOperation*) CFArrayGetValueAtIndex(_callbackOperationPool, ((indexInPool-1) >=0 ? indexInPool-1 : 0) ); }else{ - NSLog(@" ERROR :: NO pool .... "); +// NSLog(@" ERROR :: NO pool .... "); + [NSException raise:NSInvalidArgumentException format:@" ERROR :: NO pool .... "]; } } @@ -413,78 +415,78 @@ -(id)invalidateOperation:(NSInteger)operationRefIndex return nil; } --(void)_waitingPoolOperationForResult -{ - PGConnectionOperation* prevPoolOpe = [self prevPoolOperation]; - PGConnectionOperation* currentPoolOpe = [self currentPoolOperation]; - - NSLog(@" Waiting for concurrent queries resultset (%lu) (%@) ...... ", [self connectionPoolOperationCount], [self currentPoolOperation]); - NSTimeInterval resolutionTimeOut = 0.5; - bool isRunning = NO; - while (1) { - - - prevPoolOpe = [self prevPoolOperation]; - currentPoolOpe = [self currentPoolOperation]; - - - - - - if( - ([((PGConnectionOperation*)currentPoolOpe) valid] && [((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0 ) - // && [((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0 - || (_stateOperation) - ) - { - NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; - isRunning = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; - isRunning = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; - [NSThread sleepForTimeInterval:0.02]; - // NSLog(@" >>>>> :::: %@ .... %d",NSStringFromSelector(_cmd),isRunning); - - // return; - }else{ - - break; - } - } - NSLog(@" CLEARED Waiting for concurrent queries resultset (%lu) (%@) ...... ", [self connectionPoolOperationCount], [self currentPoolOperation]); -} --(void)_waitingPoolOperationForResultMaster -{ - NSTimeInterval resolutionTimeOut = 0.5; - bool isRunning = NO; - - PGConnectionOperation* prevPoolOpe = [self prevPoolOperation]; - PGConnectionOperation* currentPoolOpe = [self currentPoolOperation]; - - while ([((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0) { - - - prevPoolOpe = [self prevPoolOperation]; - currentPoolOpe = [self currentPoolOperation]; - - - - if([((PGConnectionOperation*)prevPoolOpe) valid] - && [((PGConnectionOperation*)currentPoolOpe) valid] - ) - { - // NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; - // isRunning = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; - [NSThread sleepForTimeInterval:0.02]; - NSLog(@" >>>>> master wait :::: %@ .... %d",NSStringFromSelector(_cmd),isRunning); - - // return; - }else{ - NSLog(@" >>>>> master wait :: done :::: .... %d",isRunning); - break; - } - } - - -} +//-(void)_waitingPoolOperationForResult +//{ +// PGConnectionOperation* prevPoolOpe = [self prevPoolOperation]; +// PGConnectionOperation* currentPoolOpe = [self currentPoolOperation]; +// +// NSLog(@" Waiting for concurrent queries resultset (%lu) (%@) ...... ", [self connectionPoolOperationCount], [self currentPoolOperation]); +// NSTimeInterval resolutionTimeOut = 0.5; +// bool isRunning = NO; +// while (1) { +// +// +// prevPoolOpe = [self prevPoolOperation]; +// currentPoolOpe = [self currentPoolOperation]; +// +// +// +// +// +// if( +// ([((PGConnectionOperation*)currentPoolOpe) valid] && [((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0 ) +// // && [((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0 +// || (_stateOperation) +// ) +// { +// NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; +// isRunning = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; +// isRunning = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; +// [NSThread sleepForTimeInterval:0.02]; +// // NSLog(@" >>>>> :::: %@ .... %d",NSStringFromSelector(_cmd),isRunning); +// +// // return; +// }else{ +// +// break; +// } +// } +// NSLog(@" CLEARED Waiting for concurrent queries resultset (%lu) (%@) ...... ", [self connectionPoolOperationCount], [self currentPoolOperation]); +//} +//-(void)_waitingPoolOperationForResultMaster +//{ +// NSTimeInterval resolutionTimeOut = 0.5; +// bool isRunning = NO; +// +// PGConnectionOperation* prevPoolOpe = [self prevPoolOperation]; +// PGConnectionOperation* currentPoolOpe = [self currentPoolOperation]; +// +// while ([((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0) { +// +// +// prevPoolOpe = [self prevPoolOperation]; +// currentPoolOpe = [self currentPoolOperation]; +// +// +// +// if([((PGConnectionOperation*)prevPoolOpe) valid] +// && [((PGConnectionOperation*)currentPoolOpe) valid] +// ) +// { +// // NSDate* theNextDate = [NSDate dateWithTimeIntervalSinceNow:resolutionTimeOut]; +// // isRunning = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; +// [NSThread sleepForTimeInterval:0.02]; +// NSLog(@" >>>>> master wait :::: %@ .... %d",NSStringFromSelector(_cmd),isRunning); +// +// // return; +// }else{ +// NSLog(@" >>>>> master wait :: done :::: .... %d",isRunning); +// break; +// } +// } +// +// +//} //////////////////////////////////////////////////////////////////////////////// diff --git a/src/Frameworks/PGClientKit/PGResult.m b/src/Frameworks/PGClientKit/PGResult.m index 5708185..d8705bf 100644 --- a/src/Frameworks/PGClientKit/PGResult.m +++ b/src/Frameworks/PGClientKit/PGResult.m @@ -46,14 +46,14 @@ -(void)dealloc { @synchronized(self) { - [NSThread sleepForTimeInterval:0.01]; + [NSThread sleepForTimeInterval:0.1]; [_cachedData removeAllObjects]; // _result = ((PGresult* )_result); if( _result != NULL ){ PQclear((PGresult* )_result); } _result = NULL; - [NSThread sleepForTimeInterval:0.01]; + [NSThread sleepForTimeInterval:0.1]; } } From a5cdca2a295722e0a23a52c707859bbaafc4ee08 Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Wed, 23 Aug 2017 18:52:57 +0200 Subject: [PATCH 18/21] some socket wowrkaround --- .../PGClientKit/PGConnection+Callbacks.m | 10 +- .../PGClientKit/PGConnection+Connect.m | 128 ++++++++++++------ .../PGClientKit/PGConnection+Execute.m | 34 ++++- .../PGConnection+PGConnectionSocket.m | 45 +++++- src/Frameworks/PGClientKit/PGConnection.h | 6 + src/Frameworks/PGClientKit/PGConnection.m | 4 +- 6 files changed, 172 insertions(+), 55 deletions(-) diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index 0592ba9..3c41560 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -45,6 +45,8 @@ void _socketCallback(CFSocketRef s, CFSocketCallBackType callBackType,CFDataRef PGConnection* connection = (PGConnection* ) ((__bridge PGConnection* )__self); if(! connection + + || ! [ (PGConnection*)connection masterPoolOperation] // || socketUsed_in > 20 ) return ; @@ -192,7 +194,7 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); _callbackOperation = [((PGConnectionOperation*)[self masterPoolOperation]) getCallback]; - if(_callbackOperation != nil) + if(_callbackOperation != nil && _connection ) { void (^callback_master)(BOOL usedPassword,NSError* error ) = (__bridge void (^)( BOOL,NSError* ))( _callbackOperation ); @@ -202,7 +204,7 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus [NSException raise:NSInvalidArgumentException format:@" Warning :: Master Pool callback (async) was sudently cleaned .... "]; } dispatch_semaphore_signal(ss); - [((PGConnectionOperation*)[self masterPoolOperation]) finish]; +// [((PGConnectionOperation*)[self masterPoolOperation]) finish]; } @catch (NSException *exception) { NSLog(@"**************************** \n ERROR :: %@ :: \n **************************** \n [ %@ ] \n **************************** \n ", NSStringFromSelector(_cmd), exception); dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); @@ -427,10 +429,12 @@ -(void)_socketCallbackQueryRead { #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - callback %p ",callback); #endif + id curope = [self currentPoolOperation]; + id queryResults = [ curope setResults: r ]; callback(r,error); [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; - [((PGConnectionOperation*)[self currentPoolOperation]) finish]; +// [((PGConnectionOperation*)[self currentPoolOperation]) finish]; [((PGConnectionOperation*)[self masterPoolOperation]) validate]; }); diff --git a/src/Frameworks/PGClientKit/PGConnection+Connect.m b/src/Frameworks/PGClientKit/PGConnection+Connect.m index 2d8ef11..8779118 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Connect.m +++ b/src/Frameworks/PGClientKit/PGConnection+Connect.m @@ -90,21 +90,74 @@ -(NSDictionary* )_connectionParametersForURL:(NSURL* )theURL { //////////////////////////////////////////////////////////////////////////////// #pragma mark public methods - connections //////////////////////////////////////////////////////////////////////////////// +-(void) _reconnectWithHandler: ( void(^ _Nullable )(void * pm,NSError* error)) callback +{ + if(!_connection && !_socket) + { + + // extract connection parameters + NSDictionary* parameters = [self _connectionParametersForURL: _connectedUrl]; + if(parameters==nil) { + callback(NO,[self raiseError:nil code:PGClientErrorParameters]); + return; + } + + // update the status as necessary + [self _updateStatus]; + + // create parameter pairs + PGKVPairs* pairs = makeKVPairs(parameters); + if(pairs==nil) { + callback(NO,[self raiseError:nil code:PGClientErrorParameters]); + return; + } + + // create connection + _connection = PQconnectStartParams(pairs->keywords,pairs->values,0); + freeKVPairs(pairs); + if(_connection==nil) { + callback(NO,[self raiseError:nil code:PGClientErrorParameters]); + return; + } + + // check for initial bad connection status + if(PQstatus(_connection)==CONNECTION_BAD) { + PQfinish(_connection); + _connection = nil; + [self _updateStatus]; + callback(NO,[self raiseError:nil code:PGClientErrorParameters]); + return; + } + + }else{ + NSLog(@" %@ :: connection seems good ... ",NSStringFromSelector(_cmd)); + } +} -(void)connectWithURL:(NSURL* )url whenDone:(void(^)(BOOL usedPassword,NSError* error)) callback { NSParameterAssert(url); NSParameterAssert(callback); - + @try { + // check for bad initial state - if(_connection != nil || [self state] != PGConnectionStateNone) { + if(_connection != nil ) { callback(NO,[self raiseError:nil code:PGClientErrorState]); return; } - + PGConnectionState curstate = [self state]; + if( curstate != PGConnectionStateNone) + { + NSLog(@" :: Warning :: %@ :: %@ :: \n :: Connection previously initialized ::", NSStringFromSelector(_cmd), self); + ;; + } + // check other internal variable consistency NSParameterAssert(_connection==nil); NSParameterAssert(_socket==nil); NSParameterAssert(_runloopsource==nil); + + _connectedUrl = url; + #if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) [NSThread detachNewThreadWithBlock:^{ #else @@ -112,43 +165,16 @@ -(void)connectWithURL:(NSURL* )url whenDone:(void(^)(BOOL usedPassword,NSError* // dispatch_async(dispatch_get_main_queue(),^{ #endif - - // extract connection parameters - NSDictionary* parameters = [self _connectionParametersForURL:url]; - if(parameters==nil) { - callback(NO,[self raiseError:nil code:PGClientErrorParameters]); - return; - } - - // update the status as necessary - [self _updateStatus]; - - // create parameter pairs - PGKVPairs* pairs = makeKVPairs(parameters); - if(pairs==nil) { - callback(NO,[self raiseError:nil code:PGClientErrorParameters]); - return; - } - - // create connection - _connection = PQconnectStartParams(pairs->keywords,pairs->values,0); - freeKVPairs(pairs); - if(_connection==nil) { - callback(NO,[self raiseError:nil code:PGClientErrorParameters]); - return; - } - - // check for initial bad connection status - if(PQstatus(_connection)==CONNECTION_BAD) { - PQfinish(_connection); - _connection = nil; - [self _updateStatus]; - callback(NO,[self raiseError:nil code:PGClientErrorParameters]); - return; - } - - // set callback - NSParameterAssert(callback!=nil); + // set callback + NSParameterAssert(callback!=nil); + +// void (^callbackRecall)(bool result,NSError* error) = (__bridge void (^)(bool ,NSError* ))( callback); + void (^ _Nullable callbackRecall)(void * pm,NSError* error) = ( void (^ _Nullable )(void* ,NSError* ))( callback ); + + [self _reconnectWithHandler: callbackRecall]; + + + // not quite good for cascaded Operation //:: _callback = (__bridge_retained void* )[callback copy]; // So we do good things to deal with cascaded Operation @@ -171,7 +197,22 @@ -(void)connectWithURL:(NSURL* )url whenDone:(void(^)(BOOL usedPassword,NSError* #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" ------- %@ :: %@ :::: Connection Started ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); #endif + + // start queued request [self _socketConnect:PGConnectionStateConnect]; + +// if( _socket == nil) +// { +// NSLog(@" ERROR :: Premature Closing of socket .... (%@) ", self); +// +// if(_connection) +// PQfinish(_connection); +// +// _connection = nil; +// +// callback(NO,[self raiseError:nil code:PGClientErrorUnknown]); +// +// } // CFRunLoopRun(); // [self performSelector:@selector(_waitingPoolOperationForResult) withObject:self ]; // [self performSelector:@selector(_waitingPoolOperationForResultMaster) withObject:self ]; @@ -189,6 +230,13 @@ -(void)connectWithURL:(NSURL* )url whenDone:(void(^)(BOOL usedPassword,NSError* #endif ; + } @catch (NSException *exception) { + NSLog(@"**************************** \n ERROR :: %@ :: \n **************************** \n [ %@ ] \n **************************** \n ", NSStringFromSelector(_cmd), exception); + + } @finally { + + } + } -(BOOL)connectWithURL:(NSURL* )url usedPassword:(BOOL* )usedPassword error:(NSError** )error { diff --git a/src/Frameworks/PGClientKit/PGConnection+Execute.m b/src/Frameworks/PGClientKit/PGConnection+Execute.m index 4900e38..568ef16 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Execute.m +++ b/src/Frameworks/PGClientKit/PGConnection+Execute.m @@ -37,11 +37,20 @@ -(void)_execute:(NSString* )query values:(NSArray* )values whenDone:(void(^)(PGR NSParameterAssert(query && [query isKindOfClass:[NSString class]]); - if(_connection==nil || [self state] != PGConnectionStateNone) { + + if(_connection==nil ) { callback(nil,[self raiseError:nil code:PGClientErrorState]); return; } + PGConnectionState curstate = [self state]; + if( curstate != PGConnectionStateNone) + { + NSLog(@" :: Warning :: %@ :: %@ :: \n :: Wrong State :: %u ", NSStringFromSelector(_cmd), self, curstate); + ;; + } + + // create parameters object PGClientParams* params = _paramAllocForValues(values); if(params==nil) { @@ -137,6 +146,20 @@ -(id)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) callb NSParameterAssert([query isKindOfClass:[NSString class]] || [query isKindOfClass:[PGQuery class]]); NSParameterAssert(callback); + if( ! _connection ) + { + void (^ _Nullable callbackRecall)(void * pm,NSError* error) = ( void (^ _Nullable )(void* ,NSError* ))( callback ); + + [self _reconnectWithHandler: callbackRecall]; + if( ! _connection || !_socket) + callback(NO,[self raiseError:nil code:PGClientErrorState]); + +// [[self masterPoolOperation] invalidate]; +// [[self masterPoolOperation] finish]; + +// return; + } + _stateOperation = PGOperationStatePrepare; // mach_port_t machTID = pthread_mach_thread_np(pthread_self()); @@ -172,7 +195,8 @@ -(id)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) callb #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" .... semaphore callback..... %@", [[self currentPoolOperation] semaphore]); #endif - queryResults = [[self currentPoolOperation] setResults: result_recall ]; +// id curope = [self currentPoolOperation]; +// queryResults = [ curope setResults: result_recall ]; // [result_recall fetchRowAsDictionary] callback(result_recall , error_recall); @@ -194,7 +218,9 @@ -(id)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) callb dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); // NSLog(@"+++ Is main queue? : %d", qu_inRun == dispatch_get_main_queue()); - dispatch_semaphore_t semaphore_query_send = [[self currentPoolOperation] semaphore]; + id curope = [self currentPoolOperation]; + + dispatch_semaphore_t semaphore_query_send = [curope semaphore]; [self wait_semaphore_read: semaphore_query_send withQueue:queue_inRun]; // NSLog(@" RESULTS ::\n Query : %@ \n:: Result : %@ ", query2, queryResults); @@ -339,7 +365,7 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ bool PG_busy = YES; - long timeoutThread = 600; // .05 * 600 = 30s + long timeoutThread = 1200; // .05 * 600 = 60s @try { diff --git a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m index f1a56ff..ed90122 100644 --- a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m +++ b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m @@ -273,8 +273,30 @@ -(CFSocketRef)__CFSocket_instanciate // _socket = CFSocketCreate(kCFAllocatorDefault, 0, 0, 0, kCFSocketReadCallBack | kCFSocketWriteCallBack, &_socketCallback,&context); // PQsocket(_connection); + if( _connection == nil ) + { + [NSException raise:NSInvalidArgumentException format:@" Error :: Can't create _connection : %@ ", self]; + return; + } - _socket = CFSocketCreateWithNative(kCFAllocatorDefault,PQsocket(_connection),kCFSocketReadCallBack | kCFSocketWriteCallBack,&_socketCallback,&context); + if( !PQsocket(_connection) ) + { + [NSException raise:NSInvalidArgumentException format:@" Error :: Can't create _connection : %@ ", self]; + return; + } + + int timeout = 60; + + while (! _socket && timeout > 0 ) + { + + _socket = CFSocketCreateWithNative(kCFAllocatorDefault,PQsocket(_connection),kCFSocketReadCallBack | kCFSocketWriteCallBack,&_socketCallback,&context); + [NSThread sleepForTimeInterval:1.0]; + timeout --; + if(!timeout) + [NSException raise:NSInvalidArgumentException format:@" Error :: Can't create _connection :: TIMEOUT : %@ ", self]; + + } } @@ -293,6 +315,13 @@ -(void)_socketConnect:(PGConnectionState)state { [self __CFSocket_instanciate]; + if(_socket == nil) + { + [NSException raise:NSInvalidArgumentException format:@" Error :: Can't create socket : %@ ", self]; + return; + } + + // _socket = CFSocketCreate(kCFAllocatorDefault, 0, 0, 0, kCFSocketReadCallBack | kCFSocketWriteCallBack,&_socketCallback,&context); // NSParameterAssert(_socket && CFSocketIsValid(_socket)); @@ -300,13 +329,14 @@ -(void)_socketConnect:(PGConnectionState)state { CFSocketSetSocketFlags(_socket,~kCFSocketCloseOnInvalidate & CFSocketGetSocketFlags(_socket)); // CFSocketEnableCallBacks(_socket, kCFSocketDataCallBack | kCFSocketReadCallBack | kCFSocketWriteCallBack); - dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); - - dispatch_source_t dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, qu_inRun ); - - dispatch_source_set_timer(dsrc, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC / 2, NSEC_PER_SEC); +// dispatch_queue_t qu_inRun = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0); +// +// dispatch_source_t dsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, qu_inRun ); +// +// dispatch_source_set_timer(dsrc, dispatch_time(DISPATCH_TIME_NOW, 0), NSEC_PER_SEC / 2, NSEC_PER_SEC); // cf(_socket, F_SETFL, O_NONBLOCK); + // set state [self setState:state]; [self _updateStatus]; @@ -328,7 +358,10 @@ -(void)_socketConnect:(PGConnectionState)state { [self wait_semaphore_read: semaphore_query_send ]; + [NSThread sleepForTimeInterval:0.1]; + [[NSThread currentThread] cancel]; + // CFRunLoopRun();//(kCFRunLoopDefaultMode, 0.2 , NO); #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" ------- %@ :: %@ :::: Socket Runloop ENDED CLEAR ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); diff --git a/src/Frameworks/PGClientKit/PGConnection.h b/src/Frameworks/PGClientKit/PGConnection.h index 4c3bc8e..53b5baf 100644 --- a/src/Frameworks/PGClientKit/PGConnection.h +++ b/src/Frameworks/PGClientKit/PGConnection.h @@ -101,6 +101,7 @@ typedef enum { PGOperationState _stateOperation; NSDictionary* _parameters; PGClientTupleFormat _tupleFormat; + id _connectedUrl; } //////////////////////////////////////////////////////////////////////////////// @@ -213,6 +214,11 @@ typedef enum { @interface PGConnection (Connect) + + +-(void) _reconnectWithHandler: ( void(^ _Nullable )(void * pm,NSError* error)) callback; + + /** * Connect to a database (as specififed by the URL) without blocking. The method * returns immediately, on initiation of the connection. Once the connection diff --git a/src/Frameworks/PGClientKit/PGConnection.m b/src/Frameworks/PGClientKit/PGConnection.m index 74bb5f1..0a31c66 100644 --- a/src/Frameworks/PGClientKit/PGConnection.m +++ b/src/Frameworks/PGClientKit/PGConnection.m @@ -406,9 +406,9 @@ -(id)invalidateOperation:(NSInteger)operationRefIndex dispatch_semaphore_signal( [obj semaphore] ); [obj finish]; -#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 +//#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" %@::%@ :: REMOVED pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, [obj description]); -#endif +//#endif CFArrayRemoveValueAtIndex(_callbackOperationPool, operationRefIndex); } From 797f10bf69bf2ee481ca1f36169ad4aa028eea4b Mon Sep 17 00:00:00 2001 From: "genose.org" Date: Thu, 24 Aug 2017 08:48:51 +0200 Subject: [PATCH 19/21] finding _connection lost --- src/Frameworks/PGClientKit/PGConnection+Callbacks.m | 11 +++++++++-- src/Frameworks/PGClientKit/PGConnection+Execute.m | 2 +- .../PGClientKit/PGConnection+PGConnectionSocket.m | 7 ++++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index 3c41560..c3ca743 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -89,7 +89,11 @@ @implementation PGConnection (Callbacks) -(void)_socketCallbackNotification { @try { - NSParameterAssert(_connection); +// NSParameterAssert(_connection); + if(!_connection){ + + return; + } // consume input PQconsumeInput(_connection); @@ -200,9 +204,12 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus callback_master(usedPassword ? YES : NO,nil); - }else{ + }else if(!_connection){ [NSException raise:NSInvalidArgumentException format:@" Warning :: Master Pool callback (async) was sudently cleaned .... "]; } + else{ + [NSException raise:NSInvalidArgumentException format:@" Warning :: Master Pool Warning (async) :: NO OPERATION :: was sudently cleaned .... "]; + } dispatch_semaphore_signal(ss); // [((PGConnectionOperation*)[self masterPoolOperation]) finish]; } @catch (NSException *exception) { diff --git a/src/Frameworks/PGClientKit/PGConnection+Execute.m b/src/Frameworks/PGClientKit/PGConnection+Execute.m index 568ef16..d5b7c1b 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Execute.m +++ b/src/Frameworks/PGClientKit/PGConnection+Execute.m @@ -365,7 +365,7 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ bool PG_busy = YES; - long timeoutThread = 1200; // .05 * 600 = 60s + long timeoutThread = 2400; // .05 * 2400 = 120s @try { diff --git a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m index ed90122..022b9ef 100644 --- a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m +++ b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m @@ -307,12 +307,13 @@ -(CFSocketRef)__CFSocket_instanciate //////////////////////////////////////////////////////////////////////////////// -(void)_socketConnect:(PGConnectionState)state { - NSParameterAssert(_state==PGConnectionStateNone); + NSParameterAssert(state==PGConnectionStateConnect || state==PGConnectionStateReset || state==PGConnectionStateNone); NSParameterAssert(_connection); - NSParameterAssert(_socket==nil && _runloopsource==nil); - + +// NSParameterAssert(_state==PGConnectionStateNone); +// NSParameterAssert(_socket==nil && _runloopsource==nil); [self __CFSocket_instanciate]; if(_socket == nil) From c5ab52b06b57833a78a7978d6b7be8b589b37e86 Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Thu, 24 Aug 2017 18:34:48 +0200 Subject: [PATCH 20/21] more socket workaround --- .../PGClientKit/PGConnection+Callbacks.m | 80 +++++++++++----- .../PGClientKit/PGConnection+Connect.m | 55 ++++++++--- .../PGClientKit/PGConnection+Disconnect.m | 4 +- .../PGClientKit/PGConnection+Execute.m | 34 ++++--- .../PGConnection+PGConnectionSocket.m | 44 +++++++-- src/Frameworks/PGClientKit/PGConnection.h | 1 + src/Frameworks/PGClientKit/PGConnection.m | 92 +++++++++++-------- .../PGClientKit/PGConnectionOperation.m | 17 +++- 8 files changed, 233 insertions(+), 94 deletions(-) diff --git a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m index c3ca743..c2ac6d1 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Callbacks.m +++ b/src/Frameworks/PGClientKit/PGConnection+Callbacks.m @@ -41,8 +41,8 @@ void _socketCallback(CFSocketRef s, CFSocketCallBackType callBackType,CFDataRef -// [NSThread sleepForTimeInterval:0.01]; - + // [NSThread sleepForTimeInterval:0.01]; + PGConnection* connection = (PGConnection* ) ((__bridge PGConnection* )__self); if(! connection @@ -89,11 +89,11 @@ @implementation PGConnection (Callbacks) -(void)_socketCallbackNotification { @try { -// NSParameterAssert(_connection); - if(!_connection){ - - return; - } + // NSParameterAssert(_connection); + if(!_connection){ + + return; + } // consume input PQconsumeInput(_connection); @@ -172,10 +172,10 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus PQsetNoticeProcessor(_connection,_noticeProcessor,(__bridge void *)(self)); currentPool = [self currentPoolOperation]; if(!currentPool) { - + return; } - + if([currentPool poolIdentifier] == 0){ @@ -193,10 +193,18 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus [((PGConnectionOperation*)[self masterPoolOperation]) invalidate]; + + if(!_connection) + { + return; + } + + __block dispatch_semaphore_t master_semaphore_lock = nil; + dispatch_async(queue_inRun,^{ @try{ - dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); + master_semaphore_lock = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); _callbackOperation = [((PGConnectionOperation*)[self masterPoolOperation]) getCallback]; if(_callbackOperation != nil && _connection ) { @@ -204,18 +212,36 @@ -(void)_socketCallbackConnectEndedWithStatus:(PostgresPollingStatusType)pqstatus callback_master(usedPassword ? YES : NO,nil); - }else if(!_connection){ - [NSException raise:NSInvalidArgumentException format:@" Warning :: Master Pool callback (async) was sudently cleaned .... "]; + }else if(!_connection && !_connectionClosed){ + [NSException raise:NSInvalidArgumentException format:@" Warning :: Master Pool (%p) callback (async) was sudently cleaned .... ", self]; + } + else if( ! _connectionClosed ){ + [NSException raise:NSInvalidArgumentException format:@" Warning :: Master Pool (%p) Warning (async) :: NO CONNECTION :: was sudently cleaned .... ", self]; + } + else if( ! _callbackOperation ){ + [NSException raise:NSInvalidArgumentException format:@" Warning :: Master Pool (%p) Warning (async) :: NO OPERATION :: was sudently cleaned .... ", self]; } - else{ - [NSException raise:NSInvalidArgumentException format:@" Warning :: Master Pool Warning (async) :: NO OPERATION :: was sudently cleaned .... "]; + else { + + void (^callback_master_failed)(void *,NSError* error ) = (__bridge void (^ _Nullable)( void *,NSError* ))( _callbackOperation ); + + // callback_master_failed(usedPassword ? YES : NO,nil); + [self _reconnectWithHandler:callback_master_failed]; + + if(!_connection ) + { + [NSException raise:NSInvalidArgumentException format:@" Warning :: Master Pool (%p) Warning (async) :: UNKNOW ERROR :: was sudently cleaned .... ", self]; + }else{ + NSLog(@" Warning :: Master Pool (%p) Warning (async) :: UNKNOW ERROR :: But Reconnected :: was sudently cleaned .... ", self); + } } - dispatch_semaphore_signal(ss); -// [((PGConnectionOperation*)[self masterPoolOperation]) finish]; + + dispatch_semaphore_signal(master_semaphore_lock); + // [((PGConnectionOperation*)[self masterPoolOperation]) finish]; } @catch (NSException *exception) { NSLog(@"**************************** \n ERROR :: %@ :: \n **************************** \n [ %@ ] \n **************************** \n ", NSStringFromSelector(_cmd), exception); - dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); - dispatch_semaphore_signal(ss); + // dispatch_semaphore_t ss = [((PGConnectionOperation*)[self masterPoolOperation]) semaphore]; // dispatch_semaphore_create(0); + dispatch_semaphore_signal(master_semaphore_lock); } @finally { } @@ -436,12 +462,20 @@ -(void)_socketCallbackQueryRead { #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@"PGConnectionStateQuery - Read - callback %p ",callback); #endif - id curope = [self currentPoolOperation]; - id queryResults = [ curope setResults: r ]; - - callback(r,error); + @try + { + id curope = [self currentPoolOperation]; + id queryResults = [ curope setResults: r ]; + + callback(r,error); + }@catch (NSException *exception) { + NSLog(@" %@ :: read callback (async) :: exeception .... %@",NSStringFromSelector(_cmd),exception); + } + @finally { + + } [((PGConnectionOperation*)[self currentPoolOperation]) invalidate]; -// [((PGConnectionOperation*)[self currentPoolOperation]) finish]; + // [((PGConnectionOperation*)[self currentPoolOperation]) finish]; [((PGConnectionOperation*)[self masterPoolOperation]) validate]; }); diff --git a/src/Frameworks/PGClientKit/PGConnection+Connect.m b/src/Frameworks/PGClientKit/PGConnection+Connect.m index 8779118..625b44b 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Connect.m +++ b/src/Frameworks/PGClientKit/PGConnection+Connect.m @@ -92,13 +92,27 @@ -(NSDictionary* )_connectionParametersForURL:(NSURL* )theURL { //////////////////////////////////////////////////////////////////////////////// -(void) _reconnectWithHandler: ( void(^ _Nullable )(void * pm,NSError* error)) callback { +// if(_connection && _socket) +// { +// [self disconnect]; +// } + + if(_connection && callback == nil){ + PQfinish(_connection); + _connection = nil; + } + if(_socket && callback == nil){ + [self _socketDisconnect]; + _socket = nil; + } + if(!_connection && !_socket) { - + NSLog(@" %@ :: %@",NSStringFromSelector(_cmd), callback); // extract connection parameters NSDictionary* parameters = [self _connectionParametersForURL: _connectedUrl]; if(parameters==nil) { - callback(NO,[self raiseError:nil code:PGClientErrorParameters]); + if(callback != nil) callback(NO,[self raiseError:nil code:PGClientErrorParameters]); return; } @@ -108,7 +122,7 @@ -(void) _reconnectWithHandler: ( void(^ _Nullable )(void * pm,NSError* error)) c // create parameter pairs PGKVPairs* pairs = makeKVPairs(parameters); if(pairs==nil) { - callback(NO,[self raiseError:nil code:PGClientErrorParameters]); + if(callback != nil) callback(NO,[self raiseError:nil code:PGClientErrorParameters]); return; } @@ -116,18 +130,34 @@ -(void) _reconnectWithHandler: ( void(^ _Nullable )(void * pm,NSError* error)) c _connection = PQconnectStartParams(pairs->keywords,pairs->values,0); freeKVPairs(pairs); if(_connection==nil) { - callback(NO,[self raiseError:nil code:PGClientErrorParameters]); + if(callback != nil) callback(NO,[self raiseError:nil code:PGClientErrorParameters]); return; } + _connectionClosed = NO; + // check for initial bad connection status if(PQstatus(_connection)==CONNECTION_BAD) { PQfinish(_connection); _connection = nil; [self _updateStatus]; - callback(NO,[self raiseError:nil code:PGClientErrorParameters]); + if(callback != nil) callback(NO,[self raiseError:nil code:PGClientErrorParameters]); return; } + // not quite good for cascaded Operation + //:: _callback = (__bridge_retained void* )[callback copy]; + // So we do good things to deal with cascaded Operation + if(callback != nil){ +// if(CFArrayGetCount(_callbackOperationPool)) [[self masterPoolOperation] finish]; + + [self addOperation:self withCallBackWhenDone: (__bridge_retained void* )callback withCallBackWhenError: (__bridge_retained void* )callback ]; + }else{ + if( ! CFArrayGetCount(_callbackOperationPool)) + [self addOperation:self withCallBackWhenDone: (__bridge_retained void* )callback withCallBackWhenError: (__bridge_retained void* )callback ]; + [self _socketConnect:PGConnectionStateConnect]; + } + + NSLog(@" %@ :: connection Initilized ... ",NSStringFromSelector(_cmd)); }else{ NSLog(@" %@ :: connection seems good ... ",NSStringFromSelector(_cmd)); @@ -135,8 +165,8 @@ -(void) _reconnectWithHandler: ( void(^ _Nullable )(void * pm,NSError* error)) c } -(void)connectWithURL:(NSURL* )url whenDone:(void(^)(BOOL usedPassword,NSError* error)) callback { - NSParameterAssert(url); - NSParameterAssert(callback); + NSParameterAssert(url!=nil); + NSParameterAssert(callback!=nil); @try { // check for bad initial state @@ -175,12 +205,7 @@ -(void)connectWithURL:(NSURL* )url whenDone:(void(^)(BOOL usedPassword,NSError* - // not quite good for cascaded Operation -//:: _callback = (__bridge_retained void* )[callback copy]; - // So we do good things to deal with cascaded Operation - - [self addOperation:self withCallBackWhenDone: (__bridge_retained void* )callback withCallBackWhenError: (__bridge_retained void* )callback ]; -#if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) + #if ( defined(__IPHONE_10_3) && __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_10_3 ) || ( defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_12 ) } ]; #else @@ -231,8 +256,8 @@ -(void)connectWithURL:(NSURL* )url whenDone:(void(^)(BOOL usedPassword,NSError* ; } @catch (NSException *exception) { - NSLog(@"**************************** \n ERROR :: %@ :: \n **************************** \n [ %@ ] \n **************************** \n ", NSStringFromSelector(_cmd), exception); - + NSLog(@"**************************** \n ERROR connection init :: %@ :: \n **************************** \n [ %@ ] \n **************************** \n ", NSStringFromSelector(_cmd), exception); + return; } @finally { } diff --git a/src/Frameworks/PGClientKit/PGConnection+Disconnect.m b/src/Frameworks/PGClientKit/PGConnection+Disconnect.m index b1809ed..091d484 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Disconnect.m +++ b/src/Frameworks/PGClientKit/PGConnection+Disconnect.m @@ -23,12 +23,14 @@ -(void)disconnect { [self _socketDisconnect]; if(_connection != NULL) { - + PQfinish(_connection); _connection = nil; _parameters = nil; + _connectionClosed = YES; } + NSLog(@" %@ (%p) :: %@ :: Close connection pool (%ld) :: (%@) .... ", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), CFArrayGetCount(_callbackOperationPool), _connectedUrl); } [self _updateStatus]; } diff --git a/src/Frameworks/PGClientKit/PGConnection+Execute.m b/src/Frameworks/PGClientKit/PGConnection+Execute.m index d5b7c1b..9bf92fc 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Execute.m +++ b/src/Frameworks/PGClientKit/PGConnection+Execute.m @@ -148,16 +148,26 @@ -(id)execute:(id)query whenDone:(void(^)(PGResult* result,NSError* error)) callb if( ! _connection ) { + + +// [self disconnect]; + void (^ _Nullable callbackRecall)(void * pm,NSError* error) = ( void (^ _Nullable )(void* ,NSError* ))( callback ); - [self _reconnectWithHandler: callbackRecall]; +// [self setState:PGConnectionStateNone]; + +// [self _reconnectWithHandler: nil]; if( ! _connection || !_socket) - callback(NO,[self raiseError:nil code:PGClientErrorState]); + { + callback(nil,[self raiseError:nil code:PGClientErrorUnknown]); +// [[self masterPoolOperation] invalidate]; +// [[self masterPoolOperation] finish]; + } + -// [[self masterPoolOperation] invalidate]; -// [[self masterPoolOperation] finish]; + -// return; + return nil; } _stateOperation = PGOperationStatePrepare; @@ -365,7 +375,7 @@ -(void)wait_semaphore_read:(dispatch_semaphore_t) sem withQueue:(dispatch_queue_ bool PG_busy = YES; - long timeoutThread = 2400; // .05 * 2400 = 120s + long timeoutThread = 120; // .05 * 2400 = 60s @try { @@ -505,10 +515,10 @@ -(void)dispathCall if( qq_loop != [NSRunLoop mainRunLoop]){ if([[self currentPoolOperation] poolIdentifier] == 0 ){ [qq_loop runUntilDate:theNextDate]; - if(!isRunningThread){ - [qq_loop_main runUntilDate:theNextDate]; - [NSThread sleepForTimeInterval:0.1];; - } +// if(!isRunningThread){ +// [qq_loop_main runUntilDate:theNextDate]; +// [NSThread sleepForTimeInterval:0.1];; +// } // [qq_loop_main runUntilDate:theNextDate]; // @@ -522,7 +532,7 @@ -(void)dispathCall }else{ { - [qq_loop_main runUntilDate:theNextDate]; +// [qq_loop_main runUntilDate:theNextDate]; [qq_loop runUntilDate:theNextDate]; } @@ -537,7 +547,7 @@ -(void)dispathCall if(!isRunningThread){ [qq_loop runUntilDate:theNextDate]; }else{ - [qq_loop_main runUntilDate:theNextDate]; +// [qq_loop_main runUntilDate:theNextDate]; } } diff --git a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m index 022b9ef..f18c9ac 100644 --- a/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m +++ b/src/Frameworks/PGClientKit/PGConnection+PGConnectionSocket.m @@ -33,12 +33,16 @@ extern void __CFRunLoopSourceWakeUpLoop(const void*,void*); extern void _socketCallback; + static CFMutableArrayRef __CFCF_CFAllSockets = NULL; #define INVALID_SOCKET (CFSocketNativeHandle)(-1) #define MAX_SOCKADDR_LEN 256 #define __CFCF_CFSockQueue() dispatch_get_current_queue() +static int MAX_SOCKET = 100; +static int USED_SOCKET = 0; + @implementation PGConnection (PGConnectionSocket) void _CFRunLoopSourceWakeUpRunLoops(CFRunLoopSourceRef rls) { return; @@ -279,22 +283,37 @@ -(CFSocketRef)__CFSocket_instanciate return; } + if( !PQsocket(_connection) ) { [NSException raise:NSInvalidArgumentException format:@" Error :: Can't create _connection : %@ ", self]; return; } - + + if(_socket) + { + [self _socketDisconnect]; + } + + int timeout = 60; while (! _socket && timeout > 0 ) { _socket = CFSocketCreateWithNative(kCFAllocatorDefault,PQsocket(_connection),kCFSocketReadCallBack | kCFSocketWriteCallBack,&_socketCallback,&context); - [NSThread sleepForTimeInterval:1.0]; + [NSThread sleepForTimeInterval:0.25]; + timeout --; if(!timeout) [NSException raise:NSInvalidArgumentException format:@" Error :: Can't create _connection :: TIMEOUT : %@ ", self]; + + if(!_socket) + { + NSLog(@" %@ :: %p :: Connecting ... ", NSStringFromClass([self class]), self); + }else{ + NSLog(@" %@ :: %p :: Socket aquired (%p) ... ", NSStringFromClass([self class]), self, _socket); + } } @@ -309,9 +328,12 @@ -(CFSocketRef)__CFSocket_instanciate -(void)_socketConnect:(PGConnectionState)state { NSParameterAssert(state==PGConnectionStateConnect || state==PGConnectionStateReset || state==PGConnectionStateNone); - NSParameterAssert(_connection); + NSParameterAssert(_connection != nil); - + if(USED_SOCKET > MAX_SOCKET) + { + return; + } // NSParameterAssert(_state==PGConnectionStateNone); // NSParameterAssert(_socket==nil && _runloopsource==nil); [self __CFSocket_instanciate]; @@ -342,6 +364,8 @@ -(void)_socketConnect:(PGConnectionState)state { [self setState:state]; [self _updateStatus]; + if(!_socket) + return ; // add to run loop to begin polling _runloopsource = CFSocketCreateRunLoopSource(NULL,_socket,1); NSParameterAssert(_runloopsource && CFRunLoopSourceIsValid(_runloopsource)); @@ -356,13 +380,15 @@ -(void)_socketConnect:(PGConnectionState)state { NSLog(@"%@ :: %@ :::: Socket created ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); #endif - + USED_SOCKET ++; [self wait_semaphore_read: semaphore_query_send ]; - [NSThread sleepForTimeInterval:0.1]; + [NSThread sleepForTimeInterval:0.05]; [[NSThread currentThread] cancel]; + [NSThread sleepForTimeInterval:0.05]; + // CFRunLoopRun();//(kCFRunLoopDefaultMode, 0.2 , NO); #if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 NSLog(@" ------- %@ :: %@ :::: Socket Runloop ENDED CLEAR ....", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); @@ -370,16 +396,22 @@ -(void)_socketConnect:(PGConnectionState)state { } -(void)_socketDisconnect { + [NSThread sleepForTimeInterval:0.05]; if(_runloopsource) { CFRunLoopSourceInvalidate(_runloopsource); CFRelease(_runloopsource); _runloopsource = nil; } + [NSThread sleepForTimeInterval:0.1]; if(_socket) { CFSocketInvalidate(_socket); + [NSThread sleepForTimeInterval:0.05]; CFRelease(_socket); + [NSThread sleepForTimeInterval:0.05]; _socket = nil; + USED_SOCKET --; } + [NSThread sleepForTimeInterval:0.05]; } @end diff --git a/src/Frameworks/PGClientKit/PGConnection.h b/src/Frameworks/PGClientKit/PGConnection.h index 53b5baf..6c2f638 100644 --- a/src/Frameworks/PGClientKit/PGConnection.h +++ b/src/Frameworks/PGClientKit/PGConnection.h @@ -90,6 +90,7 @@ typedef enum { @interface PGConnection : NSObject { void* _connection; + bool _connectionClosed; void* _cancel; // replaced by a pool Mechanism :: void* _callback; void* _callbackOperation; diff --git a/src/Frameworks/PGClientKit/PGConnection.m b/src/Frameworks/PGClientKit/PGConnection.m index 0a31c66..2dbd983 100644 --- a/src/Frameworks/PGClientKit/PGConnection.m +++ b/src/Frameworks/PGClientKit/PGConnection.m @@ -248,7 +248,7 @@ -(void)_updateStatusDelayed:(NSArray* )arguments { if([[self delegate] respondsToSelector:@selector(connection:statusChange:description:)]) { [[self delegate] connection:self statusChange:status description:description]; } - // [[NSThread currentThread] cancel]; + [[NSThread currentThread] cancel]; // [NSThread cancelPreviousPerformRequestsWithTarget:self]; } @@ -317,8 +317,9 @@ -(PGConnectionOperation*)masterPoolOperation { masterPoolOperation = (__bridge PGConnectionOperation*) CFArrayGetValueAtIndex(_callbackOperationPool, 0); }else{ -// NSLog(@" ERROR :: NO master pool .... "); - [NSException raise:NSInvalidArgumentException format:@" ERROR :: NO master pool .... "]; + // NSLog(@" ERROR :: NO master pool .... "); + if(_socket || _connection) + [NSException raise:NSInvalidArgumentException format:@" ERROR :: NO master pool .... "]; } } @@ -340,8 +341,9 @@ -(PGConnectionOperation*)currentPoolOperation { masterPoolOperation = (__bridge PGConnectionOperation*) CFArrayGetValueAtIndex(_callbackOperationPool, ((indexInPool-1) >=0 ? indexInPool-1 : 0) ); }else{ -// NSLog(@" ERROR :: NO pool .... "); - [NSException raise:NSInvalidArgumentException format:@" ERROR :: NO pool .... "]; + // NSLog(@" ERROR :: NO pool .... "); + if(! _connectionClosed ) + [NSException raise:NSInvalidArgumentException format:@" ERROR :: NO pool .... "]; } } @@ -398,20 +400,38 @@ -(id)addOperation: (id)operationClass withCallBackWhenDone:(void*)callBackWhenDo } -(id)invalidateOperation:(NSInteger)operationRefIndex { - CFIndex indexInPool = CFArrayGetCount(_callbackOperationPool); - if(indexInPool > 0 && indexInPool>=operationRefIndex && operationRefIndex !=0) + @try { - id obj = CFArrayGetValueAtIndex(_callbackOperationPool, operationRefIndex); - if([obj semaphore]) - dispatch_semaphore_signal( [obj semaphore] ); - [obj finish]; - -//#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 - NSLog(@" %@::%@ :: REMOVED pool (%d :: %@ ) .... ", NSStringFromClass([self class]), NSStringFromSelector(_cmd), indexInPool-1, [obj description]); -//#endif - CFArrayRemoveValueAtIndex(_callbackOperationPool, operationRefIndex); + CFIndex indexInPool = CFArrayGetCount(_callbackOperationPool); + if(indexInPool > 0 && indexInPool>=operationRefIndex && operationRefIndex !=0) + { + id obj = CFArrayGetValueAtIndex(_callbackOperationPool, operationRefIndex); + dispatch_semaphore_t opeSemaphore = [obj semaphore]; + + [obj finish]; + + + //#if defined(DEBUG) && defined(DEBUG2) && DEBUG == 1 && DEBUG2 == 1 + NSLog(@" %@ (%p) :: %@ :: REMOVED pool (%d :: %p :: %@ ) .... ", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), operationRefIndex, obj, [obj description]); + //#endif + indexInPool = CFArrayGetCount(_callbackOperationPool); + if( indexInPool >= operationRefIndex ) + { + CFArrayRemoveValueAtIndex(_callbackOperationPool, operationRefIndex); + }else{ + NSLog(@" %@ (%p) :: %@ :: ERROR REMOVing pool (%d) .... ", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd), operationRefIndex); + } + + if(opeSemaphore) + dispatch_semaphore_signal( opeSemaphore ); + + } + }@catch (NSException *exception) { + NSLog(@" %@ exeception .... %@",NSStringFromSelector(_cmd),exception); } + @finally{} + return nil; } @@ -419,20 +439,20 @@ -(id)invalidateOperation:(NSInteger)operationRefIndex //{ // PGConnectionOperation* prevPoolOpe = [self prevPoolOperation]; // PGConnectionOperation* currentPoolOpe = [self currentPoolOperation]; -// +// // NSLog(@" Waiting for concurrent queries resultset (%lu) (%@) ...... ", [self connectionPoolOperationCount], [self currentPoolOperation]); // NSTimeInterval resolutionTimeOut = 0.5; // bool isRunning = NO; // while (1) { -// -// +// +// // prevPoolOpe = [self prevPoolOperation]; // currentPoolOpe = [self currentPoolOperation]; -// -// -// -// -// +// +// +// +// +// // if( // ([((PGConnectionOperation*)currentPoolOpe) valid] && [((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0 ) // // && [((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0 @@ -444,10 +464,10 @@ -(id)invalidateOperation:(NSInteger)operationRefIndex // isRunning = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; // [NSThread sleepForTimeInterval:0.02]; // // NSLog(@" >>>>> :::: %@ .... %d",NSStringFromSelector(_cmd),isRunning); -// +// // // return; // }else{ -// +// // break; // } // } @@ -457,18 +477,18 @@ -(id)invalidateOperation:(NSInteger)operationRefIndex //{ // NSTimeInterval resolutionTimeOut = 0.5; // bool isRunning = NO; -// +// // PGConnectionOperation* prevPoolOpe = [self prevPoolOperation]; // PGConnectionOperation* currentPoolOpe = [self currentPoolOperation]; -// +// // while ([((PGConnectionOperation*)currentPoolOpe) poolIdentifier] !=0) { -// -// +// +// // prevPoolOpe = [self prevPoolOperation]; // currentPoolOpe = [self currentPoolOperation]; -// -// -// +// +// +// // if([((PGConnectionOperation*)prevPoolOpe) valid] // && [((PGConnectionOperation*)currentPoolOpe) valid] // ) @@ -477,15 +497,15 @@ -(id)invalidateOperation:(NSInteger)operationRefIndex // // isRunning = [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:theNextDate]; // [NSThread sleepForTimeInterval:0.02]; // NSLog(@" >>>>> master wait :::: %@ .... %d",NSStringFromSelector(_cmd),isRunning); -// +// // // return; // }else{ // NSLog(@" >>>>> master wait :: done :::: .... %d",isRunning); // break; // } // } -// -// +// +// //} diff --git a/src/Frameworks/PGClientKit/PGConnectionOperation.m b/src/Frameworks/PGClientKit/PGConnectionOperation.m index 87dff24..5416d3f 100644 --- a/src/Frameworks/PGClientKit/PGConnectionOperation.m +++ b/src/Frameworks/PGClientKit/PGConnectionOperation.m @@ -160,6 +160,10 @@ -(id)queryString -(id)string { + + @try{ + + id queryStringDescription = [self queryString]; if(queryStringDescription != nil) { @@ -176,12 +180,23 @@ -(id)string return [_operation string]; } - + }@catch (NSException *exception) { + NSLog(@" %@ exeception .... %@",NSStringFromSelector(_cmd),exception); + } + @finally{} return @""; } -(NSString *)description { + @try + { return [NSString stringWithFormat:@"<%@:%p> \n OperationType : %@ \n Connection Delegate : <%@:%p> \n Operation (%@)",NSStringFromClass([self class]), self, _operationType, NSStringFromClass([_operationConnectionClassRef class ]), _operationConnectionClassRef, [self string] ]; + +}@catch (NSException *exception) { + NSLog(@" %@ exeception .... %@",NSStringFromSelector(_cmd),exception); +} +@finally{} + return @""; } @end From e0ccaeaac70add48f90d7e7775fbc3f8c09d416e Mon Sep 17 00:00:00 2001 From: Sebastien Cotillard Date: Fri, 25 Aug 2017 18:34:37 +0200 Subject: [PATCH 21/21] minor socket info added --- src/Frameworks/PGClientKit/PGConnection+Connect.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Frameworks/PGClientKit/PGConnection+Connect.m b/src/Frameworks/PGClientKit/PGConnection+Connect.m index 625b44b..f669668 100644 --- a/src/Frameworks/PGClientKit/PGConnection+Connect.m +++ b/src/Frameworks/PGClientKit/PGConnection+Connect.m @@ -148,7 +148,8 @@ -(void) _reconnectWithHandler: ( void(^ _Nullable )(void * pm,NSError* error)) c //:: _callback = (__bridge_retained void* )[callback copy]; // So we do good things to deal with cascaded Operation if(callback != nil){ -// if(CFArrayGetCount(_callbackOperationPool)) [[self masterPoolOperation] finish]; + if(CFArrayGetCount(_callbackOperationPool)) + id mp = [[self masterPoolOperation] class]; [self addOperation:self withCallBackWhenDone: (__bridge_retained void* )callback withCallBackWhenError: (__bridge_retained void* )callback ]; }else{ @@ -157,7 +158,7 @@ -(void) _reconnectWithHandler: ( void(^ _Nullable )(void * pm,NSError* error)) c [self _socketConnect:PGConnectionStateConnect]; } - NSLog(@" %@ :: connection Initilized ... ",NSStringFromSelector(_cmd)); + NSLog(@" %@ :: connection Initialized (%p :: connection : %p :: socket : %p) ... ",NSStringFromSelector(_cmd), self, _connection, _socket); }else{ NSLog(@" %@ :: connection seems good ... ",NSStringFromSelector(_cmd));