diff --git a/src/ASFKAuthorizationMgr.h b/src/ASFKAuthorizationMgr.h index d399c1d..9838b42 100644 --- a/src/ASFKAuthorizationMgr.h +++ b/src/ASFKAuthorizationMgr.h @@ -12,11 +12,11 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import -#import "ASFKMBSecret.h" +#import "ASFKBase.h" @interface ASFKAuthorizationMgr : NSObject{ @public ASFKSecretComparisonProc secretProcConfig; @public ASFKSecretComparisonProc secretProcCreate; @@ -26,12 +26,14 @@ @public ASFKSecretComparisonProc secretProcSecurity; @public ASFKSecretComparisonProc secretProcUnicast; @public ASFKSecretComparisonProc secretProcMulticast; + @public ASFKSecretComparisonProc secretProcBroadcast; @public ASFKSecretComparisonProc secretProcHost; @public ASFKSecretComparisonProc secretProcIssuer; @public ASFKSecretComparisonProc secretProcModerate; } @property (readonly) ASFKMasterSecret* masterSecret; +@property (readonly) ASFKFloatingSecret* floatingSecret; /*! @brief sets master secret. @discussion some operations require secret to be provided as parameter. Master secret overrides private secret in creation/deletion of group/user, but does not override reading/popping operations. Nil secret means that no secret exists, therefore secret check is skipped. @@ -41,12 +43,15 @@ */ -(BOOL) setMasterSecret:(ASFKMasterSecret*)oldsec newSecret:(ASFKMasterSecret*)newsec; -(BOOL) isMasterSecretValid:(ASFKMasterSecret*)msecret matcher:(ASFKSecretComparisonProc)match; +-(BOOL) setFloatingSecret:(ASFKFloatingSecret*)newsec authorizeWith:(ASFKMasterSecret*) msec; +-(BOOL) isFloatingSecretValid:(ASFKFloatingSecret*)fsecret matcher:(ASFKSecretComparisonProc)match; -(BOOL) matchCreatorSecret:(ASFKPrivateSecret*)secCurrent with:(ASFKPrivateSecret*)secOther; -(BOOL) matchDiscarderSecret:(ASFKSecret*)secCurrent with:(ASFKSecret*)secOther; -(BOOL) matchReaderSecret:(ASFKPrivateSecret*)secCurrent with:(ASFKPrivateSecret*)secOther; -(BOOL) matchPopperSecret:(ASFKPrivateSecret*)secCurrent with:(ASFKPrivateSecret*)secOther; -(BOOL) matchUnicasterSecret:(ASFKPrivateSecret*)secCurrent with:(ASFKPrivateSecret*)secOther; -(BOOL) matchMulticasterSecret:(ASFKPrivateSecret*)secCurrent with:(ASFKPrivateSecret*)secOther; +-(BOOL) matchBroadcasterSecret:(ASFKFloatingSecret*)secCurrent with:(ASFKFloatingSecret*)secOther; -(BOOL) matchHostSecret:(ASFKPrivateSecret*)secCurrent with:(ASFKPrivateSecret*)secOther; -(BOOL) matchSecuritySecret:(ASFKPrivateSecret*)secCurrent with:(ASFKPrivateSecret*)secOther; -(BOOL) matchConfigSecret:(ASFKPrivateSecret*)secCurrent with:(ASFKPrivateSecret*)secOther; diff --git a/src/ASFKAuthorizationMgr.mm b/src/ASFKAuthorizationMgr.mm index bf06a2a..e67cac1 100644 --- a/src/ASFKAuthorizationMgr.mm +++ b/src/ASFKAuthorizationMgr.mm @@ -13,7 +13,7 @@ along with this program. If not, see . */ // ASFKAuthorizationMgr.m -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase.h" #import "ASFKAuthorizationMgr.h" @@ -58,7 +58,17 @@ -(id)init{ return YES; } }; - + secretProcBroadcast=^BOOL(ASFKSecret* sec0,ASFKSecret* sec1){ + if(sec0 && sec1){ + return [sec1 matchesBroadcasterSecret:sec0]; + } + else if(sec0 || sec1){ + return NO; + } + else{ + return YES; + } + }; secretProcRead=^BOOL(ASFKSecret* sec0,ASFKSecret* sec1){ if(sec0 && sec1){ return [sec1 matchesReaderSecret:sec0]; @@ -149,7 +159,6 @@ -(id)init{ return YES; } }; - } return self; @@ -160,11 +169,10 @@ -(BOOL) setMasterSecret:(ASFKMasterSecret*)oldsec newSecret:(ASFKMasterSecret*)n if(newsec!=nil){ //test validity of new secret if([newsec validSecretSecurity]){ - _masterSecret=newsec; masterSecretBack=nil; - ASFKLog(@"DONE"); + DASFKLog(@"DONE"); return YES; } return NO; @@ -189,7 +197,7 @@ -(BOOL) setMasterSecret:(ASFKMasterSecret*)oldsec newSecret:(ASFKMasterSecret*)n _masterSecret=newsec; masterSecretBack=nil; - ASFKLog(@"DONE"); + DASFKLog(@"DONE"); return YES; } return NO; @@ -199,13 +207,75 @@ -(BOOL) setMasterSecret:(ASFKMasterSecret*)oldsec newSecret:(ASFKMasterSecret*)n [_masterSecret invalidateAll]; _masterSecret=newsec; - ASFKLog(@"DONE"); + DASFKLog(@"DONE"); return YES; } } return NO; } - ASFKLog(@"FAILED"); + WASFKLog(@"FAILED"); + return NO; +} +-(BOOL) setFloatingSecret:(ASFKFloatingSecret*)newsec authorizeWith:(ASFKMasterSecret*) msec{ + BOOL mastersecValid=NO; + if(_masterSecret == nil && msec == nil){ + mastersecValid=YES; + } +// else if(_masterSecret != nil && msec == nil){ +// +// } +// else if(_masterSecret == nil && msec != nil){ +// +// } + else if(_masterSecret != nil && msec != nil){ + mastersecValid=[_masterSecret validSecretSecurity]; + mastersecValid &= [msec validSecretSecurity]; + mastersecValid &= [self isMasterSecretValid:msec matcher:self->secretProcSecurity]; + + } +// if(_masterSecret ){ +// +// if(msec){ +// +// } +// else{ +// +// } +// } +// else if(msec==nil){ +// mastersecValid=YES; +// } + + if(mastersecValid){ + if(_floatingSecret==nil && newsec==nil){ + DASFKLog(@"DONE"); + return YES; + } + else if(_floatingSecret!=nil && newsec!=nil ){ + if([_floatingSecret validCharacteristic] && [newsec validCharacteristic]){ + _floatingSecret=newsec; + DASFKLog(@"DONE"); + return YES; + } + } + else if(_floatingSecret!=nil && newsec==nil){ + if([_floatingSecret validCharacteristic] ){ + _floatingSecret=newsec; + DASFKLog(@"DONE"); + return YES; + } + } + else if(_floatingSecret==nil && newsec!=nil){ + if([newsec validCharacteristic] ){ + _floatingSecret=newsec; + DASFKLog(@"DONE"); + return YES; + } + + } + } + + WASFKLog(@"FAILED"); return NO; } -(BOOL) matchCreatorSecret:(ASFKPrivateSecret*)secCurrent with:(ASFKPrivateSecret*)secOther{ @@ -281,6 +351,15 @@ -(BOOL) matchMulticasterSecret:(ASFKPrivateSecret*)secCurrent with:(ASFKPrivateS } return NO; } +-(BOOL) matchBroadcasterSecret:(ASFKFloatingSecret*)secCurrent with:(ASFKFloatingSecret*)secOther{ + if(secCurrent && secOther){ + BOOL r1=secretProcBroadcast(secCurrent,secOther); + return r1; + }else if(secCurrent==nil && secOther==nil){ + return YES; + } + return NO; +} -(BOOL) matchConfigSecret:(ASFKPrivateSecret*)secCurrent with:(ASFKPrivateSecret*)secOther{ if(secCurrent && secOther){ BOOL r1=secretProcConfig(secCurrent,secOther); @@ -309,7 +388,6 @@ -(BOOL) matchIssuerSecret:(ASFKPrivateSecret*)secCurrent with:(ASFKPrivateSecret return NO; } -#pragma mark - Private methods -(BOOL) isMasterSecretValid:(ASFKMasterSecret*)msecret matcher:(ASFKSecretComparisonProc)match{ if(_masterSecret && msecret){ BOOL r1=match(_masterSecret,msecret); @@ -319,4 +397,13 @@ -(BOOL) isMasterSecretValid:(ASFKMasterSecret*)msecret matcher:(ASFKSecretCompar } return NO; } +-(BOOL) isFloatingSecretValid:(ASFKFloatingSecret*)fsecret matcher:(ASFKSecretComparisonProc)match{ + if(_floatingSecret && fsecret){ + BOOL r1=match(_floatingSecret,fsecret); + return r1; + }else if(_floatingSecret==nil && fsecret==nil){ + return YES; + } + return NO; +} @end diff --git a/src/ASFKBase+Internal.h b/src/ASFKBase+Internal.h index f78f9e0..9c6135d 100644 --- a/src/ASFKBase+Internal.h +++ b/src/ASFKBase+Internal.h @@ -13,7 +13,8 @@ along with this program. If not, see . */ // -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 05/04/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase.h" @@ -25,6 +26,9 @@ +(ASFK_IDENTITY_TYPE) generateIdentity; +(NSString*) generateRandomString; +(NSNumber*) generateRandomNumber; ++(NSArray*) splitArray:(NSArray*) array to:(NSUInteger) chunks; ++(NSArray*) groupArray:(NSArray*) array by:(NSUInteger) items; + -(BOOL) isCancellationRequested; -(void) registerSession:(ASFKControlBlock*)cblk; -(ASFKControlBlock*) newSession; diff --git a/src/ASFKBase+Internal.mm b/src/ASFKBase+Internal.mm index 207c455..c5e2ad5 100644 --- a/src/ASFKBase+Internal.mm +++ b/src/ASFKBase+Internal.mm @@ -13,7 +13,8 @@ along with this program. If not, see . */ // -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 05/04/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase+Internal.h" @@ -52,7 +53,58 @@ +(NSNumber*) generateRandomNumber{ NSNumber* n=[NSNumber numberWithLongLong:r]; return n; } - ++(NSArray*) splitArray:(NSArray*) array to:(NSUInteger) chunks{ + if(array && [array count]>0){ + if(chunks > 0 && chunks <= [array count]){ + NSMutableArray* ma=[NSMutableArray array]; + NSUInteger asize=[array count]/chunks; + NSUInteger rem=[array count]%chunks; + for(NSUInteger i=0;i0){ + for (NSUInteger k=0; k0){ + if(items > 0 && items <= [array count]){ + NSMutableArray* ma=[NSMutableArray array]; +// NSUInteger chunks=[array count]/items; +// NSUInteger rem=[array count]%items; +// if(rem>0){ +// ++chunks; +// } + for(NSUInteger i=0,j=0;i<[array count];++i,++j){ + NSMutableArray* ma0=[ma lastObject];; + if(j==items){ + j=0; + } + if(j==0){ + ma0=[NSMutableArray array]; + [ma addObject:ma0]; + } + [ma0 addObject:[array objectAtIndex:i]]; + + } + + return ma; + } + return array; + } + return array; +} -(BOOL) isCancellationRequested{ return NO; diff --git a/src/ASFKBase+Statistics.h b/src/ASFKBase+Statistics.h index 0516e68..ea748e7 100644 --- a/src/ASFKBase+Statistics.h +++ b/src/ASFKBase+Statistics.h @@ -13,7 +13,8 @@ along with this program. If not, see . */ // -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 05/04/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase.h" diff --git a/src/ASFKBase+Statistics.mm b/src/ASFKBase+Statistics.mm index 2b0b83f..039cc41 100644 --- a/src/ASFKBase+Statistics.mm +++ b/src/ASFKBase+Statistics.mm @@ -13,7 +13,8 @@ along with this program. If not, see . */ // -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 05/04/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase+Statistics.h" diff --git a/src/ASFKBase.h b/src/ASFKBase.h index 02de9f3..3a9691e 100644 --- a/src/ASFKBase.h +++ b/src/ASFKBase.h @@ -12,13 +12,14 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 15/02/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import #import "ASFKPrjConfig.h" -#define ASFK_VERSION @"0.3.1" +#define ASFK_VERSION @"0.4.1" #define ASFK_IDENTITY_TYPE id #ifdef __ASFK_VERBOSE_PRINTING__ @@ -33,24 +34,41 @@ #define DASFKLog(...) #endif -#ifdef __ASFK_DEBUG__ +#ifdef __ASFK_WARNING__ #define WASFKLog(...) NSLog(@"~WARNING~ %@", [NSString stringWithFormat:__VA_ARGS__]) #else #define WASFKLog(...) #endif -#ifdef __ASFK_DEBUG__ +#ifdef __ASFK_ERROR__ #define EASFKLog(...) NSLog(@"~ERROR~ %@", [NSString stringWithFormat:__VA_ARGS__]) #else #define EASFKLog(...) #endif -#ifdef __ASFK_DEBUG__ +#ifdef __ASFK_MISUSE__ #define MASFKLog(...) NSLog(@"~MISUSE~ %@", [NSString stringWithFormat:__VA_ARGS__]) #else #define MASFKLog(...) #endif +#import +#import + +@interface ASFKReturnInfo : NSObject{ +@public double totalSessionTime; + @public double totalProcsTime; + @public double returnStatsProcsElapsedSec; + @public double returnStatsSessionElapsedSec; + @public std::uint64_t totalProcsCount; + @public std::uint64_t totalSessionsCount; + @public NSString* returnCodeDescription; + @public id returnResult; + @public id returnSessionId; + @public BOOL returnCodeSuccessful; +} + +@end #define kASFKGenKeySummary @"summary" #define ASFK_STATS_KEY_TIME_SESSIONS @"totalSessionsTime" #define ASFK_STATS_KEY_TIME_PROCS @"totalProcsTime" @@ -61,16 +79,16 @@ #define ASFK_RC_SUCCESS @"asfk_ret_code_succ" #define ASFK_RC_FAIL @"asfk_ret_code_fail" -#define kASFKReturnResult @"asfk_ret_result" + #define ASFK_RET_SUMRESULT @"asfk_ret_sumresult" #define ASFK_RET_NEXT_TARGET @"asfk_ret_nextTarget" + +#define kASFKReturnResult @"asfk_ret_result" #define kASFKReturnSessionId @"asfk_ret_sessionId" #define kASFKReturnDescription @"asfk_ret_description" - #define kASFKReturnStatsTimeProcsElapsedSec @"asfk_ret_stats_procs_tesec" #define kASFKReturnStatsTimeSessionElapsedSec @"asfk_ret_stats_session_tesec" - #define kASFKProgressRoutine @"progress_proc" #define kASFKCancelRoutine @"cancel_proc" #define kASFKSummaryRoutine @"summary_proc" @@ -78,8 +96,6 @@ #define kASFKSessionIdentity @"session_id" #define kASFKExpirationCondition @"exp_cond" -#import -#import /*! @brief modes of dropping */ @@ -101,22 +117,17 @@ enum eASFKQDroppingPolicy{ */ E_ASFK_Q_DP_ALGO }; - +#pragma mark - Auxilliary typedef id ( ^ASFKThreadpoolSummary)(void); @interface ASFKGlobalQueue : NSObject -+(ASFKGlobalQueue *)sharedManager; ++(ASFKGlobalQueue *)singleInstance; -(void) setSummary:(ASFKThreadpoolSummary)summary; -(id) submitBlocks:(NSArray*)blarray summary:(id(^)(void))summary QoS:(long)qos blocking:(BOOL)blocking; @end -@protocol ASFKRoutable -@required --(BOOL) push:(id)item; --(id) pull; -@end @protocol ASFKLockable @required -(void) begin; @@ -160,13 +171,12 @@ typedef id ( ^ASFKProgressRoutine)(NSUInteger stage,NSUInteger accomplished ,NSU @return YES for cancelling by starter; NO otherwise. */ -(BOOL) cancellationRequestedByStarter; --(NSString*)getCurrentSessionId; --(NSString*)getParentObjectId; +-(id)getCurrentSessionId; +-(id)getParentObjectId; -(ASFKProgressRoutine) getProgressRoutine; @end @interface ASFKControlBlock : NSObject{ - @protected std::atomic itsResPosition; @protected NSUInteger totalProcessors; @protected NSLock* itsLock;; @@ -187,9 +197,10 @@ typedef id ( ^ASFKProgressRoutine)(NSUInteger stage,NSUInteger accomplished ,NSU typedef void(^ASFKDefaultBlockType)(void); -typedef id ( ^ASFKExecutableRoutine)(id controlBlock, id data); +typedef id ( ^ASFKExecutableRoutine)(id controlBlock, id data, NSInteger dataIndex); typedef id ( ^ASFKExecutableRoutineSummary)(id controlBlock,NSDictionary* stats,id data); +typedef id ( ^ASFKExpirationRoutine)(id controlBlock,NSDictionary* stats,id data); typedef id ( ^ASFKCancellationRoutine)(id identity); typedef id ( ^ASFKOnPauseNotification)(id identity, BOOL paused); @@ -231,12 +242,9 @@ typedef BOOL ( ^ASFKExecutableRoutineConditional)(id contro */ typedef BOOL ( ^ASFKExecutableRoutineLoopConditional)(id controlBlock,long long iteration,id param); -@protocol ASFKLinkable -@required -@end - -@interface ASFKBase : NSObject{ +#pragma mark - Base +@interface ASFKBase : NSObject{ @protected NSLock* lkNonLocal; @protected NSMutableDictionary* ctrlblocks; @protected double totalProcs; @@ -280,42 +288,962 @@ typedef BOOL ( ^ASFKExecutableRoutineLoopConditional)(id c -(NSUInteger) controlBlocks; @end -#import "ASFKMBSecret.h" -#import "ASFKExpirationCondition.h" -@interface ASFKExecutionParams:NSObject{ -@public ASFKProgressRoutine progressProc; -@public ASFKExecutableRoutineSummary summaryRoutine; -@public NSArray* procs; -@public ASFKCancellationRoutine cancellationProc; -@public ASFKExpirationCondition* expCondition; -@public ASFKOnPauseNotification onPauseProc; +#pragma mark - Conditional Predicates +@interface ASFKCondition :NSObject{ +@protected NSLock* lock; +} +-(BOOL) isConditionMet:(id) data; +-(BOOL) isConditionMetForDoubleValues:(std::vector&)values data:(id)data; +-(BOOL) isConditionMetForBoolValues:(std::vector&)values data:(id)data; +-(BOOL) isConditionMetForULonglongValues:(std::vector&)values data:(id)data; +-(BOOL) isConditionMetForLonglongValues:(std::vector&)values data:(id)data; +-(BOOL) isConditionMetAfterDateValue:(NSDate*)aDate data:(id)data; +-(BOOL) isConditionMetForObject:(id)data; +-(BOOL) isConditionMetForDoubleValue:(double)value data:(id)data; +-(BOOL) isConditionMetForBoolValue:(BOOL)value data:(id)data; +-(BOOL) isConditionMetForULonglongValue:(std::uint64_t)value data:(id)data; +-(BOOL) isConditionMetForLonglongValue:(std::int64_t)value data:(id)data; + +-(std::vector&) getULLVector; +-(std::vector&) getLLVector; +-(std::vector&) getDoubleVector; +-(std::vector&) getBoolVector; +-(NSArray*) getDateVector; +-(NSArray*) getDataVector; +@end + +@interface ASFKConditionNone :ASFKCondition +-(BOOL) isConditionMetForULonglongValues:(std::vector&)values data:(id)data; +@end + +@interface ASFKConditionTemporal : ASFKCondition +@property (readonly,nonatomic) NSDate* itsDeadline; +@property (readonly,nonatomic) NSTimeInterval itsDelay; +-(id) initWithSeconds:(NSTimeInterval)sec; +-(id) initWithDate:(NSDate*)aDate; +-(void) setDelay:(NSTimeInterval) seconds; +-(void) setDueDate:(NSDate*) aDate; +-(void) setFromTemporalCondition:(ASFKConditionTemporal*)cond; +-(void) delayToDeadline; +-(void) deadlineToDelay; +/*! + @brief tests ordering between receiver and other object adn sets the receiver to have earliest deadline/delay. + @param cond object to be tested against. If nil - none is done. + @return receiver. + */ +-(ASFKConditionTemporal*) testAndSetEarliest:(ASFKConditionTemporal*)cond; +/*! + @brief tests ordering between receiver and other object adn sets the receiver to have latest deadline/delay. + @param cond object to be tested against. If nil - none is done. + @return receiver. + */ +-(ASFKConditionTemporal*) testAndSetLatest:(ASFKConditionTemporal*)cond; +/*! + @brief Compares the receiver with other object and returns object with latest deadline or delay. + @param cond object to be tested against. If nil - receiver will be returned. + @return obejct with latest deadline (delay). If deadline and delay not set for both - returns self. + */ +-(ASFKConditionTemporal*) chooseLatest:(ASFKConditionTemporal*)cond; +/*! + @brief Compares the receiver with other object and returns object with earliest deadline or delay. + @param cond object to be tested against. If nil - receiver will be returned. + @return obejct with latest deadline (delay). If deadline and delay not set for both - returns self. + */ +-(ASFKConditionTemporal*) chooseEarliest:(ASFKConditionTemporal*)cond; + + +@end + +@interface ASFKExpirationCondition : ASFKCondition +-(BOOL) setULonglongArg:(NSUInteger)arg; +-(BOOL) setLonglongArg:(NSInteger)arg; +-(BOOL) setBoolArg:(BOOL)arg; +-(BOOL) setDoubleArg:(double)arg; +-(BOOL) setObjArg:(id)arg; +-(BOOL) setDateArg:(NSDate*)arg; +-(BOOL) setULonglongArgs:(std::vector&)args; +-(BOOL) setLonglongArgs:(std::vector&)arg; +-(BOOL) setBoolArgs:(std::vector&)arg; +-(BOOL) setDoubleArgs:(std::vector&)arg; +-(BOOL) setObjArgs:(NSArray*)arg; +-(BOOL) setDateArgs:(NSArray*)arg; +-(BOOL) setSampleLongLong:(std::int64_t) val; +@end + +@interface ASFKExpirationConditionNone :ASFKExpirationCondition +-(id) initWithBatchSize:(NSInteger)size; +@end +@interface ASFKExpirationConditionOnTimer : ASFKExpirationCondition +@property (nonatomic,readonly) ASFKConditionTemporal* expirationTimer; +-(id) initWithSeconds:(NSTimeInterval)sec; +-(id) initWithDate:(NSDate*)aDate; +-(id) initWithTemporalCondition:(ASFKConditionTemporal*)cond; +@end + +@interface ASFKExpirationOnBatchEnd :ASFKExpirationCondition +-(id) initWithBatchSize:(std::int64_t)size skip:(std::int64_t)skip; +@end + +@interface ASFKConditionCallRelease : ASFKCondition{ +@private std::vector releaseArgBool; +@private std::vector releaseArgDouble; +@private std::vector releaseArgLongLong; +@private std::vector releaseArgULongLong; +} + +@property id releaseArgObject; +@property NSDate* releaseArgDate; + +@end + +typedef void (^ASFKPreBlockingRoutine)(); +/** + @brief defines modes of blocking call. +*/ +typedef enum enumASFK_BLOCKING_CALL_MODE{ + /** + @brief ASFK_BC_NO_BLOCK stands for no blocking allowed - calls on session in this mode will be rejected. + */ + ASFK_BC_NO_BLOCK, + /** + @brief ASFK_BC_CONTINUOUS stands for continuous mode - once processing of blocked batch started, first element of the next batch will be fetched for processing immediately after the last element of previous batch. I.e. processing of the next batch will not wait until the previous batch has been fully processed. + */ + ASFK_BC_CONTINUOUS, + /** + @brief ASFK_BC_EXCLUSIVE means that processing of the next batch will start only after the previous batch was fully processed. + */ + ASFK_BC_EXCLUSIVE +} eASFKBlockingCallMode; +#pragma mark - Secrets +@class ASFKSecret; +/* + Secrets are objects used to authorize operations; When API call invoked and secret is provided, it is tested against some other stored secret; if both secrets match, the operation is allowed. + Secrets are organized by types and roles. There are 3 types: Master, Private and Group. Master secret is single, global and can affect all mailboxes. Private/Group may affect only specific mailbox; Private secret should be created and used by mailbox owners only, while Group secret may be used by owner and group members. + Each secret may play different roles, while some roles are disabled for different secret types. + + Available Roles: Private Group Master Floating + 1. Creation of group mailbox x + by cloning or set operation + 2. Reading x x + 3. Popping x x + 4. Discarding of mailboxes and groups x x + 5. Unicast x x x + 6. Multicast x x x + 7. Broadcast x x x x + 8. Moderation - blinding/muting of members x x + 9. Security - changing secrets for Mailbox, Group, Global x x + 10. Issuer - retraction/hiding of posted messages x x + 11. Config - update of mailbox operational parameters x + 12. Hosting - addition/removal of members to/from Group mailbox x x + + Secrets lifetime and configuration: + All secrets have unlimited lifetime by default, which however can be configured to be temporary: for limited time period, limited number of use attempts or custom lifetime shortening criteria. When lifetime is ended the secret is invalidated forever. Manual invalidation is available too. + Any secret may be configured to have different properties. Any property may be configured only once. + */ + +typedef BOOL(^ASFKSecretComparisonProc)(id secret1,id secret2); +/*! + @brief Declaration of generic secret entity. + @discussion secrets are associated with containers and tested each time the container is accessed using high-level API. + */ +@interface ASFKSecret :NSObject{ +@private + id _secretModerator; + id _secretUnicaster; + id _secretMulticaster; + id _secretBroadcaster; + id _secretPopper; + id _secretReader; + id _secretDiscarder; + id _secretCreator; + id _secretSecurity; + id _secretConfigurer; + id _secretHost; + id _secretIssuer; +} +@property (readonly) ASFKConditionTemporal* timerExpiration; +#pragma mark - Unicast +-(BOOL) matchesUnicasterSecret:(ASFKSecret*)secret; +-(BOOL) setUnicasterSecretOnce:(id)secret; +-(BOOL) setUnicasterSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; +-(void) invalidateUnicasterSecret; +-(BOOL) validSecretUnicaster; +#pragma mark - Multicast +-(BOOL) matchesMulticasterSecret:(ASFKSecret*)secret; +-(BOOL) setMulticasterSecretOnce:(id)secret; +-(BOOL) setMulticasterSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; +-(void) invalidateMulticasterSecret; +-(BOOL) validSecretMulticaster; +#pragma mark - Broadcast +-(BOOL) matchesBroadcasterSecret:(ASFKSecret*)secret; +-(BOOL) setBroadcasterSecretOnce:(id)secret; +-(BOOL) setBroadcasterSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; +-(void) invalidateBroadcasterSecret; +-(BOOL) validSecretBroadcaster; +#pragma mark - Reader +-(BOOL) matchesReaderSecret:(ASFKSecret*)secret; +-(BOOL) setReaderSecretOnce:(id)secret; +-(BOOL) setReaderSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; +-(void) invalidateReaderSecret; +-(BOOL) validSecretReader; +#pragma mark - Popper +-(BOOL) matchesPopperSecret:(ASFKSecret*)secret; +-(BOOL) setPopperSecretOnce:(id)secret; +-(BOOL) setPopperSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; +-(void) invalidatePopperSecret; +-(BOOL) validSecretPopper; +#pragma mark - Discarder +-(BOOL) matchesDiscarderSecret:(ASFKSecret*)secret; +-(BOOL) setDiscarderSecretOnce:(id)secret; +-(BOOL) setDiscarderSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; +-(void) invalidateDiscarderSecret; +-(BOOL) validSecretDiscarder; +#pragma mark - Creator +-(BOOL) matchesCreatorSecret:(ASFKSecret*)secret; +-(BOOL) setCreatorSecretOnce:(id)secret; +-(BOOL) setCreatorSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; +-(void) invalidateCreatorSecret; +-(BOOL) validSecretCreator; +#pragma mark - Moderator +-(BOOL) matchesModeratorSecret:(ASFKSecret*)secret; +-(BOOL) setModeratorSecretOnce:(id)secret; +-(BOOL) setModeratorSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; +-(void) invalidateModeratorSecret; +-(BOOL) validSecretModerator; +#pragma mark - Host +-(BOOL) matchesHostSecret:(ASFKSecret*)secret; +-(BOOL) setHostSecretOnce:(id)secret; +-(BOOL) setHostSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; +-(void) invalidateHostSecret; +-(BOOL) validSecretHost; +#pragma mark - Issuer +-(BOOL) matchesIssuerSecret:(ASFKSecret*)secret; +-(BOOL) setIssuerSecretOnce:(id)secret; +-(BOOL) setIssuerSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; +-(void) invalidateIssuerSecret; +-(BOOL) validSecretIssuer; +#pragma mark - Config +-(BOOL) matchesConfigSecret:(ASFKSecret*)secret; +-(BOOL) setConfigSecretOnce:(id)secret; +-(BOOL) setConfigSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; +-(void) invalidateConfigSecret; +-(BOOL) validSecretConfig; +#pragma mark - Security +-(BOOL) matchesSecuritySecret:(ASFKSecret*)secret; +-(BOOL) setSecuritySecretOnce:(id)secret; +-(BOOL) setSecuritySecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; +-(void) invalidateSecuritySecret; +-(BOOL) validSecretSecurity; +#pragma mark - Common +/*! + @brief Irreversibly invalidates all associated roles. + */ +-(void) invalidateAll; +/*! + @brief Sets expiration date. This can be done once. + */ +-(BOOL) setExpirationDateOnce:(NSDate*)aDate; +/*! + @brief Sets delay in seconds before irreversible expiration. This can be done once. + @return YES if successful; NO otherwise. + */ +-(BOOL) setExpirationDelayOnce:(NSTimeInterval) sec; +/*! + @brief Tests passing of expiration deadline. + @return YES if passed; NO otherwise. + */ +-(BOOL) passedExpirationDeadline:(NSDate*)deadline; +/*! + @brief Sets maximum usage count before irreversible expiration. This can be done once. + @return YES if successful; NO otherwise. + */ +-(BOOL) setMaxUsageCountOnce:(NSInteger)maxCount; +/*! + @brief Tests passing of maximum usage count. + @return YES if passed; NO otherwise. + */ +-(BOOL) passedMaxUsageCount; +/*! + @brief Tests availability of roles + @return YES if all roles are available; NO if at least one is unavailable. + */ +-(BOOL) validAll; +/*! + @brief Tests availability of roles + @return YES if any role is available; NO if none is unavailable. + */ +-(BOOL) validAny; +/*! + @brief Tests availability of roles specific for given class. + @return YES if all class-specific roles are available; NO if at least one specific role is unavailable. + */ +-(BOOL) validCharacteristic; +@end +/*! + @brief Declaration of master secret entity. + @discussion If applied to container having private secret - the private secret is overriden if master secret is valid and non-nil. Roles available for master key: purging of maibox, deletion of mailbox, messages and users; setting of master secret; unicast, broadcast and multicast. Master secret may not be used for moderation, reading. + */ +@interface ASFKMasterSecret :ASFKSecret + +@end +/*! + @brief Declaration of private secret entity. + @discussion only container's owner, having private secret may use it. Roles available for private secret: purging of mailbox; creation of private mailbox; reading and popping; moderation - muting, blinding and so on; unicast, broadcast and multicast. + */ +@interface ASFKPrivateSecret :ASFKSecret + +@end +/*! + @brief Declaration of group secret entity. + @discussion only group owner and group members may use it. Roles available for group secret: purging of mailbox; reading and popping; moderation - muting, blinding and so on. + */ +@interface ASFKGroupSecret :ASFKPrivateSecret + +@end +/*! + @brief Declaration of floating secret entity. + @discussion any actor may use it. Roles available for floating secret: broadcast. + */ +@interface ASFKFloatingSecret :ASFKSecret + +@end +#pragma mark - Config Sets +@interface ASFKConfigParams:NSObject +{ + @public ASFKReturnInfo* retInfo; } +-(void) setupReturnInfo; +@end + +@interface ASFKExecutionParams:ASFKConfigParams{ + @public ASFKProgressRoutine progressProc; + @public ASFKExecutableRoutineSummary summaryRoutine; + @public NSArray* procs; + @public ASFKCancellationRoutine cancellationProc; + @public ASFKExpirationCondition* expCondition; + @public ASFKOnPauseNotification onPauseProc; + @public ASFKPreBlockingRoutine preBlock; +} +@end + +@interface ASFKSessionConfigParams:ASFKConfigParams{ + @public ASFKProgressRoutine progressProc; + @public ASFKExecutableRoutineSummary summaryRoutine; + @public NSArray* procs; + @public ASFKCancellationRoutine cancellationProc; + @public ASFKExpirationCondition* expCondition; + @public ASFKOnPauseNotification onPauseProc; + @public eASFKBlockingCallMode blockCallMode; +} +@end + +@protocol ASFKSynchronous +@end +@protocol ASFKAsynchronous +@end +#pragma mark - Flow +@interface ASFKLinearFlow : ASFKBase{ + +} +/*! + @brief Performs non-blocking call with on array of data and invokes stored Summary block with result. + @param array array of data for processing. + @return dictionary that includes result of execution followed by additional information. + */ +-(BOOL) castArray:(NSArray*)array exParams:(ASFKExecutionParams*)ex; +-(BOOL) castArray:(NSArray*)array groupBy:(NSUInteger) grpSize exParams:(ASFKExecutionParams*)ex; +-(BOOL) castArray:(NSArray*)array splitTo:(NSUInteger) numOfChunks exParams:(ASFKExecutionParams*)ex; + +/*! + @brief Performs non-blocking call with dictionary of data and invokes stored Summary block with result. + @param dictionary dictionary of data. + @return dictionary that includes result of execution followed by additional information. + */ +-(BOOL) castDictionary:(NSDictionary*)dictionary exParams:(ASFKExecutionParams*)ex; + +/*! + @brief Performs non-blocking call with ordered set of data and invokes stored Summary block with result. + @param set ordered set of data. + @return dictionary that includes result of execution followed by additional information. + */ +-(BOOL) castOrderedSet:(NSOrderedSet*)set exParams:(ASFKExecutionParams*)ex; +/*! + @brief Performs non-blocking call with unordered set of data and invokes stored Summary block with result. + @param set unordered set of data. + @return dictionary that includes result of execution followed by additional information. + */ +-(BOOL) castUnorderedSet:(NSSet*)set exParams:(ASFKExecutionParams*)ex; +/*! + @brief Performs non-blocking call with dictionary of data and invokes stored Summary block with result. + @param uns unspecified piece of data. + @return dictionary that includes result of execution followed by additional information. + */ +-(BOOL) castObject:(id)uns exParams:(ASFKExecutionParams*)ex; +/** + @brief Performs blocking call with array of data and invokes stored Summary block. The method will return only after processing of data has ended. + @param array array of data for processing. + @return dictionary that includes result of execution followed by additional information. + */ +-(BOOL) callArray:(NSArray*)array exParams:(ASFKExecutionParams*)params; +-(BOOL) callArray:(NSArray*)array groupBy:(NSUInteger) grpSize exParams:(ASFKExecutionParams*)ex; +-(BOOL) callArray:(NSArray*)array splitTo:(NSUInteger) numOfChunks exParams:(ASFKExecutionParams*)ex; +/** + @brief Performs blocking call with dictionary of data and invokes stored Summary block with result. The method will return only after processing of data has ended. + @param dictionary dictionary of data. + @return dictionary that includes result of execution followed by additional information. + */ +-(BOOL) callDictionary:(NSDictionary*)dictionary exParams:(ASFKExecutionParams*)ex; +/** + @brief Performs blocking call with ordered set of data and invokes stored Summary block with result. The method will return only after processing of data has ended. + @param set ordered set of data. + @return dictionary that includes result of execution followed by additional information. + */ +-(BOOL) callOrderedSet:(NSOrderedSet*)set exParams:(ASFKExecutionParams*)ex; + +/** + @brief Performs blocking call with unordered of data and invokes stored Summary block with result. The method will return only after processing of data has ended. + @param set unordered set of data. + @return dictionary that includes result of execution followed by additional information. + */ +-(BOOL) callUnorderedSet:(NSSet*)set exParams:(ASFKExecutionParams*)ex; +/*! + @brief Performs blocking call with dictionary of data and invokes stored Summary block with result. The method will return only after processing of data has ended. + @param uns unspecified piece of data. + @return dictionary that includes result of execution followed by additional information. + */ +-(BOOL) callObject:(id)uns exParams:(ASFKExecutionParams*)ex; + +-(id) pull; + @end +#pragma mark - Sessional Flow +@interface ASFKSessionalFlow : ASFKBase{ +@protected NSMutableArray * _backprocs; +@protected NSArray *lfProcs; +@protected ASFKExecutableRoutineSummary sumProc; +@protected ASFKOnPauseNotification onPauseProc; +@protected ASFKCancellationRoutine cancellationHandler; +@protected dispatch_semaphore_t semHighLevelCall; +} +-(NSArray *) getRoutines; +-(std::uint64_t) getRoutinesCount; +-(std::uint64_t) getDataItemsCount; +-(ASFKExecutableRoutineSummary) getSummaryRoutine; +-(ASFKCancellationRoutine) getCancellationHandler; +/*! + @brief Performs non-blocking call with on array of data and invokes stored Summary block with result. + @param array array of data for processing. + @return dictionary that includes result of execution followed by additional information. + */ +-(NSDictionary*) castArray:(NSArray*)array session:(id)sessionId exParams:(ASFKExecutionParams*)ex; + +/*! + @brief Performs non-blocking call with dictionary of data and invokes stored Summary block with result. + @param dictionary dictionary of data. + @return dictionary that includes result of execution followed by additional information. + */ +-(NSDictionary*) castDictionary:(NSDictionary*)dictionary session:(id)sessionId exParams:(ASFKExecutionParams*)ex; + +/*! + @brief Performs non-blocking call with ordered set of data and invokes stored Summary block with result. + @param set ordered set of data. + @return dictionary that includes result of execution followed by additional information. + */ +-(NSDictionary*) castOrderedSet:(NSOrderedSet*)set session:(id)sessionId exParams:(ASFKExecutionParams*)ex; +/*! + @brief Performs non-blocking call with unordered set of data and invokes stored Summary block with result. + @param set unordered set of data. + @return dictionary that includes result of execution followed by additional information. + */ +-(NSDictionary*) castUnorderedSet:(NSSet*)set session:(id)sessionId exParams:(ASFKExecutionParams*)ex; +/*! + @brief Performs non-blocking call with dictionary of data and invokes stored Summary block with result. + @param uns unspecified piece of data. + @return dictionary that includes result of execution followed by additional information. + */ +-(NSDictionary*) castObject:(id)uns session:(id)sessionId exParams:(ASFKExecutionParams*)ex; +/** + @brief Performs blocking call with array of data and invokes stored Summary block. The method will return only after processing of data has ended. + @param array array of data for processing. + @return dictionary that includes result of execution followed by additional information. + */ +-(NSDictionary*) callArray:(NSArray*)array session:(id)sessionId exParams:(ASFKExecutionParams*)params; + +/** + @brief Performs blocking call with dictionary of data and invokes stored Summary block with result. The method will return only after processing of data has ended. + @param dictionary dictionary of data. + @return dictionary that includes result of execution followed by additional information. + */ +-(NSDictionary*) callDictionary:(NSDictionary*)dictionary session:(id)sessionId exParams:(NSDictionary*)ex; +/** + @brief Performs blocking call with ordered set of data and invokes stored Summary block with result. The method will return only after processing of data has ended. + @param set ordered set of data. + @return dictionary that includes result of execution followed by additional information. + */ +-(NSDictionary*) callOrderedSet:(NSOrderedSet*)set session:(id)sessionId exParams:(NSDictionary*)ex; + +/** + @brief Performs blocking call with unordered of data and invokes stored Summary block with result. The method will return only after processing of data has ended. + @param set unordered set of data. + @return dictionary that includes result of execution followed by additional information. + */ +-(NSDictionary*) callUnorderedSet:(NSSet*)set session:(id)sessionId exParams:(NSDictionary*)ex; +/*! + @brief Performs blocking call with dictionary of data and invokes stored Summary block with result. The method will return only after processing of data has ended. + @param uns unspecified piece of data. + @return dictionary that includes result of execution followed by additional information. + */ +-(NSDictionary*) callObject:(id)uns session:(id)sessionId exParams:(NSDictionary*)ex; + +/*! + @brief Equals NO if sender is updating stored Routines; YES otherwise. + */ +-(BOOL) isReady; + +/** + @brief Appends block which invokes Objective-C code; the block is added to internal collection. This operation may succeed only if no Routine is active at time of addition. + @param proc block that processes a data. + */ +-(BOOL) addRoutine:(ASFKExecutableRoutine)proc; + +/** + @brief Stores array of Routines for later use; content of array is copied and added to internal collection. + This operation may succeed only if no Routine is active at time of addition. + @param procs new array of Routines. + @return YES if operation succeeded; NO otherwise; + */ +-(BOOL) addRoutines:(NSArray*)procs; + +/** + @brief Replaces existing collection of Routines with new one. This operation may succeed only if no Routine is active at time of addition. + @param procs new array of Routines. If aray is empty or nil, nothing happens. + @return YES if operation succeeded; NO otherwise. + */ +-(BOOL) replaceRoutinesFromArray:(NSArray*)procs; +/** + @brief Stores summary block which invokes Objective-C code + @param summary block that is called after all Routines. + */ +-(BOOL) setSummary:(ASFKExecutableRoutineSummary)summary; +-(BOOL) setOnPauseNotification:(ASFKOnPauseNotification)notification; +/** + @brief Stores block which invokes Objective-C code as a summary for cancelled session. + @param ch block that is called in case of cancellation. + */ +-(BOOL) setCancellationHandler:(ASFKCancellationRoutine)ch; -#import "ASFKNonlinearFlow.h" -#import "ASFKLinearFlow.h" +@end +#pragma mark - Queues @interface ASFKQueue : ASFKLinearFlow{ @protected NSLock* lock; @protected NSMutableArray* q; +@protected std::atomic blocking; +@protected std::atomic paused; +@protected std::atomic maxQSize; +@protected std::atomic minQSize; } +-(id) initWithName:(NSString*) name blocking:(BOOL)blk; +/*! + @brief deletes all accumulated data and resetes configuration. + @discussion removes queue contents and resets configuration data to defaults. + */ -(void) reset; --(NSUInteger)count; --(BOOL) isEmpty; +/*! + @brief deletes all accumulated data. + @discussion removes queue contents only. + */ +-(void) purge; +/*! + @brief Sets maximum queue size. + @discussion when the queue size reaches this value any further enqueing operation will not increase it. + @param size required maximum size. + @return YES if the update was successful, NO otherwise. + */ +-(BOOL) setMaxQSize:(NSUInteger)size; +/*! + @brief Sets minimum queue size. + @discussion when the queue size reaches this value any further enqueing operation will not decrease it. + @param size required minimum size. + @return YES if the update was successul, NO otherwise. + */ +-(BOOL) setMinQSize:(NSUInteger)size; +#pragma mark - replacing contents +/*! + @brief replaces contents of receiver by contents of another queue. + */ -(void) queueFromQueue:(ASFKQueue*)q; -@end - -@interface ASFKThreadpoolQueue:ASFKQueue +/*! + @brief replaces contents of receiver by contents of an array. + */ -(void) queueFromArray:(NSArray*)array; +/*! + @brief replaces contents of receiver by contents of ordered set. + */ -(void) queueFromOrderedSet:(NSOrderedSet*)set; +/*! + @brief replaces contents of receiver by contents of unordered set. + */ -(void) queueFromUnorderedSet:(NSSet*)set; --(void) queueFromQueue:(ASFKThreadpoolQueue*)queue; --(void) queueFromItem:(id)item; --(id) pullAndOccupyWithId:(long)itsid empty:(BOOL&)empty; +/*! + @brief replaces values of receiver by contents of a dictionary. Keys are ignored. + */ +-(void) queueFromDictionary:(NSDictionary*)dict; +#pragma mark - prepending +/*! + @brief puts contents of another queue at head of receiver's queue. Not available in blocking mode. + */ +-(BOOL) prependFromQueue:(ASFKQueue*)q; +/*! + @brief puts contents of array at head of receiver's queue. Not available in blocking mode. + */ +-(BOOL) prependFromArray:(NSArray*)array; +/*! + @brief puts contents of ordered set at head of receiver's queue. Not available in blocking mode. + */ +-(BOOL) prependFromOrderedSet:(NSOrderedSet*)set; +/*! + @brief puts contents of unordered set at head of receiver's queue. Not available in blocking mode. + */ +-(BOOL) prependFromUnorderedSet:(NSSet*)set; +/*! + @brief puts values of a dictionary at head of receiver's queue. Keys are ignored + */ +-(BOOL) prependFromDictionary:(NSDictionary*)dict; +#pragma mark - Non-Blocking interface +-(BOOL) castQueue:(ASFKQueue* _Nullable)q exParams:(ASFKExecutionParams* _Nullable)ex; +/*! + @brief adds items of array to the queue; returns immediately. + @param array the source array. + @param ex optional extra parameters. + @return YES for success; NO for fail. + */ +-(BOOL) castArray:(NSArray* _Nullable)array exParams:(ASFKExecutionParams* _Nullable)ex; +/*! + @brief adds items of ordered set to the queue; returns immediately. + @param set the source set. + @param ex optional extra parameters. + @return YES for success; NO for fail. + */ +-(BOOL) castOrderedSet:(NSOrderedSet* _Nullable)set exParams:(ASFKExecutionParams* _Nullable)ex; +/*! + @brief adds items of unordered set to the queue; returns immediately. + @param set the source set. + @param ex optional extra parameters. + @return YES for success; NO for fail. + */ +-(BOOL) castUnorderedSet:(NSSet* _Nullable)set exParams:(ASFKExecutionParams* _Nullable)ex; +/*! + @brief adds items of dictionary to the queue, keys ignored; returns immediately. + @param dict the source array. + @param ex optional extra parameters. + @return YES for success; NO for fail. + */ +-(BOOL) castDictionary:(NSDictionary* _Nullable)dict exParams:(ASFKExecutionParams* _Nullable)ex; +/*! + @brief adds single item to the queue; returns immediately. + @param obj the object. + @param ex optional extra parameters. + @return YES for success; NO for fail. + */ +-(BOOL) castObject:(id _Nullable)obj exParams:(ASFKExecutionParams* _Nullable)ex; +/*! + @brief retrieves item from the queue. In blocking mode if the queue is empty, waits for at least one item. + */ +-(id _Nullable ) pull; +#pragma mark - Blocking interface + +-(BOOL) callQueue:(ASFKQueue*_Nullable)q exParams:(ASFKExecutionParams*_Nullable) ex; +/*! + @brief adds items of array to the queue; in blocking mode returns when the item consumed; otherwise acts same as 'cast'. + @param array the source array. + @param ex optional extra parameters. + @return YES for success; NO for fail. + */ +-(BOOL) callArray:(NSArray* _Nullable) array exParams:(ASFKExecutionParams* _Nullable) ex; +/*! + @brief adds items of ordered set to the queue; in blocking mode returns when the item consumed; otherwise acts same as 'cast' counterpart. + @param set the source set. + @param ex optional extra parameters. + @return YES for success; NO for fail. + */ +-(BOOL) callOrderedSet:(NSOrderedSet* _Nullable)set exParams:(ASFKExecutionParams* _Nullable) ex; +/*! + @brief adds items of unordered set to the queue; in blocking mode returns when the item consumed; otherwise acts same as 'cast' counterpart. + @param set the source set. + @param ex optional extra parameters. + @return YES for success; NO for fail. + */ +-(BOOL) callUnorderedSet:(NSSet* _Nullable)set exParams:(ASFKExecutionParams* _Nullable) ex; +/*! + @brief adds items of dictionary to the queue, keys ignored; in blocking mode returns when the item consumed; otherwise acts same as 'cast' counterpart. + @param dict the source array. + @param ex optional extra parameters. + @return YES for success; NO for fail. + */ +-(BOOL) callDictionary:(NSDictionary* _Nullable)dict exParams:(ASFKExecutionParams* _Nullable) ex; +/*! + @brief adds single item to the queue; in blocking mode returns when the item consumed; otherwise acts same as 'cast' counterpart. + @param obj the object. + @param ex optional extra parameters. + @return YES for success; NO for fail. + */ +-(BOOL) callObject:(id _Nullable)obj exParams:(ASFKExecutionParams* _Nullable) ex; +#pragma mark - querying +-(NSUInteger)count; +-(BOOL) isEmpty; +-(BOOL) isBlocking; +/*! + @brief pauses reading from queue. When paused, the queue will return nil on any reading attempt. + */ +-(void) pause; + +/*! + @brief resumes reading from queue. + */ +-(void) resume; + +@end + +@interface ASFKPriv_EndingTerm : NSObject ++ (ASFKPriv_EndingTerm * _Nonnull)singleInstance ; +@end + +/*! + @class ASFKBatchingQueue + @brief provides queueing functionality for batches. + @discussion any call enqueues exactly one object (batch) which in turn can contain single object or collection. Each dequeuing call returns exactly one object from the earliest batch until it is exgausted; after that next batch is tapped. Main reason for such behavior: blocking calls. If blocking mode is disabled then calls do the same as casts. Otherwise, call will block until all of its batch is consumed. + */ +@interface ASFKBatchingQueue : ASFKQueue +{ +//@protected std::atomic paused; +@protected std::atomic batchLimitUpper; +@protected std::atomic batchLimitLower; +@protected std::atomic netCount; +} +-(BOOL) setUpperBatchLimit:(std::uint64_t)limit; +-(BOOL) setLowerBatchLimit:(std::uint64_t)limit; +#pragma mark - casting with accumulation +-(NSUInteger) candidateCount; +/*! + @brief adds array to cumulative batch. The batch will not be added to queue until it is finalized. + @discussion if resulting batch size exceeds the established upper bound, the operation will fail. + @param array the array. + @return YES for success, NO otherwise. + */ +-(BOOL) castArrayToBatch:(NSArray*_Nullable) array; +/*! + @brief adds unordered set to cumulative batch. The batch will not be added to queue until it is finalized. + @discussion if resulting batch size exceeds the established upper bound, the operation will fail. + @param set the set. + @return YES for success, NO otherwise. + */ +-(BOOL) castUnorderedSetToBatch:(NSSet*_Nullable) set ; +/*! + @brief adds ordered set to cumulative batch. The batch will not be added to queue until it is finalized. + @discussion if resulting batch size exceeds the established upper bound, the operation will fail. + @param set the set. + @return YES for success, NO otherwise. + */ +-(BOOL) castOrderedSetToBatch:(NSOrderedSet*_Nullable) set ; +/*! + @brief adds dictionary to cumulative batch. The batch will not be added to queue until it is finalized. Only values are stored, keys are ignored. + @discussion if resulting batch size exceeds the established upper bound, the operation will fail. + @param dict the dictionary. + @return YES for success, NO otherwise. + */ +-(BOOL) castDictionaryToBatch:(NSDictionary*_Nullable) dict ; +/*! + @brief adds single object to cumulative batch. The batch will not be added to queue until it is finalized. + @discussion if resulting batch size exceeds the established upper bound, the operation will fail. + @param obj the dictionary. + @return YES for success, NO otherwise. + */ +-(BOOL) castObjectToBatch:(id _Nullable ) obj; +/*! + @brief finalizes cumulative batch. The batch will be added to queue and new cumulative batch will be created. + @param force if NO, then cumulative batch size will be examined against minimum size and, if less than the minumum or greater than maximum - operation will fail. Otherwise the batch will be appended to queue disregarding the size. + @return YES for success, NO otherwise. + */ +-(BOOL) commitBatch:(BOOL) force; +/*! + @brief resets cumulative batch. The batch will be cleared form all accumulated objects. + @return YES for success, NO otherwise. + */ +-(BOOL) resetBatch; + +#pragma mark - update from another queue +-(void) queueFromBatchingQueue:(ASFKBatchingQueue* _Nullable)otherq; +/*! + @brief pauses reading from queue for batches. After invocation, reading method calls will return all items belonging to batch. When entire batch is read, next reading calls will return nil, until 'resume' method invoked. + */ +-(void) pause; + +/*! + @brief resumes reading from queue for batches. + */ +-(void) resume; + +/*! + @brief returns number of batches in queue. + */ +-(NSUInteger) batchCount; + +-(NSArray* _Nullable ) pullBatchAsArray; +@end + +@interface ASFKFilter : ASFKLinearFlow +/*! + @brief Tests given object with some custom criteria. + @param object object to test. + @return YES if test passes; NO otherwise. + */ +-(BOOL) testCriteriaMatch:(id)object; +/*! + @brief Tests array of objects. + @param objects objects to test. + @param writeOut indication of whether to save passing objects or non-passing. YES for passing, NO otherwise. + @param array array of filtered objects. + @return YES if at least one test passes; NO otherwise. + */ +-(BOOL) filterCandidatesInArray:(NSArray*)objects passing:(BOOL)writeOut saveToArray:(NSMutableArray*)array; +/*! + @brief Tests array of objects. + @param objects objects to test. + @param writeOut indication of whether to save passing objects or non-passing. YES for passing, NO otherwise. + @param iset index set of filtered objects. + @return YES if at least one test passes; NO otherwise. + */ +-(BOOL) filterCandidatesInArray:(NSArray*)objects passing:(BOOL)writeOut saveToIndexSet:(NSMutableIndexSet*)iset; +/*! + @brief Tests array of objects. + @param objects objects to test. + @param writeOut indication of whether to save passing objects or non-passing. YES for passing, NO otherwise. + @param range range of indexes of filtered objects. + @return YES if at least one test passes; NO otherwise. + */ +-(BOOL) filterCandidatesInArray:(NSArray*)objects passing:(BOOL)writeOut saveToRange:(NSRange&)range; +/*! + @brief Tests unordered set of objects. + @param objects objects to test. + @param writeOut indication of whether to save passing objects or non-passing. YES for passing, NO otherwise. + @param array array of filtered objects. + @return YES if at least one test passes; NO otherwise. + */ +-(BOOL) filterCandidatesInSet:(NSSet*)objects passing:(BOOL)writeOut saveToArray:(NSMutableArray*)array; +/*! + @brief Tests unordered set of objects. + @param objects ordered set of objects to test. + @param writeOut indication of whether to save passing objects or non-passing. YES for passing, NO otherwise. + @param iset index set of filtered objects. + @return YES if at least one test passes; NO otherwise. + */ +-(BOOL) filterCandidatesInOrderedSet:(NSOrderedSet*)objects passing:(BOOL)writeOut saveToIndexSet:(NSMutableIndexSet*)iset; +/*! + @brief Tests unordered set of objects. + @param objects ordered set of objects to test. + @param writeOut indication of whether to save passing objects or non-passing. YES for passing, NO otherwise. + @param range range of indexes of filtered objects. + @return YES if at least one test passes; NO otherwise. + */ +-(BOOL) filterCandidatesInOrderedSet:(NSOrderedSet*)objects passing:(BOOL)writeOut saveToRange:(NSRange&)range; +/*! + @brief Tests dictionary of objects. + @param objects ordered set of objects to test. + @param writeOut indication of whether to save passing objects or non-passing. YES for passing, NO otherwise. + @param keys array of keys of filtered objects. If nil, then not used. + @param values array of values of filtered objects. If nil, then not used. + @return YES if at least one test passes; NO otherwise. + */ +-(BOOL) filterCandidatesInDictionary:(NSDictionary*)objects passing:(BOOL)writeOut saveToKeys:(NSMutableArray*)keys values:(NSMutableArray*)values; +@end + +@interface ASFKFilteringQueue : ASFKQueue +typedef NSIndexSet* (^clbkASFKFQFilter)(NSArray* collection, NSRange range); + +/*! + @brief Sets dropping methods for this queue. + @discussion when the queue's maximum size reached then on 'push' operation decision needs to be taken regarding fresh candidate. In order to keep the queue size unchanged some item(s) need to be discarded; alternatively new candidate may be rejected. This method sets specific dropping mode. + */ +-(void) setDroppingPolicy:(eASFKQDroppingPolicy)policy; +/*! + @brief Sets dropping algorithm for this queue. + @discussion queue items may need to be dropped not only by exceeding the limits, but by some user-defined algorithm. + @param dropAlg the custom dropping algorithm; may bi nil. + */ +-(void) setDroppingAlgorithm:(ASFKFilter*_Nullable)dropAlg; +/*! + @brief Pulls item from queue, while simulating the queue size. + @discussion Sometimes it is necessary to pull item from queue while pretending that its size is different from the actual. + @param count number to be temporarily added to the queue size while deciding if item can be pulled. + */ +-(id _Nullable ) pullWithCount:(NSInteger) count; +/*! + @brief Filters queue with provided filtering object. + @discussion Leaves in queue only items that do not match filtering criteria. + @param filter the filtering object; may be nil. + */ +-(void) filterWith:(ASFKFilter*_Nullable)filter; +/*! + @brief Removes from queue given object. + @discussion Removes from queue all objects equal to given object with respect to provided property; equality is defined by the block. + @param obj object to remove; may not be nil. + @param blk block that tests equality; must return YES to remove; may not be nil. + @return YES for succesful removal; NO otherwise. + */ +-(BOOL) removeObjWithProperty:(id)obj andBlock:(BOOL (^)(id item,id sample, BOOL* stop)) blk; +@end + + +#pragma mark - private interfaces + +@interface ASFKPriv_WrapBQ:NSObject{ +@public NSCondition* writecond;; +@public std::atomic wcPred; +@public NSMutableArray* many; +} +@end +/*! + @brief ASFKBatchingQueue2 + @discussion internal use. Main purpose: providing 'call' methods without unblocking thread waiting to read. + */ +@interface ASFKBatchingQueue2 : ASFKBatchingQueue +{ +@protected NSMutableArray* deferred; +} +-(id _Nullable ) initWithName:(NSString*_Nullable) name blocking:(BOOL)blk; +-(id _Nullable) pullAndBatchStatus:(NSInteger&)itemsLeft endBatch:(BOOL&)endBatch term:(ASFKPriv_EndingTerm** _Nonnull)term; +-(void) queueFromBatchingQueue:(ASFKBatchingQueue* _Nullable)otherq; +-(void) releaseFirst; +-(void) releaseAll; +@end +/*! + @brief ASFKBatchingQueue3 + @discussion internal use. Main purpose: providing 'call' methods without unblocking thread waiting to read. + */ +@interface ASFKBatchingQueue3 : ASFKBatchingQueue2 +{} +@end + +@interface ASFKThreadpoolQueue:ASFKQueue{ +@protected NSInteger occupant;; +} +-(void) queueFromThreadpoolQueue:(ASFKThreadpoolQueue*)queue; +//-(void) queueFromItem:(id)item; +-(id) pullAndOccupyWithId:(long)itsid empty:(BOOL&)empty index:(NSInteger&)itemIndex term:(ASFKPriv_EndingTerm**)term; +-(BOOL) castObject:(id _Nullable )item exParams:(ASFKExecutionParams*_Nullable)ex index:(NSInteger)index; -(void) unoccupyWithId:(long)itsid; -(void) unoccupy; @end +@interface ASFKThreadpoolQueueHyb : ASFKThreadpoolQueue{ + @public id itsSig; +} +-(id) initWithBlkMode:(eASFKBlockingCallMode) blockingMode; +-(void) _releaseBlocked; +-(void) _releaseBlockedAll; +@end + typedef enum enumASFKPipelineExecutionStatus{ eASFK_ES_HAS_MORE=0, eASFK_ES_HAS_NONE, @@ -324,48 +1252,414 @@ typedef enum enumASFKPipelineExecutionStatus{ } eASFKThreadpoolExecutionStatus; typedef id ( ^ASFKThreadpoolSessionCancelProc)(id sessionId); + +#pragma mark - Threadpool session(s) @interface ASFKThreadpoolSession : ASFKBase{ - @public ASFKControlBlock* cblk; + @public ASFKControlBlock* cblk; @protected ASFKExecutableRoutineSummary passSummary; - @protected ASFKExecutableRoutineSummary expirationSummary; + @protected ASFKExpirationRoutine expirationSummary; @protected ASFKCancellationRoutine cancellationHandler; @protected NSMutableArray* procs; @protected ASFKExpirationCondition* excond; @public ASFKOnPauseNotification onPauseNotification; + @public ASFKThreadpoolSessionCancelProc cancellationProc; @public std::atomic isStopped; @public std::atomic paused; - @public ASFKThreadpoolSessionCancelProc cancellationProc; + @public std::atomic callMode; + } @property ASFK_IDENTITY_TYPE sessionId; -(ASFKControlBlock*) getControlBlock; --(id)initWithSessionId:(ASFK_IDENTITY_TYPE)sessionId andSubsessionId:(ASFK_IDENTITY_TYPE)subId; +-(id) initWithSessionId:(ASFK_IDENTITY_TYPE)sessionId andSubsessionId:(ASFK_IDENTITY_TYPE)subId blkMode:(eASFKBlockingCallMode)blkMode; -(void) flush; -(void) cancel; --(void) postDataItemsAsArray:(NSArray*)array; --(void) postDataItemsAsOrderedSet:(NSOrderedSet*)set; --(void) postDataItemsAsUnorderedSet:(NSSet*)set; --(void) postDataItemsAsDictionary:(NSDictionary*)dict; --(void) postDataItem:(id)dataItem; --(void) replaceRoutinesWithArray:(NSArray*)procs; --(void) setProgressRoutine:(ASFKProgressRoutine)progress; --(void) setSummary:(ASFKExecutableRoutineSummary)sum; --(void) setExpirationSummary:(ASFKExecutableRoutineSummary)sum; +-(BOOL) postDataItemsAsArray:(NSArray*_Nullable)array blocking:(BOOL)blk; +-(BOOL) postDataItemsAsOrderedSet:(NSOrderedSet*_Nullable)set blocking:(BOOL)blk; +-(BOOL) postDataItemsAsUnorderedSet:(NSSet*_Nullable)set blocking:(BOOL)blk; +-(BOOL) postDataItemsAsDictionary:(NSDictionary*_Nullable)dict blocking:(BOOL)blk; +-(BOOL) postDataItem:(id _Nullable )dataItem blocking:(BOOL)blk; +-(void) replaceRoutinesWithArray:(NSArray*_Nullable)procs; +-(void) setProgressRoutine:(ASFKProgressRoutine _Nullable )progress; +-(void) setSummary:(ASFKExecutableRoutineSummary _Nullable )sum; +-(void) setExpirationSummary:(ASFKExecutableRoutineSummary _Nullable )sum; -(eASFKThreadpoolExecutionStatus) select:(long)selector routineCancel:(ASFKCancellationRoutine)cancel; --(void) setCancellationHandler:(ASFKCancellationRoutine)cru; --(void) setExpirationCondition:(ASFKExpirationCondition*) trop; +-(void) setCancellationHandler:(ASFKCancellationRoutine _Nullable )cru; +-(void) setExpirationCondition:(ASFKExpirationCondition* _Nullable) trop; -(BOOL) hasSessionSummary; -(BOOL) isBusy; --(long) procsCount; --(long) itemsCount; +-(std::uint64_t) getRoutinesCount; +-(std::uint64_t) getDataItemsCount; -(void) _invokeCancellationHandler:(ASFKCancellationRoutine) cru identity:(id)identity; @end +#pragma mark - Global threadpool +@interface ASFKGlobalThreadpool : NSObject ++(ASFKGlobalThreadpool *)singleInstance ; + +-(std::uint64_t) runningSessionsCount; +-(std::uint64_t) pausedSessionsCount; +-(std::uint64_t) itemsCountForSession:(ASFK_IDENTITY_TYPE)sessionId; +-(std::uint64_t) totalSessionsCount; + +-(BOOL) postDataAsArray:(NSArray*)data forSession:(ASFK_IDENTITY_TYPE)sessionId blocking:(BOOL)blk; +-(BOOL) postDataAsOrderedSet:(NSOrderedSet*)set forSession:(ASFK_IDENTITY_TYPE)sessionId blocking:(BOOL)blk; +-(BOOL) postDataAsUnorderedSet:(NSSet*)data forSession:(ASFK_IDENTITY_TYPE)sessionId blocking:(BOOL)blk; +-(BOOL) postDataAsDictionary:(NSDictionary*)data forSession:(ASFK_IDENTITY_TYPE)sessionId blocking:(BOOL)blk; +-(BOOL) addSession:(ASFKThreadpoolSession*)aseq withId:(ASFK_IDENTITY_TYPE)identity; + +-(ASFKThreadpoolSession*) getThreadpoolSessionWithId:(ASFK_IDENTITY_TYPE)identity; +-(NSArray*) getThreadpoolSessionsList; +-(void) cancelSession:(ASFK_IDENTITY_TYPE)sessionId; +-(void) cancelAll; +-(BOOL) isBusySession:(ASFK_IDENTITY_TYPE)sessionId; + +-(BOOL) isPausedSession:(ASFK_IDENTITY_TYPE)sessionId; + +-(void) flushSession:(ASFK_IDENTITY_TYPE)sessionId; +-(void) flushAll; +-(void) pauseSession:(ASFK_IDENTITY_TYPE)sessionId; +-(void) pauseAll; +-(void) resumeSession:(ASFK_IDENTITY_TYPE)sessionId; +-(void) resumeAll; + +@end +#pragma mark - Container callbacks +typedef void(^ASFKMbNRunOnContainerReadRoutine)(id cId,NSDate* tstamp, NSArray* data); +/*! + @brief custom filter of incoming messages. + @discussion custom Routine that filters accepted messages. User can review all accepted messages and select some subset to be removed. After this call ended, the selected messages will be removed from collection. + @param cId group/mailbox ID. + @param msgs ordered set of accepted messages. + @param stop indication provided by user that filtering should be stopped. + @param lock reference to synchronization primitive. Must be used when the collection as accessed. + */ +typedef BOOL(^ASFKMbContainerFilteringRoutine)(id cId,NSOrderedSet* msgs, BOOL* stop, id lock); +typedef void(^ASFKMbNotifyOnContainerJoinRoutine)(id cId, id guestId); +typedef void(^ASFKMbNotifyOnContainerLeaveRoutine)(id cId, id guestId); +typedef void(^ASFKMbNotifyOnContainerDiscardRoutine)(id cId,NSDate* tstamp); +/*! + @brief notification on incoming messages. + @discussion custom Routine that notifies user about incoming message. + @param cId group/user ID. + @param newMsgCount up-to-date message count. + */ +typedef void(^ASFKMbNotifyOnNewMsgRoutine)(id cId, NSUInteger newMsgCount); +/*! + @brief notification on popped messages(s). + @discussion custom Routine that notifies user about popping message(s). + @param cId group/user ID. + @param popped array of popped messages. + @param remaining count of remaining messages. + */ +typedef void(^ASFKMbNotifyOnContainerPopRoutine)(id cId,NSArray* popped,NSUInteger remaining); +/*! + @brief notification on read messages(s). + @discussion custom Routine that notifies user about popping message(s). + @param cId group/user ID. + @param read array of popped messages. + @param remaining count of remaining messages. + */ +typedef void(^ASFKMbNotifyOnContainerReadRoutine)(id cId,NSArray* read,NSUInteger remaining); + +#pragma mark - Properties +@interface ASFKMBPropertiesNull:NSObject +@end +#pragma mark - Group Member Props +@interface ASFKMBGroupMemberProperties :NSObject +-(void) initFromProps:(ASFKMBGroupMemberProperties*)p; +/*! + @brief Indication that user should be prevented from reading messages delivered to group. YES for confirmation. + @discussion Is ignored when applied to owner of group. Explicit setting of this property will have no effect. + */ +@property (nonatomic) BOOL isBlinded; +/*! + @brief Indication that user should be prevented from delivering messages to group. YES for confirmation. + @discussion Is ignored when applied to owner of group. Explicit setting of this property will have no effect. + */ +@property (nonatomic) BOOL isMuted; + +/*! + @brief Date at which a Group Member will leave group automatically. Nil is ignored. + */ +//@property (nonatomic,readonly) NSDate* leaveOnDate; +/*! + @brief Group membership duration, greater than zero. After this period member will automatically leave the group. Negative value ignored. + */ +@property (nonatomic,readonly) ASFKConditionTemporal* grpMemLeaveTimer; +/*! + @brief set Group membership leaving date. Nil or date lesser than or equal to current time lead to invalidation of underlying properties. + @param date leaving date to set. + */ +-(void) setPropLeaveOnDate:(NSDate *)date; +/*! + @brief set Group membership duration, greater than zero. Negative/zero value leads to invalidation of underlying properties. + @param seconds time interval to set. + */ +-(void) setPropLeaveAfterSeconds:(NSTimeInterval)seconds; +/*! + @param date date to be tested against the 'leaveOnDate' property. + @return YES if 'date' is before 'leaveOnDate' property; NO otherwise. + */ +-(BOOL) passedLeavingDate:(NSDate *)date; +@end +#pragma mark - Group/Container Props +@interface ASFKMBContainerProperties :NSObject +-(void) initFromProps:(ASFKMBContainerProperties*)p; +@property ASFKMbNRunOnContainerReadRoutine runOnReadProc; +/*! + @brief Indication of whether addition of new members to a group is allowed. NO for permission. + @discussion When applied to standalone mailbox, no effect expected. + */ +@property BOOL isPrivate; +/*! + @brief Indication of whether this container permits blocking Read/Write operations. YES for permission. + @discussion When applied to standalone mailbox, no effect expected. + */ +@property BOOL blockingReadwriteAllowed; +/*! + @brief Indication of whether a standalone user can join another group. YES for permission. + @discussion When applied to a group, no effect expected. + */ +@property BOOL isInvitable; +/*! + @brief Indication that group container should not accept posts while is not populated; YES for confirmation. Is ignored for single user container. + */ +@property (nonatomic) BOOL noPostUnpopulatedGroup; +/*! + @brief defines if user list of some group may be used for operations like group cloning, sendToMembers operation or set operations. YES for no sharing, NO otherwise. + */ +@property (nonatomic) BOOL noUserListSharing; +/*! + @brief indication whether anonimous posting is allowed. YES for confirmation, NO otherwise. + @discussion anonymous is any message that is accompanied with author ID set to nil. + */ +@property (nonatomic) BOOL anonimousPostingAllowed; +@property (nonatomic) BOOL retractionAllowed; +/*! + @brief Container Deletion Timer. If set, provides that the container will be deleted upon expiration. + */ +@property (nonatomic,readonly) ASFKConditionTemporal* containerDeleteTimer; +/*! + @brief Container Kickout Timer. If set, provides that any user, except the owner will be removed from the container upon timer expiration. + */ +@property (nonatomic,readonly) ASFKConditionTemporal* containerKickoutTimer; +/*! + @brief Container Drop Message Timer. If set, provides that messages older than established delay will be removed from the container. + */ +@property (nonatomic,readonly) ASFKConditionTemporal* containerDropMsgTimer; +@property ASFKMbContainerFilteringRoutine containerFilterProc; +@property ASFKMbNotifyOnContainerDiscardRoutine onDiscardProc; +@property ASFKMbNotifyOnNewMsgRoutine onNewMsgProc; +@property ASFKMbNotifyOnContainerPopRoutine onPopProc; +@property ASFKMbNotifyOnContainerReadRoutine onReadProc; +@property ASFKMbNotifyOnContainerJoinRoutine onJoinProc; +@property ASFKMbNotifyOnContainerLeaveRoutine onLeaveProc; + +-(void) setPropMsgCustomCondition:(ASFKCondition*)msgCustomCond; +/*! + @brief set User/Group deletion date. Nil or date lesser than or equal to current time lead to invalidation of underlying properties Nil means that deletion will not happen. + @param date termination date to set. + */ +-(void) setPropDeleteOnDate:(NSDate *)date; +-(void) setPropDropMsgOnDate:(NSDate *)date; +-(void) setPropKickoutOnDate:(NSDate *)date; +/*! + @brief User/Group lifetime, greater than zero. After this period it will be automatically destroyed. Negative value will invalidate underlying properties, deletion will not happen. + @param seconds time left to termination. + */ +-(void) setPropDeleteAfterSeconds:(NSTimeInterval)seconds; +/*! + @brief Group member's lifetime, greater than zero. After this period it will be automatically removed from group. Negative value will invalidate underlying properties, kickout will not happen. + @param seconds time left to termination. + */ +-(void) setPropKickoutAfterSeconds:(NSTimeInterval)seconds; +/*! + @brief Delivered message's lifetime, greater than zero. After this period it will be automatically destroyed. Negative value will invalidate underlying properties, kickout will not happen. + @param seconds time left to termination. + */ +-(void) setPropDropMsgAfterSeconds:(NSTimeInterval)seconds; +/*! + @param date date to be tested against the 'deleteOnDate' property. + @return YES if 'date' is before 'deleteOnDate' property; NO otherwise. + */ +-(BOOL) passedDeletionDate:(NSDate *)date; +-(BOOL) passedKickoutDate:(NSDate *)date; +-(BOOL) passedDropMsgDate:(NSDate *)date; +@end +#pragma mark - Message Props +@interface ASFKMBMsgProperties:NSObject{ + /*! + @brief maximum number of reading attempts. Decreases on each attempt. When value is zero, the message will not be available for reading, and deleted. By default set to positive maximum. + */ +@public std::atomic maxAccessLimit; +} +-(void) initFromProps:(ASFKMBMsgProperties*)p; +@property BOOL blocking; +/*! + @brief Date at which a Message will be destroyed automatically. Nil is ignored. + @discussion if in container exists ASFKMBContainerProperties object and it defines deletion date for messages, then the earliest date will be picked. + */ +@property (nonatomic,readonly) ASFKConditionTemporal* msgDeletionTimer; +/*! + @brief When applied to message, indicates that it may be retracted from Group/User before the specified date only. Nil date is ignored. + */ +@property (nonatomic,readonly) ASFKConditionTemporal* msgRetractionTimer; +/*! + @brief When applied to message, indicates that it may be read from Group/User after the specified date only. Nil date is ignored. + */ +@property (nonatomic,readonly) ASFKConditionTemporal* msgReadabilityTimer; + +/*! + @brief user id of message poster. Nil is interpreted as anonimous posting. + */ +@property (nonatomic,readonly) id msgAuthorId; +/*! + @brief unique id of message. Nil is ignored. + */ +@property (nonatomic,readonly) NSUUID* msgId; +/*! + @param date date to be tested. + @return YES if 'date' is earlier than setting of 'msgRetractionTimer' property; NO otherwise. + */ +-(BOOL) passedRetractionDate:(NSDate *)date; +/*! + @param date date to be tested.. + @return YES if 'date' is earlier than setting of 'msgReadabilityTimer' property; NO otherwise. + */ +-(BOOL) passedReadingDate:(NSDate *)date; +/*! + @param date date to be tested. + @return YES if 'date' is earlier than setting of 'msgDeletionTimer' property; NO otherwise. + */ +-(BOOL) passedDeletionDate:(NSDate *)date; +/*! + @brief set message deletion date. After this period it will be automatically destroyed. Nil value will invalidate underlying properties. + @param date date when message must be terminated, if not read. + */ +-(void) setPropDeleteOnDate:(NSDate *)date; +/*! + @brief set message termination date. Message can be read only before that date passed. + @param seconds delay before message's termination. + */ +-(void) setPropDeleteAfterSeconds:(NSTimeInterval)seconds; +/*! + @brief set message reading date. Message can be read only after that date passed. + @param date date when message would be available for reading. + */ +-(void) setPropReadOnDate:(NSDate *)date; +/*! + @brief set message reading delay. Message can be read only after that delay elapsed. + @param seconds delay before the message would be available for reading. + */ +-(void) setPropReadAfterSeconds:(NSTimeInterval)seconds; +/*! + @brief set time period, during which message may be retracted. + @param msgRetractInSeconds time left to retraction, unless popped. + */ +-(void) setPropMsgRetractInSeconds:(NSTimeInterval)msgRetractInSeconds; +/*! + @brief set date, until which the message could be retracted. + @param msgRetractBeforeDate last date of retraction, unless deleted in other way. + */ +-(void) setPropMsgRetractBeforeDate:(NSDate *)msgRetractBeforeDate; +/*! + @brief set maximum number of reading attempts. + @param limit number of times the message can be accessed. + */ +-(void) setPropMsgMaxReadLimit:(NSUInteger)limit; +/*! + @brief set message's identifier. + @param msgId identifier. + */ +-(void) setPropMsgId:(NSUUID *)msgId; +/*! + @brief set identifier of message's issuer. + @param msgAuthorId issuer's identifier. + */ +-(void) setPropMsgAuthorId:(id)msgAuthorId; +@end + +typedef void(^ASFKMbCallReleaseRoutine)(); -#import "ASFKFilter.h" -#import "ASFKFilteringQueue.h" +#pragma mark - Mailboxes #import "ASFKMailbox.h" -#import "ASFKPipelinePar.h" +#pragma mark - Pipelines +//#import "ASFKPipelinePar.h" +@interface ASFKPipelineSession : ASFKThreadpoolSession +@end +/*! + @see ASFKLinearFlow + @brief This class provides pipelined execution's functionality. For N Routines it takes Routine P0 and applies it to item D0. Upon completion P0 is applied to D1 while P1 is concurrently applied to D0 and so on. + */ +@interface ASFKPipelinePar : ASFKSessionalFlow +-(std::uint64_t) itemsCountForSession:(_Null_unspecified id)sessionId; +-(std::uint64_t) totalSessionsCount; + +-(BOOL) isPausedSession:(_Null_unspecified ASFK_IDENTITY_TYPE)sessionId; +/*! + @brief Equals YES if session with given identity exists AND is still processing data batch ; NO otherwise. + */ +-(BOOL) isBusySession:(_Null_unspecified ASFK_IDENTITY_TYPE)sessionId; + +-(std::uint64_t) getRunningSessionsCount; +-(std::uint64_t) getPausedSessionsCount; + +/*! + @brief Cancels ALL sessions created by this instance. + */ +-(void)cancelAll; +/*! + @brief Cancels session with given id. + */ +-(void)cancelSession:(_Null_unspecified ASFK_IDENTITY_TYPE)sessionId; +/*! + @brief flushes all queued items for all sessions created by this instance. + */ +-(void)flushAll; +/*! + @brief flushes all queued items for given session ID. + */ +-(void)flushSession:(_Null_unspecified ASFK_IDENTITY_TYPE)sessionId; + +/*! + @brief flushes all queued items for all sessions created by this instance. + */ +-(void)pauseAll; +/*! + @brief flushes all queued items for given session ID. + */ +-(void)pauseSession:(_Null_unspecified ASFK_IDENTITY_TYPE)sessionId; + +/*! + @brief flushes all queued items for all sessions created by this instance. + */ +-(void)resumeAll; +/*! + @brief flushes all queued items for given session ID. + */ +-(void)resumeSession:(_Null_unspecified ASFK_IDENTITY_TYPE)sessionId; + +/*! + @brief sets new class of QoS (i.e. thread priority). + @param newqos required class of Quality of Service . Allowed values are:QOS_CLASS_USER_INTERACTIVE, QOS_CLASS_UTILITY, QOS_CLASS_BACKGROUND. By default QOS_CLASS_BACKGROUND is set. The parameter will be in effect after restart. + */ +-(void) setQualityOfService:(long)newqos; + +/*! + @brief returns list of session ID's for all sessions created by this instance. + @return Array of session ID's. + */ +-(NSArray* _Null_unspecified) getSessions; +/*! + @brief creates new non-expiring session associated with this instance. + @param exparams collection of session properties. May be nil; in that case default parameters will be adopted. + @param sid optional name of session. If nil, then random value will be assigned. + @return Dictionary of return values. + */ +-(NSDictionary* _Nonnull) createSession:(ASFKSessionConfigParams*_Nullable) exparams sessionId:(id _Nullable ) sid; + +@end diff --git a/src/ASFKBase.mm b/src/ASFKBase.mm index ecb172c..2b6c43c 100644 --- a/src/ASFKBase.mm +++ b/src/ASFKBase.mm @@ -12,7 +12,8 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 15/02/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase.h" @@ -21,6 +22,70 @@ #include #import "ASFKQueue+Internal.h" +@implementation ASFKPriv_EndingTerm ++ (ASFKPriv_EndingTerm *)singleInstance { + static ASFKPriv_EndingTerm *singleInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + singleInstance = [[self alloc] init]; + }); + return singleInstance; +} +@end + +@implementation ASFKReturnInfo{ + +} +-(id) init{ + self=[super init]; + if(self){ + totalSessionTime=0; + totalProcsTime=0; + totalProcsCount=0; + totalSessionsCount=0; + returnCodeSuccessful=NO; + returnCodeDescription=@""; + returnResult=nil; + returnStatsProcsElapsedSec=0; + returnStatsSessionElapsedSec=0; + returnSessionId=nil; + } + return self; +} +@end + +@implementation ASFKConfigParams +-(id) init{ + self = [super init]; + if(self) { + retInfo=nil; + } + return self; +} +-(void) setupReturnInfo{ + if(retInfo==nil){ + retInfo=[ASFKReturnInfo new]; + } +} +@end + +@implementation ASFKSessionConfigParams +-(id) init{ + self = [super init]; + if(self) { + progressProc=nil; + summaryRoutine=nil; + procs=nil; + cancellationProc=nil; + expCondition=nil; + onPauseProc=nil; + blockCallMode=ASFK_BC_NO_BLOCK; + } + return self; +} + +@end + @implementation ASFKExecutionParams{ } @@ -33,35 +98,43 @@ -(id) init{ cancellationProc=nil; expCondition=nil; onPauseProc=nil; + preBlock=nil; } return self; } +-(void) setupReturnInfo{ + if(retInfo==nil){ + retInfo=[ASFKReturnInfo new]; + } +} @end @implementation ASFKThreadpoolSession{ std::atomic cancelled; + std::vector vectorTermPos; } -(id)init{ self=[super init]; if(self){ - [self _TPSinitWithSession:nil andSubsession:nil]; + [self _TPSinitWithSession:nil andSubsession:nil blkMode:ASFK_BC_NO_BLOCK]; } return self; } --(id)initWithSessionId:(ASFK_IDENTITY_TYPE)sessionId andSubsessionId:(ASFK_IDENTITY_TYPE)subId{ +-(id)initWithSessionId:(ASFK_IDENTITY_TYPE)sessionId andSubsessionId:(ASFK_IDENTITY_TYPE)subId blkMode:(eASFKBlockingCallMode)blkMode{ self=[super init]; if(self){ - [self _TPSinitWithSession:sessionId andSubsession:subId]; + [self _TPSinitWithSession:sessionId andSubsession:subId blkMode:blkMode]; } return self; } --(void)_TPSinitWithSession:(ASFK_IDENTITY_TYPE)sessionId andSubsession:(ASFK_IDENTITY_TYPE)subId{ +-(void)_TPSinitWithSession:(ASFK_IDENTITY_TYPE)sessionId andSubsession:(ASFK_IDENTITY_TYPE)subId blkMode:(eASFKBlockingCallMode)blkMode{ procs=[NSMutableArray array]; excond=[[ASFKExpirationCondition alloc]init]; isStopped=NO; paused=NO; onPauseNotification=nil; + callMode=blkMode; if(sessionId){ cblk= [self newSession:sessionId andSubsession:subId]; }else{ @@ -102,13 +175,13 @@ @implementation ASFKGlobalQueue{ NSLock* lock; } #pragma mark Singleton Methods -+ (ASFKGlobalQueue *)sharedManager { - static ASFKGlobalQueue *sharedManager = nil; ++ (ASFKGlobalQueue *)singleInstance { + static ASFKGlobalQueue *singleInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - sharedManager = [[self alloc] init]; + singleInstance = [[self alloc] init]; }); - return sharedManager; + return singleInstance; } - (id)init { @@ -210,7 +283,7 @@ -(NSDictionary*)getStatistics{ -(void)cancelAll{ [lkNonLocal lock]; [ctrlblocks enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { - ASFKControlBlock* cb = (ASFKControlBlock*)obj; + ASFKControlBlock* cb = (ASFKControlBlock*)obj;// [ctrlblocks objectForKey:key]; if(cb){ [cb cancel]; }else{ diff --git a/src/ASFKBatchingQueue.mm b/src/ASFKBatchingQueue.mm new file mode 100644 index 0000000..61f50b7 --- /dev/null +++ b/src/ASFKBatchingQueue.mm @@ -0,0 +1,905 @@ +/* + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ +// Copyright © 2019-2023 Boris Vigman. All rights reserved. +// + +#import "ASFKBase.h" +#import "ASFKQueue+Internal.h" +#import + +@implementation ASFKPriv_WrapBQ{ + +} +-(id) init{ + self=[super init]; + if(self){ + writecond=nil; + wcPred=NO; + many = [NSMutableArray new]; + } + return self; +} +@end + +@implementation ASFKBatchingQueue{ + NSCondition* readcond; + ASFKPriv_WrapBQ* tempWBQ; + std::atomic condPredR; +} +-(id)init{ + self=[super init]; + if(self){ + [self _initBQ]; + } + return self; +} +-(id)initWithName:(NSString*)name{ + self=[super initWithName:name blocking:NO]; + if(self){ + [self _initBQ]; + } + return self; +} +-(id)initWithName:(NSString*)name blocking:(BOOL)blk{ + self=[super initWithName:name blocking:blk]; + if(self){ + [self _initBQ]; + } + return self; +} +-(void) _initBQ{ + q=[NSMutableArray array]; + lock=[NSLock new]; + paused=NO; + netCount=0; + condPredR=NO; + tempWBQ=[ASFKPriv_WrapBQ new]; + batchLimitUpper=std::numeric_limits::max(); + batchLimitLower=std::numeric_limits::min(); + if(blocking){ + readcond=[NSCondition new]; + } +} +-(void)reset{ + [self purge]; + batchLimitUpper=std::numeric_limits::max(); + batchLimitLower=std::numeric_limits::min(); + paused=NO; + netCount=0; + condPredR=NO; + tempWBQ=nil; + tempWBQ=[ASFKPriv_WrapBQ new]; +} +-(void) purge{ + [lock lock]; + if(blocking){ + [q enumerateObjectsWithOptions:(NSEnumerationConcurrent) usingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + if(((ASFKPriv_WrapBQ*)obj)->writecond){ + [((ASFKPriv_WrapBQ*)obj)->writecond lock]; + ((ASFKPriv_WrapBQ*)obj)->wcPred=YES; + [((ASFKPriv_WrapBQ*)obj)->writecond broadcast]; + [((ASFKPriv_WrapBQ*)obj)->writecond unlock]; + } + }]; + } + [q removeAllObjects]; + netCount=0; + condPredR=NO; + [lock unlock];; +} +-(BOOL) setMaxQSize:(NSUInteger)size{ + WASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) setMinQSize:(NSUInteger)size{ + WASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) setUpperBatchLimit:(std::uint64_t)limit{ + BOOL r=YES; + if(limit < batchLimitLower.load()){ + r=NO; + WASFKLog(@"new upper limit is not greater than lower limit"); + } + batchLimitUpper=limit; + return r; + +} +-(BOOL) setLowerBatchLimit:(std::uint64_t)limit{ + BOOL r=YES; + if(limit > batchLimitUpper.load()){ + r=NO; + WASFKLog(@"new lower limit is not less than upper limit"); + } + batchLimitLower=limit; + return r; +} + +-(BOOL) castArrayToBatch:(NSArray*) ar{ + BOOL tval=NO; + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return tval; +} +-(BOOL) castUnorderedSetToBatch:(NSSet*) set { + BOOL tval=NO; + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return tval; +} +-(BOOL) castOrderedSetToBatch:(NSOrderedSet*) set { + BOOL tval=NO; + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return tval; +} +-(BOOL) castDictionaryToBatch:(NSDictionary*) dict { + BOOL tval=NO; + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + + return tval; +} +-(BOOL) castObjectToBatch:(id) obj{ + BOOL tval=NO; + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return tval; +} +-(BOOL) commitBatch:(BOOL) force{ + BOOL res=NO; + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return res; +} +-(BOOL) resetBatch{ + BOOL res=NO; + [lock lock]; + + if(tempWBQ && [tempWBQ->many count]>0){ + [tempWBQ->many removeAllObjects]; + res=YES; + } + [lock unlock]; + return res; +} +#pragma mark - content replacement +-(void) queueFromBatchingQueue:(ASFKBatchingQueue*)otherq{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); +} +-(void) queueFromQueue:(ASFKQueue*)otherq{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); +} +-(void) queueFromArray:(NSArray*)array{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); +} +-(void) queueFromOrderedSet:(NSOrderedSet*)set{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); +} +-(void) queueFromUnorderedSet:(NSSet*)set{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); +} +-(void) queueFromDictionary:(NSDictionary*)dict{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); +} +#pragma mark - Prepending (disabled) +-(BOOL) prependFromQueue:(ASFKQueue*)otherq{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) prependFromArray:(NSArray*)array{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) prependFromOrderedSet:(NSOrderedSet*)set{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) prependFromUnorderedSet:(NSSet*)set{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) prependFromDictionary:(NSDictionary*)dict{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} + +#pragma mark - Non-blocking interface +-(BOOL) castQueue:(ASFKQueue*)otherq{ + if(otherq){ + ASFKPriv_WrapBQ* filler=[ASFKPriv_WrapBQ new]; + [lock lock]; + [otherq begin]; + NSArray* d=[otherq getData]; + [d enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + if(NO==[obj isKindOfClass:[ASFKPriv_WrapBQ class]]){ + [q addObject:obj]; + } + }]; + [otherq commit]; + [q addObject:filler]; + netCount=[q count]; + [lock unlock]; + return YES; + } + return NO; +} +-(BOOL)castObject:(id)item exParams:(ASFKExecutionParams *)ex{ + if(item){ + if(batchLimitUpper.load()<1 || batchLimitLower.load()>1){ + WASFKLog(ASFK_STR_Q_ULIMIT_VIOLATION); + return NO; + } + ASFKPriv_WrapBQ* wrap=[ASFKPriv_WrapBQ new]; + [wrap->many addObject:item]; + [lock lock]; + [q addObject:wrap]; + netCount.fetch_add(1); + [lock unlock]; + if(blocking){ + wrap->writecond=[NSCondition new]; + [readcond lock]; + condPredR=YES; + [readcond broadcast]; + [readcond unlock]; + } + + return YES; + } + return NO; +} +-(BOOL) castArray:(NSArray*)array exParams:(ASFKExecutionParams *)ex{ + if(array && [array count]>0 ){ + if(batchLimitUpper.load() < [array count] || batchLimitLower.load()>[array count]){ + WASFKLog(ASFK_STR_Q_ULIMIT_VIOLATION); + return NO; + } + ASFKPriv_WrapBQ* wrap=[ASFKPriv_WrapBQ new]; + [wrap->many addObjectsFromArray:array]; + [lock lock]; + [q addObject:wrap]; + netCount.fetch_add([wrap->many count]); + [lock unlock]; + if(blocking){ + wrap->writecond=[NSCondition new]; + [readcond lock]; + condPredR=YES; + [readcond broadcast]; + [readcond unlock]; + } + + return YES; + } + return NO; +} +-(BOOL) castDictionary:(NSDictionary*)dict exParams:(ASFKExecutionParams *)ex{ + if(dict && [dict count]>0){ + if(batchLimitUpper.load()<[dict count] || batchLimitLower.load()>[dict count]){ + WASFKLog(ASFK_STR_Q_ULIMIT_VIOLATION); + return NO; + } + ASFKPriv_WrapBQ* wrap=[ASFKPriv_WrapBQ new]; + [wrap->many addObjectsFromArray:[dict allValues]]; + [lock lock]; + [q addObject:wrap]; + netCount.fetch_add([dict count]); + [lock unlock]; + if(blocking){ + wrap->writecond=[NSCondition new]; + [readcond lock]; + condPredR=YES; + [readcond broadcast]; + [readcond unlock]; + } + + return YES; + } + return NO; +} +-(BOOL) castOrderedSet:(NSOrderedSet*)set exParams:(ASFKExecutionParams *)ex{ + if(set && [set count]>0){ + if(batchLimitUpper.load()<[set count] || batchLimitLower.load()>[set count]){ + WASFKLog(ASFK_STR_Q_ULIMIT_VIOLATION); + return NO; + } + ASFKPriv_WrapBQ* wrap=[ASFKPriv_WrapBQ new]; + [wrap->many addObjectsFromArray:[set array]]; + [lock lock]; + [q addObject:wrap]; + netCount.fetch_add([set count]); + [lock unlock]; + if(blocking){ + wrap->writecond=[NSCondition new]; + [readcond lock]; + condPredR=YES; + [readcond broadcast]; + [readcond unlock]; + } + + return YES; + } + return NO; +} +-(BOOL) castUnorderedSet:(NSSet*)set exParams:(ASFKExecutionParams *)ex{ + if(set && [set count]>0){ + if(batchLimitUpper.load()<[set count] || batchLimitLower.load()>[set count]){ + WASFKLog(ASFK_STR_Q_ULIMIT_VIOLATION); + return NO; + } + ASFKPriv_WrapBQ* wrap=[ASFKPriv_WrapBQ new]; + [wrap->many addObjectsFromArray:[set allObjects]]; + [lock lock]; + [q addObject:wrap]; + netCount.fetch_add([set count]); + [lock unlock]; + if(blocking){ + wrap->writecond=[NSCondition new]; + [readcond lock]; + condPredR=YES; + [readcond broadcast]; + [readcond unlock]; + } + + return YES; + } + return NO; +} + +#pragma mark - Blocking interface +-(BOOL) callQueue:(ASFKQueue*)otherq{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return NO; +} +-(BOOL) callArray:(NSArray*)array exParams:(ASFKExecutionParams*) params{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return NO; +} +-(BOOL) callDictionary:(NSDictionary*)dict exParams:(ASFKExecutionParams *)params{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return NO; +} +-(BOOL) callOrderedSet:(NSOrderedSet*)set exParams:(ASFKExecutionParams *)params{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + + return NO; +} +-(BOOL) callUnorderedSet:(NSSet*)set exParams:(ASFKExecutionParams *)params{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return NO; +} +-(BOOL) callObject:(id _Nullable)item exParams:(ASFKExecutionParams * _Nullable)params{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return NO; +} +#pragma mark - querying +-(BOOL) isEmpty{ + [lock lock]; + BOOL e=netCount.load()>0?NO:YES; + [lock unlock]; + return e; +} +-(NSUInteger )count{ + return netCount.load(); +} +-(NSUInteger) batchCount{ + [lock lock]; + NSUInteger qc=[q count]; + [lock unlock]; + return qc; +} +-(NSUInteger) candidateCount{ + NSUInteger csize=0; + [lock lock]; + csize=[tempWBQ->many count]; + [lock unlock]; + return csize; +} +-(NSArray* _Nullable ) pullBatchAsArray{ + if(paused){ + return nil; + } + if(blocking){ + [self->readcond lock]; + //if(paused==NO){ + [lock lock]; + condPredR=[q count]>0?YES:NO; + [lock unlock]; + while (condPredR==NO) { + [self->readcond wait]; + } + //} + [self->readcond unlock]; + } + + id subitem=nil; + //if(paused==NO){ + [lock lock]; + id item=[q firstObject]; + if(item){ + subitem=((ASFKPriv_WrapBQ*)item)->many ; + if(subitem){ + if(blocking && ((ASFKPriv_WrapBQ*)item)->writecond){ + [((ASFKPriv_WrapBQ*)item)->writecond lock]; + ((ASFKPriv_WrapBQ*)item)->wcPred=YES; + [((ASFKPriv_WrapBQ*)item)->writecond broadcast]; + [((ASFKPriv_WrapBQ*)item)->writecond unlock]; + } + netCount.fetch_sub([((ASFKPriv_WrapBQ*)item)->many count]); + [q removeObjectAtIndex:0]; + } + } + else{ + + } + [lock unlock];; + return subitem; +// } +// else{ +// +// } + +// return nil; +} +-(id) pull{ + if(paused){ + return nil; + } + if(blocking){ + [self->readcond lock]; + [lock lock]; + condPredR=[q count]>0?YES:NO; + [lock unlock]; + while (condPredR==NO) { + [self->readcond wait]; + } + [self->readcond unlock]; + } + + id subitem=nil; + [lock lock]; + id item=[q firstObject]; + if(item){ + subitem=[((ASFKPriv_WrapBQ*)item)->many firstObject]; + if(subitem){ + [((ASFKPriv_WrapBQ*)item)->many removeObjectAtIndex:0]; + netCount.fetch_sub(1); + if([((ASFKPriv_WrapBQ*)item)->many count]==0){ + [q removeObjectAtIndex:0]; + if(blocking && ((ASFKPriv_WrapBQ*)item)->writecond){ + [((ASFKPriv_WrapBQ*)item)->writecond lock]; + ((ASFKPriv_WrapBQ*)item)->wcPred=YES; + [((ASFKPriv_WrapBQ*)item)->writecond broadcast]; + [((ASFKPriv_WrapBQ*)item)->writecond unlock]; + } + + } + } + else{ + + } + } + + [lock unlock];; + return subitem; +} + +@end +#pragma mark - Private +/*! + This class is for private use. + */ +@implementation ASFKBatchingQueue2 +{ + +} +-(id) initWithName:(NSString *)name{ + self=[super initWithName:name]; + if(self){ + [self _initBQ2]; + } + return self; +} +-(id) init{ + self=[super init]; + if(self){ + [self _initBQ2]; + } + return self; +} +-(id) initWithName:(NSString*) name blocking:(BOOL)blk{ + self=[super initWithName:name blocking:blk]; + if(self){ + [self _initBQ2]; + blocking=blk; + } + return self; +} +-(void) _initBQ2{ + deferred=[NSMutableArray new]; +} + +-(id) pullAndBatchStatus:(NSInteger&)itemsLeft endBatch:(BOOL&)endBatch term:(ASFKPriv_EndingTerm**)term{ + id subitem=nil; + *term=nil; + endBatch=NO; +// if(paused.load()==NO){ +// +// } +// else{ +// //Paused +// +// } + [lock lock]; + if([deferred count]>0){ + subitem=nil; + } + else + { + id item=[q firstObject]; + if(item){ + subitem=[((ASFKPriv_WrapBQ*)item)->many firstObject]; + if(subitem){ + [((ASFKPriv_WrapBQ*)item)->many removeObjectAtIndex:0]; + netCount.fetch_sub(1); + if([((ASFKPriv_WrapBQ*)item)->many count]==0){ + [q removeObjectAtIndex:0]; + *term=[ASFKPriv_EndingTerm singleInstance]; + endBatch=YES; + if(((ASFKPriv_WrapBQ*)item)->writecond){ + [deferred addObject:(item)]; + } + } + } + } + } + + [lock unlock]; + return subitem; +} +-(BOOL) castObject:(id)item exParams:(ASFKExecutionParams *)ex{ + if(item){ + ASFKPriv_WrapBQ* wrap=[ASFKPriv_WrapBQ new]; + //wrap->single=item; + [wrap->many addObject:item]; + [lock lock]; + [q addObject:wrap]; + netCount.fetch_add(1); + [lock unlock]; + return YES; + } + return NO; +} +-(BOOL) castArray:(NSArray*)array exParams:(ASFKExecutionParams *)ex{ + if(array && [array count]>0){ + ASFKPriv_WrapBQ* wrap=[ASFKPriv_WrapBQ new]; + + [wrap->many addObjectsFromArray:array]; + [lock lock]; + [q addObject:wrap]; + netCount.fetch_add([wrap->many count]); + [lock unlock]; + + return YES; + } + return NO; +} +-(BOOL) castArray:(NSArray*)array groupBy:(NSUInteger) grpSize exParams:(ASFKExecutionParams*)ex{ + return NO; +} +-(BOOL) castArray:(NSArray*)array splitTo:(NSUInteger) numOfChunks exParams:(ASFKExecutionParams*)ex{ + return NO; +} +-(BOOL) castDictionary:(NSDictionary*)dict exParams:(ASFKExecutionParams *)ex{ + if(dict && [dict count]>0){ + ASFKPriv_WrapBQ* wrap=[ASFKPriv_WrapBQ new]; +// NSMutableArray* ma=[NSMutableArray array]; +// [ma addObjectsFromArray:[dict allValues]]; + + [wrap->many addObjectsFromArray:[dict allValues]]; + [lock lock]; + [q addObject:wrap]; + netCount.fetch_add([wrap->many count]); + [lock unlock]; + + return YES; + } + return NO; +} +-(BOOL) castOrderedSet:(NSOrderedSet*)set exParams:(ASFKExecutionParams *)ex{ + if(set && [set count]>0){ + ASFKPriv_WrapBQ* wrap=[ASFKPriv_WrapBQ new]; + + [wrap->many addObjectsFromArray:[set array]]; + [lock lock]; + [q addObject:wrap]; + netCount.fetch_add([set count]); + [lock unlock]; + + return YES; + } + return NO; +} +-(BOOL) castUnorderedSet:(NSSet*)set exParams:(ASFKExecutionParams *)ex{ + if(set && [set count]>0){ + ASFKPriv_WrapBQ* wrap=[ASFKPriv_WrapBQ new]; + + [wrap->many addObjectsFromArray:[set allObjects]]; + [lock lock]; + [q addObject:wrap]; + netCount.fetch_add([wrap->many count]); + [lock unlock]; + + return YES; + } + return NO; +} + +#pragma mark - Blocking interface +-(BOOL) callQueue:(ASFKQueue*)otherq{ + if(otherq){ + [lock lock]; + [otherq begin]; + NSArray* d=[otherq getData]; + [q addObjectsFromArray:d]; + [otherq commit]; + [lock unlock]; + return YES; + } + return NO; +} +-(BOOL) callArray:(NSArray*)array exParams:(ASFKExecutionParams*) params{ + if(blocking){ + if(array && [array count]>0){ + ASFKPriv_WrapBQ* wrap=[ASFKPriv_WrapBQ new]; + if(blocking){ + wrap->writecond=[NSCondition new]; + } + [wrap->many addObjectsFromArray:array]; + [lock lock]; + [q addObject:wrap]; + netCount.fetch_add([wrap->many count]); + [lock unlock]; + + [wrap->writecond lock]; + if(params){ + params->preBlock(); + } + while(!wrap->wcPred){ + [wrap->writecond wait]; + } + [wrap->writecond unlock]; + return YES; + } + + } + else{ + return [self castArray:array exParams:params]; + } + return NO; +} +-(BOOL) callDictionary:(NSDictionary*)dict exParams:(ASFKExecutionParams *)params{ + if(blocking){ + if(dict && [dict count]>0){ + ASFKPriv_WrapBQ* wrap=[ASFKPriv_WrapBQ new]; + if(blocking){ + wrap->writecond=[NSCondition new]; + } + [wrap->many addObjectsFromArray:[dict allValues]]; + [lock lock]; + [q addObject:wrap]; + netCount.fetch_add([wrap->many count]); + [lock unlock]; + + + [wrap->writecond lock]; + if(params){ + params->preBlock(); + } + while(!wrap->wcPred){ + [wrap->writecond wait]; + } + [wrap->writecond unlock]; + + return YES; + } + + } + else{ + return [self callDictionary:dict exParams:params]; + } + return NO; +} +-(BOOL) callOrderedSet:(NSOrderedSet*)set exParams:(ASFKExecutionParams *)params{ + if(blocking){ + if(set && [set count]>0){ + ASFKPriv_WrapBQ* wrap=[ASFKPriv_WrapBQ new]; + if(blocking){ + wrap->writecond=[NSCondition new]; + } + [wrap->many addObjectsFromArray:[set array]]; + [lock lock]; + [q addObject:wrap]; + netCount.fetch_add([wrap->many count]); + [lock unlock]; + + + [wrap->writecond lock]; + if(params){ + params->preBlock(); + } + while(!wrap->wcPred){ + [wrap->writecond wait]; + } + [wrap->writecond unlock]; + return YES; + } + } + else{ + return [self castOrderedSet:set exParams:params]; + } + return NO; +} +-(BOOL) callUnorderedSet:(NSSet*)set exParams:(ASFKExecutionParams *)params{ + if(blocking){ + if(set && [set count]>0){ + ASFKPriv_WrapBQ* wrap=[ASFKPriv_WrapBQ new]; + if(blocking){ + wrap->writecond=[NSCondition new]; + } + [wrap->many addObjectsFromArray:[set allObjects]]; + [lock lock]; + [q addObject:wrap]; + netCount.fetch_add([wrap->many count]); + [lock unlock]; + + [wrap->writecond lock]; + if(params){ + params->preBlock(); + } + while(!wrap->wcPred){ + [wrap->writecond wait]; + } + [wrap->writecond unlock]; + return YES; + } + } + else{ + return [self castUnorderedSet:set exParams:params]; + } + + return NO; +} +-(BOOL) callObject:(id)item exParams:(ASFKExecutionParams *)params{ + if(blocking){ + if(item){ + ASFKPriv_WrapBQ* wrap=[ASFKPriv_WrapBQ new]; + if(blocking){ + wrap->writecond=[NSCondition new]; + } + [wrap->many addObject:item]; + [lock lock]; + [q addObject:wrap]; + netCount.fetch_add(1); + [lock unlock]; + + [wrap->writecond lock]; + if(params){ + params->preBlock(); + } + [wrap->writecond wait]; + [wrap->writecond unlock]; + return YES; + } + } + else{ + return [self castObject:item exParams:params]; + } + return NO; +} +-(void) releaseFirst{ + [lock lock]; + + if([deferred count]>0){ + ASFKPriv_WrapBQ* wrap = [deferred objectAtIndex:0]; + + [wrap->writecond lock]; + wrap->wcPred=YES; + [wrap->writecond broadcast]; + [wrap->writecond unlock]; + [deferred removeObjectAtIndex:0]; + } + [lock unlock]; +} +-(void) releaseAll{ + [lock lock]; + [deferred enumerateObjectsWithOptions:(NSEnumerationConcurrent) usingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + [((ASFKPriv_WrapBQ*)obj)->writecond lock]; + ((ASFKPriv_WrapBQ*)obj)->wcPred=YES; + [((ASFKPriv_WrapBQ*)obj)->writecond broadcast]; + [((ASFKPriv_WrapBQ*)obj)->writecond unlock]; + }]; + [deferred removeAllObjects]; + [lock unlock]; +} + +@end +/*For internal use*/ +@implementation ASFKBatchingQueue3 +{ + +} +-(id) initWithName:(NSString *)name{ + self=[super initWithName:name]; + if(self){ + [self _initBQ3]; + } + return self; +} +-(id) init{ + self=[super init]; + if(self){ + [self _initBQ3]; + } + return self; +} +-(void) _initBQ3{ + +} + +-(void) releaseFirst{ + [lock lock]; + + if([deferred count]>0){ + ASFKPriv_WrapBQ* wrap = [deferred objectAtIndex:0]; + [wrap->writecond lock]; + wrap->wcPred=YES; + [wrap->writecond broadcast]; + [wrap->writecond unlock]; + [deferred removeObjectAtIndex:0]; + } + [lock unlock]; +} + +-(id) pullAndBatchStatus:(NSInteger&)itemsLeft endBatch:(BOOL&)endBatch term:(ASFKPriv_EndingTerm**)term{ + id subitem=nil; + endBatch=NO; +// if(paused.load()==NO){ +// +// } +// else{ +// //Paused +// +// } + [lock lock]; + { + id item=[q firstObject]; + if(item){ + subitem=[((ASFKPriv_WrapBQ*)item)->many firstObject]; + if(subitem){ + [((ASFKPriv_WrapBQ*)item)->many removeObjectAtIndex:0]; + netCount.fetch_sub(1); + if([((ASFKPriv_WrapBQ*)item)->many count]==0){ + [q removeObjectAtIndex:0]; + *term=[ASFKPriv_EndingTerm singleInstance]; + endBatch=YES; + if(((ASFKPriv_WrapBQ*)item)->writecond){ + [deferred addObject:(item)]; + } + } + } + } + + } + [lock unlock]; + return subitem; +} + +@end + + diff --git a/src/ASFKCondition.h b/src/ASFKCondition.h deleted file mode 100644 index 054cc07..0000000 --- a/src/ASFKCondition.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// ASFKCondition.h -// Async -// -// Created by bv on 19/12/2020. -// Copyright © 2020 bv. All rights reserved. -// - -#ifndef ASFKCondition_h -#define ASFKCondition_h -/*! - @brief --------------------- - @discussion The main purpose: provide concurrent execution of set of functions. - For each function order of start and termination is undefined. - After first N applications are complete the execution will end. - */ -@interface ASFKCondition : ASFKNonlinearFlow -#pragma mark - Deferred evaluation --(ASFKExecutableProcedureConditional) storeCondition:(ASFKExecutableProcedureConditional)condProc; --(ASFKExecutableProcedureConditionalBranch) storeThenBranch:(ASFKExecutableProcedureConditionalBranch)thenproc; --(ASFKExecutableProcedureConditionalBranch) storeElseBranch:(ASFKExecutableProcedureConditionalBranch)elseproc; --(BOOL) callEvaluateConditionWithParam:(id)param withSummary:(ASFKExecutableProcedureSummary)summary; --(BOOL) castEvaluateConditionWithParam:(id)param withSummary:(ASFKExecutableProcedureSummary)summary; --(BOOL) callEvaluateCondition:(ASFKExecutableProcedureConditional)cond withParam:(id)param withSummary:(ASFKExecutableProcedureSummary)summary; --(BOOL) castEvaluateCondition:(ASFKExecutableProcedureConditional)cond withParam:(id)param withSummary:(ASFKExecutableProcedureSummary)summary; -#pragma mark - Immediate evaluation --(void)callIfExists:(ASFKExecutableProcedureConditional)condProc withParam:(id)param thenDo:(ASFKExecutableProcedureConditionalBranch)thenProc thenParam:(id)thenParam elseDo:(ASFKExecutableProcedureConditionalBranch)elseProc elseParam:(id)elseParam; --(void)castIfExists:(ASFKExecutableProcedureConditional)condProc withParam:(id)param thenDo:(ASFKExecutableProcedureConditionalBranch)thenProc thenParam:(id)thenParam elseDo:(ASFKExecutableProcedureConditionalBranch)elseProc elseParam:(id)elseParam; --(void)callIfExistsWithParam:(id)param thenParam:(id)thenParam elseParam:(id)elseParam; --(void)castIfExistsWithParam:(id)param thenParam:(id)thenParam elseParam:(id)elseParam; --(void)callIfExists:(ASFKExecutableProcedureConditional)condProc withParam:(id)param thenParam:(id)thenParam elseParam:(id)elseParam; --(void)castIfExists:(ASFKExecutableProcedureConditional)condProc withParam:(id)param thenParam:(id)thenParam elseParam:(id)elseParam; -@end - -#endif /* ASFKCondition_h */ diff --git a/src/ASFKCondition.mm b/src/ASFKCondition.mm deleted file mode 100644 index 6000c98..0000000 --- a/src/ASFKCondition.mm +++ /dev/null @@ -1,104 +0,0 @@ -/* - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -// Created by Boris Vigman on 23/02/2019. -// Copyright © 2019-2021 Boris Vigman. All rights reserved. -// - -#import "ASFKBase.h" -@interface ASFKCondition() -@property ASFKExecutableProcedureConditionalBranch thenP; -@property ASFKExecutableProcedureConditionalBranch elseP; -@property ASFKExecutableProcedureConditional condition; -@property dispatch_queue_t exQ; -@end -@implementation ASFKCondition --(id)init{ - self=[super init]; - if(self){ - self.thenP = nil; - self.elseP = nil; - self.condition = nil; - NSString* rand=[[self generateRandomNumber]stringValue]; - self.exQ = dispatch_queue_create([[@"com.condition.1." stringByAppendingString:rand]cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_SERIAL); - rand=nil; - } - return self; -} -#pragma mark - Deferred evaluation --(ASFKExecutableProcedureConditional) storeCondition:(ASFKExecutableProcedureConditional)condProc{ - ASFKExecutableProcedureConditional last=self.condition; - if(condProc){ - self.condition = condProc; - }else{ - ASFKLog(@"WARNING: invalid condition, not set"); - } - return last; -} --(ASFKExecutableProcedureConditionalBranch) storeThenBranch:(ASFKExecutableProcedureConditionalBranch)thenproc{ - ASFKExecutableProcedureConditionalBranch last=self.thenP; - if(thenproc){ - self.thenP = thenproc; - }else{ - ASFKLog(@"WARNING: invalid THEN branch, not set"); - } - return last; -} --(ASFKExecutableProcedureConditionalBranch) storeElseBranch:(ASFKExecutableProcedureConditionalBranch)elseproc{ - ASFKExecutableProcedureConditionalBranch last=self.elseP; - if(elseproc){ - self.elseP = elseproc; - }else{ - ASFKLog(@"WARNING: invalid ELSE branch, not set"); - } - return last; -} -#pragma mark - Immediate evaluation --(BOOL) evaluateConditionWithParam:(id)param withSummary:(ASFKExecutableProcedureSummary)summary{ - return [self evaluateCondition:self.condition withParam:param withSummary:summary]; -} --(BOOL) evaluateCondition:(ASFKExecutableProcedureConditional)cond withParam:(id)param withSummary:(ASFKExecutableProcedureSummary)summary{ - if(self.enabledNonBlockingExecution){ - dispatch_async(self.exQ, ^{ - summary(self.sharedCtrlBlock,[NSNumber numberWithBool: cond(self.sharedCtrlBlock,param)]); - }); - return YES; - }else{ - return cond(self.sharedCtrlBlock, param); - } -} - --(void)ifExists:(ASFKExecutableProcedureConditional)condProc withParam:(id)param thenDo:(ASFKExecutableProcedureConditionalBranch)thenProc thenParam:(id)thenParam elseDo:(ASFKExecutableProcedureConditionalBranch)elseProc elseParam:(id)elseParam{ - if(condProc&&thenProc&&elseProc){ - if(condProc(self.sharedCtrlBlock, param)){ - thenProc(self.sharedCtrlBlock,param,thenParam); - }else{ - elseProc(self.sharedCtrlBlock,param,elseParam); - } - }else{ - ASFKLog(@"WARNING: Condition OR one of branches not set"); - } -} --(void)ifExistsWithParam:(id)param thenParam:(id)thenParam elseParam:(id)elseParam{ - [self ifExists:self.condition withParam:param thenDo:self.thenP thenParam:thenParam elseDo:self.elseP elseParam:elseParam]; -} -/* --(void)pickBranchWithParam:(id)param thenParam:(id)thenParam elseParam:(id)elseParam{ - [self ifExists:self.condition withParam:param thenDo:self.thenP thenParam:thenParam elseDo:self.elseP elseParam:elseParam]; -} - */ --(void)ifExists:(ASFKExecutableProcedureConditional)condProc withParam:(id)param thenParam:(id)thenParam elseParam:(id)elseParam{ - [self ifExists:condProc withParam:param thenDo:self.thenP thenParam:thenParam elseDo:self.elseP elseParam:elseParam]; -} -@end diff --git a/src/ASFKControlBlock+Internal.h b/src/ASFKControlBlock+Internal.h index 080890e..a9378a8 100644 --- a/src/ASFKControlBlock+Internal.h +++ b/src/ASFKControlBlock+Internal.h @@ -13,7 +13,8 @@ along with this program. If not, see . */ // -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 05/04/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. #import "ASFKBase.h" @@ -24,6 +25,6 @@ //-(NSUInteger) getTotalProcessorsNum; -(NSUInteger) getResultPosition; -(void) setProgressRoutine:(ASFKProgressRoutine)progress; --(void) setSecondaryIndex:(NSUInteger)secind; --(NSUInteger) getSecondaryIndex; +//-(void) setSecondaryIndex:(NSUInteger)secind; +//-(NSUInteger) getSecondaryIndex; @end diff --git a/src/ASFKControlBlock+Internal.mm b/src/ASFKControlBlock+Internal.mm index 0105969..ba3e137 100644 --- a/src/ASFKControlBlock+Internal.mm +++ b/src/ASFKControlBlock+Internal.mm @@ -13,18 +13,19 @@ along with this program. If not, see . */ // -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 05/04/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. #import "ASFKControlBlock+Internal.h" @implementation ASFKControlBlock (Internal) --(void) setSecondaryIndex:(NSUInteger)secind{ - indexSecondary=secind; -} --(NSUInteger) getSecondaryIndex{ - return indexSecondary; -} +//-(void) setSecondaryIndex:(NSUInteger)secind{ +// indexSecondary=secind; +//} +//-(NSUInteger) getSecondaryIndex{ +// return indexSecondary; +//} -(void) setResultPosition:(NSUInteger)proc{ diff --git a/src/ASFKControlBlock.mm b/src/ASFKControlBlock.mm index 0e93827..65044a0 100644 --- a/src/ASFKControlBlock.mm +++ b/src/ASFKControlBlock.mm @@ -13,7 +13,8 @@ along with this program. If not, see . */ // -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 05/04/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase.h" @@ -86,10 +87,10 @@ -(BOOL) cancellationRequested{ BOOL b=abortByCallback|abortByCaller; return b; } --(NSString*) getCurrentSessionId{ +-(id) getCurrentSessionId{ return self.sessionId; } --(NSString*)getParentObjectId{ +-(id)getParentObjectId{ return self.parentId; } -(ASFKProgressRoutine) getProgressRoutine{ diff --git a/src/ASFKExpirationCondition.h b/src/ASFKExpirationCondition.h deleted file mode 100644 index 5bfad29..0000000 --- a/src/ASFKExpirationCondition.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. - -#ifndef ASFKExpirationCondition_h -#define ASFKExpirationCondition_h -#import -#include -@interface ASFKCondition :NSObject{ - @protected NSLock* lock; -} --(BOOL) isConditionMet:(id) data; --(BOOL) isConditionMetForDoubleValues:(std::vector&)values data:(id)data; --(BOOL) isConditionMetForBoolValues:(std::vector&)values data:(id)data; --(BOOL) isConditionMetForULonglongValues:(std::vector&)values data:(id)data; --(BOOL) isConditionMetForLonglongValues:(std::vector&)values data:(id)data; --(BOOL) isConditionMetAfterDateValue:(NSDate*)aDate data:(id)data; --(BOOL) isConditionMetForObject:(id)data; --(BOOL) isConditionMetForDoubleValue:(double)value data:(id)data; --(BOOL) isConditionMetForBoolValue:(BOOL)value data:(id)data; --(BOOL) isConditionMetForULonglongValue:(NSUInteger)value data:(id)data; --(BOOL) isConditionMetForLonglongValue:(NSInteger)value data:(id)data; - --(std::vector&) getULLVector; --(std::vector&) getLLVector; --(std::vector&) getDoubleVector; --(std::vector&) getBoolVector; --(NSArray*) getDateVector; --(NSArray*) getDataVector; -@end - -@interface ASFKConditionNone :ASFKCondition --(BOOL) isConditionMetForLonglongValues:(std::vector&)values data:(id)data; -@end - -//@interface ASFKConditionOnBatchEnd:ASFKCondition -//-(BOOL) isConditionMetForLonglongValues:(std::vector&)values data:(id)data; -//@end - -@interface ASFKConditionTemporal : ASFKCondition -@property (readonly,nonatomic) NSDate* itsDeadline; -@property (readonly,nonatomic) NSTimeInterval itsDelay; --(id) initWithSeconds:(NSTimeInterval)sec; --(id) initWithDate:(NSDate*)aDate; --(void) setDelay:(NSTimeInterval) seconds; --(void) setDueDate:(NSDate*) aDate; --(void) setFromTemporalCondition:(ASFKConditionTemporal*)cond; --(void) delayToDeadline; --(void) deadlineToDelay; -/*! - @brief tests ordering between receiver and other object adn sets the receiver to have earliest deadline/delay. - @param cond object to be tested against. If nil - none is done. - @return receiver. - */ --(ASFKConditionTemporal*) testAndSetEarliest:(ASFKConditionTemporal*)cond; -/*! - @brief tests ordering between receiver and other object adn sets the receiver to have latest deadline/delay. - @param cond object to be tested against. If nil - none is done. - @return receiver. - */ --(ASFKConditionTemporal*) testAndSetLatest:(ASFKConditionTemporal*)cond; -/*! - @brief Compares the receiver with other object and returns object with latest deadline or delay. - @param cond object to be tested against. If nil - receiver will be returned. - @return obejct with latest deadline (delay). If deadline and delay not set for both - returns self. - */ --(ASFKConditionTemporal*) chooseLatest:(ASFKConditionTemporal*)cond; -/*! - @brief Compares the receiver with other object and returns object with earliest deadline or delay. - @param cond object to be tested against. If nil - receiver will be returned. - @return obejct with latest deadline (delay). If deadline and delay not set for both - returns self. - */ --(ASFKConditionTemporal*) chooseEarliest:(ASFKConditionTemporal*)cond; - - -@end -#pragma mark - Expiration conditions -@interface ASFKExpirationCondition : ASFKCondition --(BOOL) setULonglongArg:(NSUInteger)arg; --(BOOL) setLonglongArg:(NSInteger)arg; --(BOOL) setBoolArg:(BOOL)arg; --(BOOL) setDoubleArg:(double)arg; --(BOOL) setObjArg:(id)arg; --(BOOL) setDateArg:(NSDate*)arg; --(BOOL) setULonglongArgs:(std::vector&)args; --(BOOL) setLonglongArgs:(std::vector&)arg; --(BOOL) setBoolArgs:(std::vector&)arg; --(BOOL) setDoubleArgs:(std::vector&)arg; --(BOOL) setObjArgs:(NSArray*)arg; --(BOOL) setDateArgs:(NSArray*)arg; --(BOOL) setSampleLongLong:(NSInteger) val; -@end - -@interface ASFKExpirationConditionNone :ASFKExpirationCondition --(id) initWithBatchSize:(NSInteger)size; -@end -@interface ASFKExpirationConditionOnTimer : ASFKExpirationCondition -@property (nonatomic,readonly) ASFKConditionTemporal* expirationTimer; --(id) initWithSeconds:(NSTimeInterval)sec; --(id) initWithDate:(NSDate*)aDate; --(id) initWithTemporalCondition:(ASFKConditionTemporal*)cond; -@end - -@interface ASFKExpirationOnBatchEnd :ASFKExpirationCondition --(id) initWithBatchSize:(NSInteger)size skip:(NSInteger)skip; -@end - -@interface ASFKConditionCallRelease : ASFKCondition{ - @private std::vector releaseArgBool; - @private std::vector releaseArgDouble; - @private std::vector releaseArgLongLong; - @private std::vector releaseArgULongLong; -} - -@property id releaseArgObject; -@property NSDate* releaseArgDate; - -@end -#endif /* ASFKExpirationCondition_h */ diff --git a/src/ASFKExpirationCondition.mm b/src/ASFKExpirationCondition.mm index 7b52b01..34a4968 100644 --- a/src/ASFKExpirationCondition.mm +++ b/src/ASFKExpirationCondition.mm @@ -12,25 +12,28 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 23/02/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // -#import "ASFKExpirationCondition.h" #import "ASFKBase.h" #include +#include +#include @implementation ASFKCondition{ std::atomic setDates; NSMutableArray* datesArray; std::atomic setData; NSMutableArray* dataArray; std::atomic setULL; - std::vector vectULL; std::atomic setLL; - std::vector vectLL; std::atomic setDouble; - std::vector vectDouble; std::atomic setBool; std::vector vectBool; + std::vector vectULL; + std::vector vectLL; + std::vector vectDouble; + } -(void) _initCond{ lock = [NSLock new]; @@ -55,7 +58,7 @@ -(id) init{ } return self; } --(BOOL) setULonglongArg:(NSUInteger)arg{ +-(BOOL) setULonglongArg:(std::uint64_t)arg{ BOOL tval=NO; if(setULL.compare_exchange_strong(tval,YES)){ [lock lock]; @@ -68,7 +71,7 @@ -(BOOL) setULonglongArg:(NSUInteger)arg{ } return NO; } --(BOOL) setLonglongArg:(NSInteger)arg{ +-(BOOL) setLonglongArg:(std::int64_t)arg{ BOOL tval=NO; if(setLL.compare_exchange_strong(tval,YES)){ [lock lock]; @@ -148,7 +151,7 @@ -(BOOL) setDateArg:(NSDate*)arg{ } return NO; } --(BOOL) setULonglongArgs:(std::vector&)args{ +-(BOOL) setULonglongArgs:(std::vector&)args{ BOOL tval=NO; if(setULL.compare_exchange_strong(tval,YES)){ [lock lock]; @@ -161,7 +164,7 @@ -(BOOL) setULonglongArgs:(std::vector&)args{ } return NO; } --(BOOL) setLonglongArgs:(std::vector&)args{ +-(BOOL) setLonglongArgs:(std::vector&)args{ BOOL tval=NO; if(setLL.compare_exchange_strong(tval,YES)){ [lock lock]; @@ -240,10 +243,10 @@ -(BOOL) setObjArgs:(NSArray*)args{ } return NO; } --(std::vector&) getULLVector{ +-(std::vector&) getULLVector{ return vectULL; } --(std::vector&) getLLVector{ +-(std::vector&) getLLVector{ return vectLL; } -(std::vector&) getDoubleVector{ @@ -267,10 +270,10 @@ -(BOOL) isConditionMetForDoubleValues:(std::vector&)values data:(id)data -(BOOL) isConditionMetForBoolValues:(std::vector&)value data:(id)data{ return NO; } --(BOOL) isConditionMetForULonglongValues:(std::vector&)value data:(id)data{ +-(BOOL) isConditionMetForULonglongValues:(std::vector&)value data:(id)data{ return NO; } --(BOOL) isConditionMetForLonglongValues:(std::vector&)value data:(id)data{ +-(BOOL) isConditionMetForLonglongValues:(std::vector&)value data:(id)data{ return NO; } -(BOOL) isConditionMetAfterDateValues:(NSDate*)aDate data:(id)data{ @@ -285,10 +288,10 @@ -(BOOL) isConditionMetForDoubleValue:(double)value data:(id)data{ -(BOOL) isConditionMetForBoolValue:(BOOL)value data:(id)data{ return NO; } --(BOOL) isConditionMetForULonglongValue:(NSUInteger)value data:(id)data{ +-(BOOL) isConditionMetForULonglongValue:(std::uint64_t)value data:(id)data{ return NO; } --(BOOL) isConditionMetForLonglongValue:(NSInteger)value data:(id)data{ +-(BOOL) isConditionMetForLonglongValue:(std::int64_t)value data:(id)data{ return NO; } @end @@ -480,7 +483,7 @@ -(BOOL) isConditionMetAfterDateValue:(NSDate*)aDate data:(id)data{ @end @implementation ASFKExpirationCondition --(BOOL) setSampleLongLong:(NSInteger) val{ +-(BOOL) setSampleLongLong:(std::int64_t) val{ return NO; } @end @@ -534,9 +537,9 @@ -(BOOL) isConditionMet:(id) data{ @end @implementation ASFKExpirationOnBatchEnd{ - std::atomic batchSize; - std::atomic skipItems; - std::atomic sample; + std::atomic batchSize; + std::atomic skipItems; + std::atomic sample; } -(id) init{ self = [super init]; @@ -547,7 +550,7 @@ -(id) init{ } return self; } --(id) initWithBatchSize:(NSInteger)size skip:(NSInteger)skip{ +-(id) initWithBatchSize:(std::int64_t)size skip:(std::int64_t)skip{ self = [super init]; if(self){ if(skip<0){ @@ -569,7 +572,7 @@ -(BOOL) isConditionMet:(id)data{ return x; } --(BOOL) isConditionMetForLonglongValue:(NSInteger)value data:(id)data{ +-(BOOL) isConditionMetForLonglongValue:(std::int64_t)value data:(id)data{ BOOL res=NO; if(value > 0){ skipItems.fetch_sub(1); @@ -589,7 +592,7 @@ -(BOOL) isConditionMetForLonglongValue:(NSInteger)value data:(id)data{ } return res; } --(BOOL) setSampleLongLong:(NSInteger)val{ +-(BOOL) setSampleLongLong:(std::int64_t)val{ sample=val; return YES; } diff --git a/src/ASFKFilter.h b/src/ASFKFilter.h deleted file mode 100644 index 8c56956..0000000 --- a/src/ASFKFilter.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. -// - -#import "ASFKBase.h" - -@interface ASFKFilter : ASFKLinearFlow -/*! - @brief Tests given object with some custom criteria. - @param object object to test. - @return YES if test passes; NO otherwise. - */ --(BOOL) testCriteriaMatch:(id)object; -/*! - @brief Tests array of objects. - @param objects objects to test. - @param writeOut indication of whether to save passing objects or non-passing. YES for passing, NO otherwise. - @param array array of filtered objects. - @return YES if at least one test passes; NO otherwise. - */ --(BOOL) filterCandidatesInArray:(NSArray*)objects passing:(BOOL)writeOut saveToArray:(NSMutableArray*)array; -/*! - @brief Tests array of objects. - @param objects objects to test. - @param writeOut indication of whether to save passing objects or non-passing. YES for passing, NO otherwise. - @param iset index set of filtered objects. - @return YES if at least one test passes; NO otherwise. - */ --(BOOL) filterCandidatesInArray:(NSArray*)objects passing:(BOOL)writeOut saveToIndexSet:(NSMutableIndexSet*)iset; -/*! - @brief Tests array of objects. - @param objects objects to test. - @param writeOut indication of whether to save passing objects or non-passing. YES for passing, NO otherwise. - @param range range of indexes of filtered objects. - @return YES if at least one test passes; NO otherwise. - */ --(BOOL) filterCandidatesInArray:(NSArray*)objects passing:(BOOL)writeOut saveToRange:(NSRange&)range; -/*! - @brief Tests unordered set of objects. - @param objects objects to test. - @param writeOut indication of whether to save passing objects or non-passing. YES for passing, NO otherwise. - @param array array of filtered objects. - @return YES if at least one test passes; NO otherwise. - */ --(BOOL) filterCandidatesInSet:(NSSet*)objects passing:(BOOL)writeOut saveToArray:(NSMutableArray*)array; -/*! - @brief Tests unordered set of objects. - @param objects ordered set of objects to test. - @param writeOut indication of whether to save passing objects or non-passing. YES for passing, NO otherwise. - @param iset index set of filtered objects. - @return YES if at least one test passes; NO otherwise. - */ --(BOOL) filterCandidatesInOrderedSet:(NSOrderedSet*)objects passing:(BOOL)writeOut saveToIndexSet:(NSMutableIndexSet*)iset; -/*! - @brief Tests unordered set of objects. - @param objects ordered set of objects to test. - @param writeOut indication of whether to save passing objects or non-passing. YES for passing, NO otherwise. - @param range range of indexes of filtered objects. - @return YES if at least one test passes; NO otherwise. - */ --(BOOL) filterCandidatesInOrderedSet:(NSOrderedSet*)objects passing:(BOOL)writeOut saveToRange:(NSRange&)range; -/*! - @brief Tests dictionary of objects. - @param objects ordered set of objects to test. - @param writeOut indication of whether to save passing objects or non-passing. YES for passing, NO otherwise. - @param keys array of keys of filtered objects. If nil, then not used. - @param values array of values of filtered objects. If nil, then not used. - @return YES if at least one test passes; NO otherwise. - */ --(BOOL) filterCandidatesInDictionary:(NSDictionary*)objects passing:(BOOL)writeOut saveToKeys:(NSMutableArray*)keys values:(NSMutableArray*)values; -@end diff --git a/src/ASFKFilter.mm b/src/ASFKFilter.mm index 7e0df16..a47f1c7 100644 --- a/src/ASFKFilter.mm +++ b/src/ASFKFilter.mm @@ -12,21 +12,22 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 15/02/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase.h" -#import "ASFKLinearFlow+Internal.h" +#import "ASFKSessionalFlow+Internal.h" @implementation ASFKFilter --(NSDictionary*) _castUnorderedSet:(ASFKParamSet*) params{ +-(NSDictionary*) _postUnorderedSet:(ASFKParamSet*) params blocking:(BOOL) blk{ return @{}; } --(NSDictionary*) _castOrderedSet:(ASFKParamSet*) params{ +-(NSDictionary*) _postOrderedSet:(ASFKParamSet*) params blocking:(BOOL) blk{ return @{}; } --(NSDictionary*) _castArray:(ASFKParamSet*) params{ +-(NSDictionary*) _postArray:(ASFKParamSet*)params blocking:(BOOL) blk{ return @{}; } diff --git a/src/ASFKFilteringQueue.h b/src/ASFKFilteringQueue.h deleted file mode 100644 index f3b189b..0000000 --- a/src/ASFKFilteringQueue.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -// -// Copyright © 2019-2022 Boris Vigman. All rights reserved. -// -#import "ASFKBase.h" - -@interface ASFKFilteringQueue : ASFKQueue -typedef NSIndexSet* (^clbkASFKFQFilter)(NSArray* collection, NSRange range); -/*! - @brief Sets maximum queue size. - @discussion when the queue size reached this value any further enqueing operation will not increase it. - @param size required maximum size. - @return YES if the update left the limits in ascending order, NO otherwise. - */ --(BOOL) setMaxQSize:(NSUInteger)size; -/*! - @brief Sets minimum queue size. - @discussion when the queue size reached this value any further enqueing operation will not decrease it. - @param size required minimum size. - @return YES if the update left the limits in ascending order, NO otherwise. - */ --(BOOL) setMinQSize:(NSUInteger)size; -/*! - @brief Sets dropping methods for this queue. - @discussion when the queue's maximum size reached then on 'push' operation decision needs to be taken regarding fresh candidate. In order to keep the queue size unchanged some item(s) need to be discarded; alternatively new candidate may be rejected. This method sets specific dropping mode. - */ --(void) setDroppingPolicy:(eASFKQDroppingPolicy)policy; -/*! - @brief Sets dropping algorithm for this queue. - @discussion when the queue's maximum size reached then on 'push' operation decision needs to be taken regarding fresh candidate. In order to keep the queue size unchanged some item(s) need to be discarded; alternatively new candidate may be rejected. this method sets specific dropping algorittm. - @param dropAlg the custom dropping algorithm; may bi nil. - */ --(void) setDroppingAlgorithmL1:(ASFKFilter*)dropAlg; -/*! - @brief Pulls item from queue, while simulating the queue size. - @discussion Sometimes it is necessary to pull item from queue while pretending that its size is differend from actual. - @param count number to be temporarily added to the queue size while deciding if item can be pulled. - */ --(id) pullWithCount:(NSInteger) count; -/*! - @brief Filters queue with provided filtering object. - @discussion Leaves in queue only items that do not match filtering criteria. - @param filter the filtering object; may be nil. - */ --(void) filterWith:(ASFKFilter*)filter; -/*! - @brief Removes from queue given object. - @discussion Removes from queue all objects equal to given object with respect to provided property; equality is defined by the block. - @param obj object to remove; may not be nil. - @param blk block that tests equality; must return YES to remove; may not be nil. - @return YES for succesful removal; NO otherwise. - */ --(BOOL) removeObjWithProperty:(id)obj andBlock:(BOOL (^)(id item,id sample, BOOL* stop)) blk; -@end diff --git a/src/ASFKFilteringQueue.mm b/src/ASFKFilteringQueue.mm index 272b4ca..3599747 100644 --- a/src/ASFKFilteringQueue.mm +++ b/src/ASFKFilteringQueue.mm @@ -13,15 +13,12 @@ along with this program. If not, see . */ // -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase.h" -#import "ASFKFilteringQueue.h" @implementation ASFKFilteringQueue{ std::atomic dpolicy; - std::atomic maxQSize; - std::atomic minQSize; ASFKFilter* itsFilter; } -(id)init{ @@ -39,38 +36,50 @@ -(id)initWithName:(NSString*)name{ } return self; } +-(id)initWithName:(NSString*)name blocking:(BOOL)blk{ + self=[super initWithName:name]; + if(self){ + [self _initFQ]; + } + return self; +} -(void) _initFQ{ dpolicy=E_ASFK_Q_DP_HEAD; itsFilter=nil; - minQSize=0; - maxQSize=ULONG_MAX; } --(BOOL) setMaxQSize:(NSUInteger)size{ - BOOL r=YES; - if(size <= minQSize){ - r=NO; - WASFKLog(@"new upper limit is not greater than lower limit"); - } - maxQSize=size; - return r; + +#pragma mark - Prepending (disabled) +-(BOOL) prependFromQueue:(ASFKQueue*)otherq{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; } --(BOOL) setMinQSize:(NSUInteger)size{ - BOOL r=YES; - if(size >= maxQSize){ - r=NO; - WASFKLog(@"new lower limit is not less than upper limit"); - } - minQSize=size; - return r; +-(BOOL) prependFromArray:(NSArray*)array{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) prependFromOrderedSet:(NSOrderedSet*)set{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) prependFromUnorderedSet:(NSSet*)set{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; } +-(BOOL) prependFromDictionary:(NSDictionary*)dict{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +#pragma mark - configuration + -(void) setDroppingPolicy:(eASFKQDroppingPolicy)policy{ dpolicy=policy; } --(void) setDroppingAlgorithmL1:(ASFKFilter*)dropAlg{ +-(void) setDroppingAlgorithm:(ASFKFilter*)dropAlg{ [lkNonLocal lock]; itsFilter = dropAlg; [lkNonLocal unlock]; } +#pragma mark - filtering -(BOOL) removeObjWithProperty:(id)obj andBlock:(BOOL (^)(id item,id sample, BOOL* stop)) blk{ BOOL r=NO; @@ -96,11 +105,153 @@ -(BOOL) removeObjWithProperty:(id)obj andBlock:(BOOL (^)(id item,id sample, BOOL } return r; } +#pragma mark - non-blocking interface +-(BOOL) castQueue:(ASFKQueue*)otherq exParams:(ASFKExecutionParams*)ex{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} --(BOOL)push:(id)item{ +-(BOOL) castArray:(NSArray*)array exParams:(ASFKExecutionParams*)ex{ + if(array==nil || [array count]==0){ + return NO; + } + BOOL res=YES; + [lock lock]; + for (id item in array) { + res &= [self _insertElement:item]; + } + + [lock unlock]; + return res; +} +-(BOOL) castDictionary:(NSDictionary*)dict exParams:(ASFKExecutionParams*)ex{ + if(dict==nil || [dict count]==0){ + return NO; + } + BOOL res=YES; + NSArray* a=[dict allValues]; + [lock lock]; + for (id item in a) { + res &= [self _insertElement:item]; + } + + [lock unlock]; + return res; +} +-(BOOL) castOrderedSet:(NSOrderedSet*)set exParams:(ASFKExecutionParams*)ex{ + if(set==nil || [set count]==0){ + return NO; + } + BOOL res=YES; + [lock lock]; + for (id item in set) { + res &= [self _insertElement:item]; + } + [lock unlock]; + return res; +} +-(BOOL) castUnorderedSet:(NSSet*)set exParams:(ASFKExecutionParams*)ex{ + if(set==nil || [set count]==0){ + return NO; + } + BOOL res=YES; + [lock lock]; + for (id item in set) { + res &= [self _insertElement:item]; + } + [lock unlock]; + return res; +} + +-(BOOL)castObject:(id)item exParams:(ASFKExecutionParams*)ex{ BOOL res=NO; if(item){ [lock lock]; + res = [self _insertElement:item]; + [lock unlock]; + } + return res; +} +#pragma mark - Blocking interface (disabled) +-(BOOL) callQueue:(ASFKQueue*)otherq{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) callArray:(NSArray*)array exParams:(ASFKExecutionParams*) expar{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) callDictionary:(NSDictionary*)dict exParams:(ASFKExecutionParams*) expar{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) callOrderedSet:(NSOrderedSet*)set exParams:(ASFKExecutionParams*) expar{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) callUnorderedSet:(NSSet*)set exParams:(ASFKExecutionParams*) expar{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) callObject:(id)item exParams:(ASFKExecutionParams*) expar{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +#pragma mark - Reading +-(id)pullWithCount:(NSInteger) count{ + if(paused){ + return nil; + } + [lock lock]; + NSUInteger qc = [q count]; + id item=[q firstObject]; + if (item && qc + count >= minQSize) { + [q removeObjectAtIndex:0]; + } + else{ + item=nil; + } + [lock unlock];; + return item; +} +-(id)pull{ + if(paused){ + return nil; + } + [lock lock]; + NSUInteger qc = [q count]; + id item=[q firstObject]; + if (item && qc >= minQSize) { + [q removeObjectAtIndex:0]; + } + else{ + item=nil; + } + [lock unlock];; + + return item; +} + +-(void) filterWith:(ASFKFilter*)filter{ + ASFKFilter* ft=filter; + [lock lock]; + if(!ft) + { + ft=itsFilter; + } + if(ft){ + NSMutableIndexSet* iset=[NSMutableIndexSet new]; + BOOL res=[ft filterCandidatesInArray:q passing:YES saveToIndexSet:iset]; + if(res){ + [q removeObjectsAtIndexes:iset]; + } + } + [lock unlock]; +} + +#pragma mark - Private methods +-(BOOL) _insertElement:(id) item{ + BOOL res=NO; NSUInteger qc = [q count]; if(qc+1 <= maxQSize) { @@ -148,52 +299,17 @@ -(BOOL)push:(id)item{ } } - [lock unlock]; - } return res; } --(id)pullWithCount:(NSInteger) count{ - [lock lock]; - NSUInteger qc = [q count]; - id item=[q firstObject]; - if (item && qc + count >= minQSize) { - [q removeObjectAtIndex:0]; - } - else{ - item=nil; - } - [lock unlock];; - return item; -} --(id)pull{ - [lock lock]; - NSUInteger qc = [q count]; - id item=[q firstObject]; - if (item && qc >= minQSize) { - [q removeObjectAtIndex:0]; - } - else{ - item=nil; - } - [lock unlock];; - - return item; +-(void) reset{ + [super reset]; + dpolicy=E_ASFK_Q_DP_HEAD; + itsFilter=nil; + minQSize=0; + maxQSize=ULONG_MAX; } --(void) filterWith:(ASFKFilter*)filter{ - ASFKFilter* ft=filter; - [lock lock]; - if(!ft) - { - ft=itsFilter; - } - if(ft){ - NSMutableIndexSet* iset=[NSMutableIndexSet new]; - BOOL res=[ft filterCandidatesInArray:q passing:YES saveToIndexSet:iset]; - if(res){ - [q removeObjectsAtIndexes:iset]; - } - } - [lock unlock]; +-(void) purge{ + [super purge]; } @end diff --git a/src/ASFKGlobalThreadpool.h b/src/ASFKGlobalThreadpool.h deleted file mode 100644 index eaf41ac..0000000 --- a/src/ASFKGlobalThreadpool.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -// -// Copyright © 2019-2022 Boris Vigman. All rights reserved. -// - -#import -#import "ASFKBase.h" - -@interface ASFKGlobalThreadpool : NSObject -+(ASFKGlobalThreadpool *)sharedManager ; - --(long long) runningSessionsCount; --(long long) pausedSessionsCount; --(void) postDataAsArray:(NSArray*)data forSession:(ASFK_IDENTITY_TYPE)sessionId; --(void) postDataAsOrderedSet:(NSOrderedSet*)set forSession:(ASFK_IDENTITY_TYPE)sessionId; --(void) postDataAsUnorderedSet:(NSSet*)data forSession:(ASFK_IDENTITY_TYPE)sessionId; --(void) postDataAsDictionary:(NSDictionary*)data forSession:(ASFK_IDENTITY_TYPE)sessionId; --(BOOL) addSession:(ASFKThreadpoolSession*)aseq withId:(ASFK_IDENTITY_TYPE)identity; - --(ASFKThreadpoolSession*) getThreadpoolSessionWithId:(ASFK_IDENTITY_TYPE)identity; --(NSArray*) getThreadpoolSessionsList; --(void) cancelSession:(ASFK_IDENTITY_TYPE)sessionId; --(void) cancelAll; --(BOOL) isBusySession:(ASFK_IDENTITY_TYPE)sessionId; - --(BOOL) isPausedSession:(ASFK_IDENTITY_TYPE)sessionId; - --(void) flushSession:(ASFK_IDENTITY_TYPE)sessionId; --(void) flushAll; --(void) pauseSession:(ASFK_IDENTITY_TYPE)sessionId; --(void) pauseAll; --(void) resumeSession:(ASFK_IDENTITY_TYPE)sessionId; --(void) resumeAll; --(long long) itemsCountForSession:(ASFK_IDENTITY_TYPE)sessionId; -@end diff --git a/src/ASFKGlobalThreadpool.mm b/src/ASFKGlobalThreadpool.mm index a66621a..f16a500 100644 --- a/src/ASFKGlobalThreadpool.mm +++ b/src/ASFKGlobalThreadpool.mm @@ -13,10 +13,10 @@ along with this program. If not, see . */ // -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 05/04/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // -#import "ASFKGlobalThreadpool.h" #import "ASFKBase+Internal.h" #include #include @@ -43,7 +43,7 @@ @implementation ASFKGlobalThreadpool{ NSMutableDictionary* allSessions; ThreadpoolConfig tpcfg; NSLock* lkMutexL1; - NSLock* lkMutexL2; + //NSLock* lkMutexL2; //NSLock* lkMutexL1; NSCondition* lkCond; @@ -53,25 +53,25 @@ @implementation ASFKGlobalThreadpool{ std::vector vectProc2Bounds; } #pragma mark Singleton Methods -+ (ASFKGlobalThreadpool *)sharedManager { - static ASFKGlobalThreadpool *sharedManager = nil; ++ (ASFKGlobalThreadpool *)singleInstance { + static ASFKGlobalThreadpool *singleInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - sharedManager = [[self alloc] init]; + singleInstance = [[self alloc] init]; }); - return sharedManager; + return singleInstance; } - (id)init { self = [super init]; if (self) { runningSessions=[NSMutableDictionary dictionary]; - onlineSessions=[NSMutableArray array]; + onlineSessions=[NSArray array]; killedSessions=[NSMutableArray array]; pausedSessions=[NSMutableDictionary new]; allSessions=[NSMutableDictionary new]; lkMutexL1=[NSLock new]; - lkMutexL2=[NSLock new]; + //lkMutexL2=[NSLock new]; lkCond=[NSCondition new]; self.threadsLimit=1; shouldSleep=YES; @@ -96,15 +96,15 @@ - (id)init { } return self; } --(long long)runningSessionsCount{ +-(std::uint64_t)runningSessionsCount{ [lkMutexL1 lock]; - long long cc=[runningSessions count]; + std::uint64_t cc=[runningSessions count]; [lkMutexL1 unlock]; return (cc); } --(long long)pausedSessionsCount{ +-(std::uint64_t)pausedSessionsCount{ [lkMutexL1 lock]; - long long ac=[pausedSessions count]; + std::uint64_t ac=[pausedSessions count]; [lkMutexL1 unlock]; return (ac); } @@ -135,18 +135,23 @@ -(BOOL) isBusySession:(ASFK_IDENTITY_TYPE)sessionId{ } -(NSArray*) getThreadpoolSessionsList{ [lkMutexL1 lock]; - NSArray* a=[runningSessions allKeys]; + NSArray* a=[allSessions allKeys]; [lkMutexL1 unlock]; return a; } - --(long long) itemsCountForSession:(ASFK_IDENTITY_TYPE)sessionId{ - long result=0; +-(std::uint64_t) totalSessionsCount{ + [lkMutexL1 lock]; + std::uint64_t c=[allSessions count]; + [lkMutexL1 unlock]; + return c; +} +-(std::uint64_t) itemsCountForSession:(ASFK_IDENTITY_TYPE)sessionId{ + std::uint64_t result=0; if(sessionId){ [lkMutexL1 lock]; ASFKThreadpoolSession* ss=[allSessions objectForKey:sessionId]; if(ss){ - result= [ss itemsCount]; + result= [ss getDataItemsCount]; } [lkMutexL1 unlock]; @@ -185,10 +190,10 @@ -(void) _cancelSessionInternally:(ASFK_IDENTITY_TYPE)sessionId{ ASFKThreadpoolSession* ss=[allSessions objectForKey:sessionId]; if(ss){ [runningSessions removeObjectForKey:sessionId]; - [lkMutexL2 lock]; + //[lkMutexL2 lock]; onlineSessions=[runningSessions allValues]; - [lkMutexL2 unlock]; + //[lkMutexL2 unlock]; [allSessions removeObjectForKey:sessionId]; [pausedSessions removeObjectForKey:sessionId]; @@ -207,10 +212,10 @@ -(void) cancelSession:(ASFK_IDENTITY_TYPE)sessionId{ [ss cancel]; [runningSessions removeObjectForKey:sessionId]; - [lkMutexL2 lock]; + //[lkMutexL2 lock]; onlineSessions=[runningSessions allValues]; - [lkMutexL2 unlock]; + //[lkMutexL2 unlock]; [allSessions removeObjectForKey:sessionId]; [pausedSessions removeObjectForKey:sessionId]; @@ -230,7 +235,7 @@ -(void) cancelAll{ ss=nil; }]; - [lkMutexL2 lock]; + //[lkMutexL2 lock]; tpcfg.actualThreadsCount=0; ThreadpoolConfig tpc=tpcfg; [self _reassignProcs:tpc]; @@ -238,9 +243,8 @@ -(void) cancelAll{ vectProc2Bounds.resize(tpcfg.actualThreadsCount); onlineSessions = [NSArray new]; - [lkMutexL2 unlock]; + //[lkMutexL2 unlock]; runningSessions = [NSMutableDictionary new]; - pausedSessions = [NSMutableDictionary new]; allSessions = [NSMutableDictionary new]; [lkMutexL1 unlock]; @@ -255,9 +259,9 @@ -(void) pauseSession:(ASFK_IDENTITY_TYPE)sessionId{ ss->paused=YES; [pausedSessions setObject:ss forKey:sessionId]; [runningSessions removeObjectForKey:sessionId]; - [lkMutexL2 lock]; + //[lkMutexL2 lock]; onlineSessions=[runningSessions allValues]; - [lkMutexL2 unlock]; + //[lkMutexL2 unlock]; if(ss->onPauseNotification){ ss->onPauseNotification(sessionId,YES); } @@ -276,9 +280,9 @@ -(void) pauseAll{ ASFKThreadpoolSession* ss=(ASFKThreadpoolSession*)obj; ss->paused=YES; }]; - [lkMutexL2 lock]; + //[lkMutexL2 lock]; onlineSessions = [NSArray new]; - [lkMutexL2 unlock]; + //[lkMutexL2 unlock]; [lkMutexL1 unlock]; DASFKLog(@"ASFKGlobalThreadpool: All sessions paused"); } @@ -291,9 +295,9 @@ -(void) resumeSession:(ASFK_IDENTITY_TYPE)sessionId{ ss->paused=NO; [pausedSessions removeObjectForKey:sessionId]; [runningSessions setObject:ss forKey:sessionId]; - [lkMutexL2 lock]; + //[lkMutexL2 lock]; onlineSessions = [runningSessions allValues]; - [lkMutexL2 unlock]; + //[lkMutexL2 unlock]; if(ss->onPauseNotification){ ss->onPauseNotification(sessionId,NO); } @@ -310,9 +314,9 @@ -(void) resumeAll{ [runningSessions addEntriesFromDictionary:pausedSessions]; pausedSessions=[NSMutableDictionary new]; - [lkMutexL2 lock]; + //[lkMutexL2 lock]; onlineSessions=[runningSessions allValues]; - [lkMutexL2 unlock]; + //[lkMutexL2 unlock]; [runningSessions enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop){ ASFKThreadpoolSession* ss=(ASFKThreadpoolSession*)obj; ss->paused=NO; @@ -320,49 +324,110 @@ -(void) resumeAll{ [lkMutexL1 unlock]; DASFKLog(@"ASFKGlobalThreadpool: All sessions resumed"); } --(void) postDataAsDictionary:(NSDictionary*)data forSession:(ASFK_IDENTITY_TYPE)sessionId{ +-(BOOL) postDataAsDictionary:(NSDictionary*)data forSession:(ASFK_IDENTITY_TYPE)sessionId blocking:(BOOL)blk{ +#ifdef __ASFK_DEBUG__ + if(blk){ + DASFKLog(@"Performing blocking call"); + } + else{ + DASFKLog(@"Performing non-blocking call"); + } +#endif + BOOL res=NO; [lkMutexL1 lock]; ASFKThreadpoolSession* ss=[allSessions objectForKey:sessionId]; [lkMutexL1 unlock]; if(ss){ - [ss postDataItemsAsDictionary:data]; + if(ss->callMode == ASFK_BC_NO_BLOCK && blk){ + MASFKLog(ASFK_STR_MISCONFIG_OP); + } + else{ + res=[ss postDataItemsAsDictionary:data blocking:blk]; + } + } else{ EASFKLog(@"ASFKGlobalThreadpool: Pipeline session %@ not found",sessionId); } + return res; } --(void) postDataAsArray:(NSArray*)data forSession:(ASFK_IDENTITY_TYPE)sessionId{ +-(BOOL) postDataAsArray:(NSArray*)data forSession:(ASFK_IDENTITY_TYPE)sessionId blocking:(BOOL)blk{ +#ifdef __ASFK_DEBUG__ + if(blk){ + DASFKLog(@"Performing blocking call"); + } + else{ + DASFKLog(@"Performing non-blocking call"); + } +#endif + BOOL res=NO; [lkMutexL1 lock]; ASFKThreadpoolSession* ss=[allSessions objectForKey:sessionId]; [lkMutexL1 unlock]; if(ss){ - [ss postDataItemsAsArray:data]; + if(ss->callMode == ASFK_BC_NO_BLOCK && blk){ + MASFKLog(ASFK_STR_MISCONFIG_OP); + } + else{ + res=[ss postDataItemsAsArray:data blocking:blk]; + } } else{ EASFKLog(@"ASFKGlobalThreadpool: Pipeline session %@ not found",sessionId); } + return res; } --(void) postDataAsOrderedSet:(NSOrderedSet*)data forSession:(ASFK_IDENTITY_TYPE)sessionId{ +-(BOOL) postDataAsOrderedSet:(NSOrderedSet*)data forSession:(ASFK_IDENTITY_TYPE)sessionId blocking:(BOOL)blk{ +#ifdef __ASFK_DEBUG__ + if(blk){ + DASFKLog(@"Performing blocking call"); + } + else{ + DASFKLog(@"Performing non-blocking call"); + } +#endif + BOOL res=NO; [lkMutexL1 lock]; ASFKThreadpoolSession* ss=[allSessions objectForKey:sessionId]; [lkMutexL1 unlock]; if(ss){ - [ss postDataItemsAsOrderedSet:data]; + if(ss->callMode == ASFK_BC_NO_BLOCK && blk){ + MASFKLog(ASFK_STR_MISCONFIG_OP); + } + else{ + res=[ss postDataItemsAsOrderedSet:data blocking:blk]; + } } else{ EASFKLog(@"ASFKGlobalThreadpool: Pipeline session %@ not found",sessionId); } + return res; } --(void) postDataAsUnorderedSet:(NSSet*)data forSession:(ASFK_IDENTITY_TYPE)sessionId{ +-(BOOL) postDataAsUnorderedSet:(NSSet*)data forSession:(ASFK_IDENTITY_TYPE)sessionId blocking:(BOOL)blk{ +#ifdef __ASFK_DEBUG__ + if(blk){ + DASFKLog(@"Performing blocking call"); + } + else{ + DASFKLog(@"Performing non-blocking call"); + } +#endif + BOOL res=NO; [lkMutexL1 lock]; ASFKThreadpoolSession* ss=[allSessions objectForKey:sessionId]; [lkMutexL1 unlock]; if(ss){ - [ss postDataItemsAsUnorderedSet:data]; + if(ss->callMode == ASFK_BC_NO_BLOCK && blk){ + MASFKLog(ASFK_STR_MISCONFIG_OP); + } + else{ + res=[ss postDataItemsAsUnorderedSet:data blocking:blk]; + } } else{ EASFKLog(@"ASFKGlobalThreadpool: Pipeline session %@ not found",sessionId); } + return res; } -(BOOL) addSession:(ASFKThreadpoolSession*)aseq withId:(ASFK_IDENTITY_TYPE)identity{ @@ -371,9 +436,9 @@ -(BOOL) addSession:(ASFKThreadpoolSession*)aseq withId:(ASFK_IDENTITY_TYPE)ident if([allSessions objectForKey:identity]==nil){ [runningSessions setObject:aseq forKey:identity]; [allSessions setObject:aseq forKey:identity]; - [lkMutexL2 lock]; + //[lkMutexL2 lock]; onlineSessions=[runningSessions allValues]; - [lkMutexL2 unlock]; + //[lkMutexL2 unlock]; res=YES; } @@ -382,7 +447,7 @@ -(BOOL) addSession:(ASFKThreadpoolSession*)aseq withId:(ASFK_IDENTITY_TYPE)ident } -(ASFKThreadpoolSession*) getThreadpoolSessionWithId:(ASFK_IDENTITY_TYPE)identity{ [lkMutexL1 lock]; - ASFKThreadpoolSession* ss=[runningSessions objectForKey:identity]; + ASFKThreadpoolSession* ss=[allSessions objectForKey:identity]; [lkMutexL1 unlock]; return ss; } @@ -404,25 +469,13 @@ -(void) _reassignProcs:(ThreadpoolConfig&)tpc{ if(tpc.requiredThreadsCount0;--r){ - tcr=vectProc2Bounds[tpc.actualThreadsCount-r]; - tcr.length=1; - tcr.lowBound=r; - vectProc2Bounds[tpc.actualThreadsCount-r]=tcr; - } } else{ tpc.share = tpc.requiredThreadsCount / tpc.actualThreadsCount; @@ -456,7 +509,7 @@ -(void) _engineDeploy{ { ThreadpoolConfig tpc=tpcfg; ThreadpoolConfigRange tcr; - [lkMutexL2 lock]; + [lkMutexL1 lock]; ///-----Housekeeping----- /// @@ -469,7 +522,7 @@ -(void) _engineDeploy{ tcr=vectProc2Bounds[ii]; if(tcr.length==0 || [onlineSessions count]==0){ - [lkMutexL2 unlock]; + [lkMutexL1 unlock]; continue; } selectedSlot=(selectedSlot+1); @@ -480,7 +533,7 @@ -(void) _engineDeploy{ selectedSlot=tcr.lowBound; } if(selectedSlot >= [onlineSessions count]){ - [lkMutexL2 unlock]; + [lkMutexL1 unlock]; continue; } @@ -488,24 +541,35 @@ -(void) _engineDeploy{ if(ss && [ss->cblk cancellationRequested]){ ThreadpoolConfig tpc1=tpcfg; //[lkMutexL2 lock]; + // @try{ + //[lkMutexL1 lock]; onlineSessions=nil; onlineSessions=[runningSessions allValues]; + //[lkMutexL1 unlock]; + //} +// @catch(NSException* exp){ +// NSLog(@"Err 1: %@",exp); +// int x=0; +// } +// @finally{ +// //NSLog(@"Finally"); +// }; [self _reassignProcs:tpc1]; - [lkMutexL2 unlock]; + [lkMutexL1 unlock]; //[lkMutexL1 unlock]; continue; } - [lkMutexL2 unlock]; + [lkMutexL1 unlock]; if(ss){ [ss select:ii routineCancel:^id(id identity) { DASFKLog(@"Stopping session %@, selector %ld",identity,selectedSlot); [self _cancelSessionInternally:identity]; ThreadpoolConfig tpc1=tpcfg; - [lkMutexL2 lock]; + [lkMutexL1 lock]; [self _reassignProcs:tpc1]; - [lkMutexL2 unlock]; + [lkMutexL1 unlock]; //[lkMutexL1 unlock]; return nil; }]; @@ -516,7 +580,7 @@ -(void) _engineDeploy{ [blocks addObject:b1]; } - id sumresult= [[ASFKGlobalQueue sharedManager]submitBlocks:blocks summary:(id)^{ + id sumresult= [[ASFKGlobalQueue singleInstance]submitBlocks:blocks summary:(id)^{ busyCount=0; return nil; } diff --git a/src/ASFKLinearFlow.h b/src/ASFKLinearFlow.h deleted file mode 100644 index fd64246..0000000 --- a/src/ASFKLinearFlow.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. -// -#ifndef ASFKLinearFlow_h -#define ASFKLinearFlow_h - -@protocol ASFKSynchronous -@required -/** - @brief Performs blocking call with array of data and invokes stored Summary block. - @param array array of data for processing. - @return dictionary that includes result of execution followed by additional information. - */ --(NSDictionary*) callArray:(NSArray*)array session:(id)sessionId execParams:(ASFKExecutionParams*)params; - -/** - @brief Performs blocking call with dictionary of data and invokes stored Summary block with result. - @param dictionary dictionary of data. - @return dictionary that includes result of execution followed by additional information. - */ --(NSDictionary*) callDictionary:(NSDictionary*)dictionary session:(id)sessionId exParam:(NSDictionary*)ex; -/** - @brief Performs blocking call with ordered set of data and invokes stored Summary block with result. - @param set ordered set of data. - @return dictionary that includes result of execution followed by additional information. - */ --(NSDictionary*) callOrderedSet:(NSOrderedSet*)set session:(id)sessionId exParam:(NSDictionary*)ex; - -/** - @brief Performs blocking call with unordered of data and invokes stored Summary block with result. - @param set unordered set of data. - @return dictionary that includes result of execution followed by additional information. - */ --(NSDictionary*) callUnorderedSet:(NSSet*)set session:(id)sessionId exParam:(NSDictionary*)ex; -/*! - @brief Performs blocking call with dictionary of data and invokes stored Summary block with result. - @param uns unspecified piece of data. - @return dictionary that includes result of execution followed by additional information. - */ --(NSDictionary*) callObject:(id)uns session:(id)sessionId exParam:(NSDictionary*)ex; - -@end -@protocol ASFKAsynchronous -@required -/*! - @brief Performs non-blocking call with on array of data and invokes stored Summary block with result. - @param array array of data for processing. - @return dictionary that includes result of execution followed by additional information. - */ --(NSDictionary*) castArray:(NSArray*)array session:(id)sessionId exParam:(ASFKExecutionParams*)ex; - -/*! - @brief Performs non-blocking call with dictionary of data and invokes stored Summary block with result. - @param dictionary dictionary of data. - @return dictionary that includes result of execution followed by additional information. - */ --(NSDictionary*) castDictionary:(NSDictionary*)dictionary session:(id)sessionId exParam:(ASFKExecutionParams*)ex; - -/*! - @brief Performs non-blocking call with ordered set of data and invokes stored Summary block with result. - @param set ordered set of data. - @return dictionary that includes result of execution followed by additional information. - */ --(NSDictionary*) castOrderedSet:(NSOrderedSet*)set session:(id)sessionId exParam:(ASFKExecutionParams*)ex; -/*! - @brief Performs non-blocking call with unordered set of data and invokes stored Summary block with result. - @param set unordered set of data. - @return dictionary that includes result of execution followed by additional information. - */ --(NSDictionary*) castUnorderedSet:(NSSet*)set session:(id)sessionId exParam:(ASFKExecutionParams*)ex; -/*! - @brief Performs non-blocking call with dictionary of data and invokes stored Summary block with result. - @param uns unspecified piece of data. - @return dictionary that includes result of execution followed by additional information. - */ --(NSDictionary*) castObject:(id)uns session:(id)sessionId exParam:(ASFKExecutionParams*)ex; -@end - -@interface ASFKLinearFlow : ASFKBase{ - @protected NSMutableArray * _backprocs; - @protected NSArray *lfProcs; - @protected ASFKExecutableRoutineSummary sumProc; - @protected ASFKOnPauseNotification onPauseProc; - @protected ASFKCancellationRoutine cancellationHandler; - @protected dispatch_semaphore_t semHighLevelCall; -} --(NSArray *) getRoutines; --(NSUInteger) getRoutinesCount; --(ASFKExecutableRoutineSummary) getSummaryRoutine; --(ASFKCancellationRoutine) getCancellationHandler; - -/*! - @brief Equals NO if sender is updating stored Routines; YES otherwise. - */ --(BOOL) isReady; - -/** - @brief Appends block which invokes Objective-C code; the block is added to internal collection. This operation may succeed only if no Routine is active at time of addition. - @param proc block that processes a data. - */ --(BOOL) addRoutine:(ASFKExecutableRoutine)proc; - -/** - @brief Stores array of Routines for later use; content of array is copied and added to internal collection. - This operation may succeed only if no Routine is active at time of addition. - @param procs new array of Routines. - @return YES if operation succeeded; NO otherwise; - */ --(BOOL) addRoutines:(NSArray*)procs; - -/** - @brief Replaces existing collection of Routines with new one. This operation may succeed only if no Routine is active at time of addition. - @param procs new array of Routines. If aray is empty or nil, nothing happens. - @return YES if operation succeeded; NO otherwise. - */ --(BOOL) replaceRoutinesFromArray:(NSArray*)procs; - -/** - @brief Stores summary block which invokes Objective-C code - @param summary block that is called after all Routines. - */ --(BOOL) setSummary:(ASFKExecutableRoutineSummary)summary; --(BOOL) setOnPauseNotification:(ASFKOnPauseNotification)notification; -/** - @brief Stores block which invokes Objective-C code as a summary for cancelled session. - @param ch block that is called in case of cancellation. - */ --(BOOL) setCancellationHandler:(ASFKCancellationRoutine)ch; - -@end -#endif /* ASFKLinearFlow_h */ diff --git a/src/ASFKLinearFlow.mm b/src/ASFKLinearFlow.mm index 9aa40ee..7983ea6 100644 --- a/src/ASFKLinearFlow.mm +++ b/src/ASFKLinearFlow.mm @@ -1,32 +1,16 @@ -/* - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ - -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// +// ASFKLinearFlow.m +// Async +// +// Created by bv on 19/10/2022. +// Copyright © 2022 bv. All rights reserved. // #import "ASFKBase.h" -#import "ASFKBase+Statistics.h" -#import "ASFKLinearFlow+Internal.h" -#import "ASFKBase+Internal.h" -#include -@interface ASFKLinearFlow() -@end -@implementation ASFKLinearFlow{ - std::atomic itsIsReady; -} +@implementation ASFKLinearFlow +{} + -(id)init{ self=[super init]; if(self){ @@ -41,322 +25,86 @@ -(id)initWithName:(NSString*)name{ } return self; } --(void)_initLF{ - itsIsReady=YES; - _backprocs=[[NSMutableArray alloc]init]; - lfProcs=_backprocs; - sumProc=(id)^(id controlBlock,NSDictionary* stats,id data){ - ASFKLog(@"ASFKLinearFlow: Stub summary"); - return data; - }; - cancellationHandler=nil; - progressProc=nil; - semHighLevelCall=dispatch_semaphore_create(1); -} --(NSUInteger) getRoutinesCount{ - [lkNonLocal lock]; - NSUInteger count=[lfProcs count]; - [lkNonLocal unlock]; - return count; -} --(NSArray *) getRoutines{ - [lkNonLocal lock]; - NSMutableArray * a=[NSMutableArray array]; - for (ASFKExecutableRoutine p in lfProcs) { - [a addObject:[p copy]]; - } - [lkNonLocal unlock]; - return a; -} --(ASFKExecutableRoutineSummary) getSummaryRoutine{ - [lkNonLocal lock]; - ASFKExecutableRoutineSummary c=sumProc; - [lkNonLocal unlock]; - return c; -} --(ASFKCancellationRoutine) getCancellationHandler{ - [lkNonLocal lock]; - ASFKCancellationRoutine c=cancellationHandler; - [lkNonLocal unlock]; - return c; -} --(ASFKProgressRoutine) getProgressRoutine{ - [lkNonLocal lock]; - ASFKProgressRoutine p=progressProc; - [lkNonLocal unlock]; - return p; -} --(BOOL) setProgressRoutine:(ASFKProgressRoutine)pro{ - if(pro){ - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - itsIsReady=NO; - [lkNonLocal lock]; - progressProc=nil; - progressProc=pro; - [lkNonLocal unlock]; - itsIsReady=YES; - dispatch_semaphore_signal(semHighLevelCall); - }else{ - EASFKLog(@"ASFKLinearFlow: Invalid Progress Handler provided"); - return NO; - } - return YES; -} --(BOOL) addRoutine:(ASFKExecutableRoutine)proc{ - if(proc){ - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - itsIsReady=NO; - [lkNonLocal lock]; - [_backprocs addObject:proc]; - [lkNonLocal unlock]; - itsIsReady=YES; - dispatch_semaphore_signal(semHighLevelCall); - }else{ - EASFKLog(@"ASFKLinearFlow: Invalid Routine provided"); - return NO; - } - - return YES; -} --(BOOL) addRoutines:(NSArray*)procs{ - if(procs && [procs count]>0){ - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - itsIsReady=NO; - [lkNonLocal lock]; - [_backprocs addObjectsFromArray:procs]; - [lkNonLocal unlock]; - itsIsReady=YES; - dispatch_semaphore_signal(semHighLevelCall); - }else{ - EASFKLog(@"ASFKLinearFlow: Invalid Routine(s) provided"); - return NO; - } - return YES; -} --(BOOL) replaceRoutinesFromArray:(NSArray*)someprocs{ - BOOL replaced=NO; - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - itsIsReady=NO; - [lkNonLocal lock]; - [_backprocs removeAllObjects]; - if(someprocs && [someprocs count]>0){ - [_backprocs addObjectsFromArray:someprocs]; - replaced=YES; - } - [lkNonLocal unlock]; - itsIsReady=YES; - dispatch_semaphore_signal(semHighLevelCall); - if(replaced==NO){ - WASFKLog(@"ASFKLinearFlow: Routines were removed"); - } - return replaced; -} --(BOOL) isReady{ - return itsIsReady; +-(void) _initLF { + } --(BOOL) setOnPauseNotification:(ASFKOnPauseNotification)notification{ - if(notification){ - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - itsIsReady=NO; - [lkNonLocal lock]; - onPauseProc=notification; - [lkNonLocal unlock]; - itsIsReady=YES; - dispatch_semaphore_signal(semHighLevelCall); - } - else{ - EASFKLog(@"ASFKLinearFlow: Invalid Routine provided"); - return NO; - } - return YES; +#pragma mark - Asynchronous API +-(BOOL) castArray:(NSArray*)array exParams:(ASFKExecutionParams*)ex{ + EASFKLog(ASFK_STR_WRONG_METHOD_CALL); + return NO; } --(BOOL) setSummary:(ASFKExecutableRoutineSummary)summary{ - if(summary){ - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - itsIsReady=NO; - [lkNonLocal lock]; - sumProc=nil; - sumProc=summary; - [lkNonLocal unlock]; - itsIsReady=YES; - dispatch_semaphore_signal(semHighLevelCall); - }else{ - EASFKLog(@"ASFKLinearFlow: Invalid Routine provided"); - return NO; - } - return YES; + +-(BOOL) castDictionary:(NSDictionary*)dictionary exParams:(ASFKExecutionParams*)ex{ + EASFKLog(ASFK_STR_WRONG_METHOD_CALL); + return NO; } --(BOOL) setCancellationHandler:(ASFKCancellationRoutine)ch{ - if(ch){ - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - itsIsReady=NO; - [lkNonLocal lock]; - cancellationHandler=nil; - cancellationHandler=ch; - [lkNonLocal unlock]; - itsIsReady=YES; - dispatch_semaphore_signal(semHighLevelCall); - } - else{ - EASFKLog(@"ASFKLinearFlow: Invalid Cancellation Handler provided"); - return NO; - } - return YES; + +-(BOOL) castOrderedSet:(NSOrderedSet*)set exParams:(ASFKExecutionParams*)ex{ + EASFKLog(ASFK_STR_WRONG_METHOD_CALL); + return NO; } -#pragma mark - Non-blocking methods --(NSDictionary*) castOrderedSet:(NSOrderedSet*)set session:(id)sessionId exParam:(ASFKExecutionParams*)ex{ - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - ASFKParamSet* params=[ASFKParamSet new]; - params.sessionId=sessionId; - params=[self _convertInputOrderedSet:set to:params]; - dispatch_semaphore_signal(semHighLevelCall); - NSDictionary* res= [self _castOrderedSet:params]; - - return res; +-(BOOL) castArray:(NSArray*)array groupBy:(NSUInteger) grpSize exParams:(ASFKExecutionParams*)ex{ + EASFKLog(ASFK_STR_WRONG_METHOD_CALL); + return NO; } --(NSDictionary*) castUnorderedSet:(NSSet*)set session:(id)sessionId exParam:(ASFKExecutionParams*)ex{ - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - ASFKParamSet* params=[ASFKParamSet new]; - params.sessionId=sessionId; - params=[self _convertInputUnorderedSet:set to:params]; - dispatch_semaphore_signal(semHighLevelCall); - NSDictionary* res= [self _castUnorderedSet:params]; - - return res; +-(BOOL) castArray:(NSArray*)array splitTo:(NSUInteger) numOfChunks exParams:(ASFKExecutionParams*)ex{ + EASFKLog(ASFK_STR_WRONG_METHOD_CALL); + return NO; } --(NSDictionary*) castArray:(NSArray*)array session:(id)sessionId exParam:(ASFKExecutionParams*)ex{ - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - ASFKParamSet* params=[ASFKParamSet new]; - params.sessionId=sessionId; - params=[self _convertInputArray:array to:params]; - dispatch_semaphore_signal(semHighLevelCall); - - NSDictionary* res= [self _castArray:params]; - - return res; +-(BOOL) castUnorderedSet:(NSSet*)set exParams:(ASFKExecutionParams*)ex{ + EASFKLog(ASFK_STR_WRONG_METHOD_CALL); + return NO; } --(NSDictionary*) castDictionary:(NSDictionary*)dictionary session:(id)sessionId exParam:(ASFKExecutionParams*)ex{ - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - ASFKParamSet* params=[ASFKParamSet new]; - params.sessionId=sessionId; - params=[self _convertInputDictionary:dictionary to:params]; - dispatch_semaphore_signal(semHighLevelCall); - NSDictionary* res= [self _castDictionary:params]; - - return res; + +-(BOOL) castObject:(id)uns exParams:(ASFKExecutionParams*)ex{ + EASFKLog(ASFK_STR_WRONG_METHOD_CALL); + return NO; } --(NSDictionary*) castObject:(id)uns session:(id)sessionId exParam:(ASFKExecutionParams*)ex{ - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - ASFKParamSet* params=[ASFKParamSet new]; - params.sessionId=sessionId; - params=[self _convertInput:uns to:params]; - dispatch_semaphore_signal(semHighLevelCall); - NSDictionary* res= [self _castArray:params]; - return res; +#pragma mark - Synchronous API +-(BOOL) callArray:(NSArray*)array exParams:(ASFKExecutionParams*)params{ + EASFKLog(ASFK_STR_WRONG_METHOD_CALL); + return NO; } -#pragma mark - Blocking methods --(NSDictionary*) callOrderedSet:(NSOrderedSet*)set session:(id)sessionId exParam:(ASFKExecutionParams*)ex{ - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - ASFKParamSet* params=[ASFKParamSet new]; - params.sessionId=sessionId; - params=[self _convertInputOrderedSet:set to:params]; - dispatch_semaphore_signal(semHighLevelCall); - NSDictionary* res= [self _callOrderedSet:params]; - - return res; +-(BOOL) callArray:(NSArray*)array groupBy:(NSUInteger) grpSize exParams:(ASFKExecutionParams*)ex{ + EASFKLog(ASFK_STR_WRONG_METHOD_CALL); + return NO; } --(NSDictionary*) callUnorderedSet:(NSSet*)set session:(id)sessionId exParam:(ASFKExecutionParams*)ex{ - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - ASFKParamSet* params=[ASFKParamSet new]; - params.sessionId=sessionId; - params=[self _convertInputUnorderedSet:set to:params]; - dispatch_semaphore_signal(semHighLevelCall); - - NSDictionary* res= [self _callUnorderedSet:params]; - - return res; +-(BOOL) callArray:(NSArray*)array splitTo:(NSUInteger) numOfChunks exParams:(ASFKExecutionParams*)ex{ + EASFKLog(ASFK_STR_WRONG_METHOD_CALL); + return NO; } --(NSDictionary*) callArray:(NSArray*)array session:(id)sessionId exParam:(ASFKExecutionParams*)ex{ - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - ASFKParamSet* params=[ASFKParamSet new]; - params.sessionId=sessionId; - params=[self _convertInputArray:array to:params]; - dispatch_semaphore_signal(semHighLevelCall); - NSDictionary* res= [self _callArray:params]; - - return res; +-(BOOL) callDictionary:(NSDictionary*)dictionary exParams:(ASFKExecutionParams*)ex{ + EASFKLog(ASFK_STR_WRONG_METHOD_CALL); + return NO; } --(NSDictionary*) callDictionary:(NSDictionary*)dictionary session:(id)sessionId exParam:(ASFKExecutionParams*)ex{ - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - ASFKParamSet* params=[ASFKParamSet new]; - params.sessionId=sessionId; - params=[self _convertInputDictionary:dictionary to:params]; - dispatch_semaphore_signal(semHighLevelCall); - NSDictionary* res= [self _callDictionary:params]; - return res; +-(BOOL) callOrderedSet:(NSOrderedSet*)set exParams:(ASFKExecutionParams*)ex{ + EASFKLog(ASFK_STR_WRONG_METHOD_CALL); + return NO; } --(NSDictionary*) callObject:(id)uns session:(id)sessionId exParam:(ASFKExecutionParams*)ex{ - dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - ASFKParamSet* params=[ASFKParamSet new]; - params.sessionId=sessionId; - params=[self _convertInput:uns to:params]; - dispatch_semaphore_signal(semHighLevelCall); - NSDictionary* res= [self _callArray:params]; - return res; -} -- (NSDictionary *)stepBlockingWithData:(id)data { - NSDictionary* result=nil; - if([data isKindOfClass:[NSDictionary class]]){ - result=[self callDictionary:data session:nil exParam:nil]; - }else if([data isKindOfClass:[NSArray class]]){ - result=[self callArray:data session:nil exParam:nil]; - }else{ - result=[self callObject:data session:nil exParam:nil]; - } - return result; +-(BOOL) callUnorderedSet:(NSSet*)set exParams:(ASFKExecutionParams*)ex{ + EASFKLog(ASFK_STR_WRONG_METHOD_CALL); + return NO; } -- (NSDictionary *)stepNonblockingWithData:(id)data { - NSDictionary* result=nil; - if([data isKindOfClass:[NSDictionary class]]){ - //result=[self castDictionary:data exParam:nil]; - }else if([data isKindOfClass:[NSArray class]]){ - //result=[self castArray:data exParam:nil]; - }else{ - //result=[self castObject:data exParam:nil]; - } - return result; + +-(BOOL) callObject:(id)uns exParams:(ASFKExecutionParams*)ex{ + EASFKLog(ASFK_STR_WRONG_METHOD_CALL); + return NO; } -#pragma mark - private methods --(ASFKParamSet*) _decodeExParams:(ASFKExecutionParams*)ex forSession:(id)sessionId{ - ASFKParamSet* expar=[ASFKParamSet new]; - if(ex){ - expar.summary = ex->summaryRoutine?ex->summaryRoutine:sumProc; - expar.procs = [NSMutableArray array]; - NSArray* prarr=ex->procs; - if(prarr==nil || [prarr count]==0 || [prarr isKindOfClass:[NSNull class]]){ - prarr=_backprocs; - } - for (ASFKExecutableRoutine p in prarr){ - [expar.procs addObject:[p copy]]; - }; - expar.onPause = ex->onPauseProc?ex->onPauseProc:onPauseProc; - expar.cancProc = ex->cancellationProc?ex->cancellationProc:cancellationHandler; - expar.excond=ex->expCondition; - expar.progress = ex->progressProc?ex->progressProc:progressProc; - expar.sessionId=sessionId; - } - return expar; +-(id) pull{ + EASFKLog(ASFK_STR_WRONG_METHOD_CALL); + return nil; } + @end diff --git a/src/ASFKMBProperties.h b/src/ASFKMBProperties.h deleted file mode 100644 index 2e5263d..0000000 --- a/src/ASFKMBProperties.h +++ /dev/null @@ -1,265 +0,0 @@ -/* -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. -// - -#import -#import "ASFKExpirationCondition.h" -#include - -typedef void(^ASFKMbNRunOnContainerReadRoutine)(id cId,NSDate* tstamp, NSArray* data); -/*! - @brief custom filter of incoming messages. - @discussion custom Routine that filters accepted messages. User can review all accepted messages and select some subset to be removed. After this call ended, the selected messages will be removed from collection. - @param cId group/mailbox ID. - @param msgs ordered set of accepted messages. - @param stop indication provided by user that filtering should be stopped. - @param lock reference to synchronization primitive. Must be used when the collection as accessed. - */ -typedef BOOL(^ASFKMbContainerFilteringRoutine)(id cId,NSOrderedSet* msgs, BOOL* stop, id lock); -typedef void(^ASFKMbNotifyOnContainerJoinRoutine)(id cId, id guestId); -typedef void(^ASFKMbNotifyOnContainerLeaveRoutine)(id cId, id guestId); -typedef void(^ASFKMbNotifyOnContainerDiscardRoutine)(id cId,NSDate* tstamp); - -/*! - @brief notification on incoming messages. - @discussion custom Routine that notifies user about incoming message. - @param cId group/user ID. - @param newMsgCount up-to-date message count. - */ -typedef void(^ASFKMbNotifyOnNewMsgRoutine)(id cId, NSUInteger newMsgCount); -typedef void(^ASFKMbNotifyOnContainerPopRoutine)(id cId,NSArray* popped,NSUInteger left); -typedef void(^ASFKMbNotifyOnContainerReadRoutine)(id cId,NSArray* read,NSUInteger total); -typedef void(^ASFKMbMsgFeedbackProc)(id cId, NSDate* timepoint, id msg); -#pragma mark - Null Properties -@interface ASFKMBPropertiesNull:NSObject -@end -#pragma mark - Group Member Props -@interface ASFKMBGroupMemberProperties :NSObject --(void) initFromProps:(ASFKMBGroupMemberProperties*)p; -/*! - @brief Indication that user should be prevented from reading messages delivered to group. YES for confirmation. - @discussion Is ignored when applied to owner of group. Explicit setting of this property will have no effect. - */ -@property (nonatomic) BOOL isBlinded; -/*! - @brief Indication that user should be prevented from delivering messages to group. YES for confirmation. - @discussion Is ignored when applied to owner of group. Explicit setting of this property will have no effect. - */ -@property (nonatomic) BOOL isMuted; - -/*! - @brief Date at which a Group Member will leave group automatically. Nil is ignored. - */ -//@property (nonatomic,readonly) NSDate* leaveOnDate; -/*! - @brief Group membership duration, greater than zero. After this period member will automatically leave the group. Negative value ignored. - */ -@property (nonatomic,readonly) ASFKConditionTemporal* grpMemLeaveTimer; -/*! - @brief set Group membership leaving date. Nil or date lesser than or equal to current time lead to invalidation of underlying properties. - @param date leaving date to set. - */ --(void) setPropLeaveOnDate:(NSDate *)date; -/*! - @brief set Group membership duration, greater than zero. Negative/zero value leads to invalidation of underlying properties. - @param seconds time interval to set. - */ --(void) setPropLeaveAfterSeconds:(NSTimeInterval)seconds; -/*! - @param date date to be tested against the 'leaveOnDate' property. - @return YES if 'date' is before 'leaveOnDate' property; NO otherwise. - */ --(BOOL) passedLeavingDate:(NSDate *)date; -@end -#pragma mark - Group/Container Props -@interface ASFKMBContainerProperties :NSObject --(void) initFromProps:(ASFKMBContainerProperties*)p; -@property ASFKMbNRunOnContainerReadRoutine runOnReadProc; -/*! - @brief Indication of whether addition of new members to a group is allowed. NO for permission. - @discussion When applied to standalone mailbox, no effect expected. - */ -@property BOOL isPrivate; -/*! - @brief Indication of whether this container permits blocking Read/Write operations. YES for permission. - @discussion When applied to standalone mailbox, no effect expected. - */ -@property BOOL blockingReadwriteAllowed; -/*! - @brief Indication of whether a standalone user can join another group. YES for permission. - @discussion When applied to a group, no effect expected. - */ -@property BOOL isInvitable; -/*! - @brief Indication that group container should not accept posts while is not populated; YES for confirmation. Is ignored for single user container. - */ -@property (nonatomic) BOOL noPostUnpopulatedGroup; -/*! - @brief defines if user list of some group may be used for operations like group cloning, sendToMembers operation or set operations. YES for no sharing, NO otherwise. - */ -@property (nonatomic) BOOL noUserListSharing; -/*! - @brief indication whether anonimous posting is allowed. YES for confirmation, NO otherwise. - @discussion anonymous is any message that is accompanied with author ID set to nil. - */ -@property (nonatomic) BOOL anonimousPostingAllowed; -@property (nonatomic) BOOL retractionAllowed; -/*! - @brief Container Deletion Timer. If set, provides that the container will be deleted upon expiration. - */ -@property (nonatomic,readonly) ASFKConditionTemporal* containerDeleteTimer; -/*! - @brief Container Kickout Timer. If set, provides that any user, except the owner will be removed from the container upon timer expiration. - */ -@property (nonatomic,readonly) ASFKConditionTemporal* containerKickoutTimer; -/*! - @brief Container Drop Message Timer. If set, provides that messages older than established delay will be removed from the container. - */ -@property (nonatomic,readonly) ASFKConditionTemporal* containerDropMsgTimer; -@property ASFKMbContainerFilteringRoutine containerFilterProc; -@property ASFKMbNotifyOnContainerDiscardRoutine onDiscardProc; -@property ASFKMbNotifyOnNewMsgRoutine onNewMsgProc; -@property ASFKMbNotifyOnContainerPopRoutine onPopProc; -@property ASFKMbNotifyOnContainerReadRoutine onReadProc; -@property ASFKMbNotifyOnContainerJoinRoutine onJoinProc; -@property ASFKMbNotifyOnContainerLeaveRoutine onLeaveProc; -@property ASFKMbMsgFeedbackProc feedbackProc; - --(void) setPropMsgCustomCondition:(ASFKCondition*)msgCustomCond; -/*! - @brief set User/Group deletion date. Nil or date lesser than or equal to current time lead to invalidation of underlying properties Nil means that deletion will not happen. - @param date termination date to set. - */ --(void) setPropDeleteOnDate:(NSDate *)date; --(void) setPropDropMsgOnDate:(NSDate *)date; --(void) setPropKickoutOnDate:(NSDate *)date; -/*! - @brief User/Group lifetime, greater than zero. After this period it will be automatically destroyed. Negative value will invalidate underlying properties, deletion will not happen. - @param seconds time left to termination. - */ --(void) setPropDeleteAfterSeconds:(NSTimeInterval)seconds; -/*! - @brief Group member's lifetime, greater than zero. After this period it will be automatically removed from group. Negative value will invalidate underlying properties, kickout will not happen. - @param seconds time left to termination. - */ --(void) setPropKickoutAfterSeconds:(NSTimeInterval)seconds; -/*! - @brief Delivered message's lifetime, greater than zero. After this period it will be automatically destroyed. Negative value will invalidate underlying properties, kickout will not happen. - @param seconds time left to termination. - */ --(void) setPropDropMsgAfterSeconds:(NSTimeInterval)seconds; -/*! - @param date date to be tested against the 'deleteOnDate' property. - @return YES if 'date' is before 'deleteOnDate' property; NO otherwise. - */ --(BOOL) passedDeletionDate:(NSDate *)date; --(BOOL) passedKickoutDate:(NSDate *)date; --(BOOL) passedDropMsgDate:(NSDate *)date; -@end -#pragma mark - Message Props -@interface ASFKMBMsgProperties:NSObject{ - /*! - @brief maximum number of reading attempts. Decreases on each attempt. When value is zero, the message will not be available for reading, and deleted. By default set to positive maximum. - */ - @public std::atomic maxAccessLimit; -} --(void) initFromProps:(ASFKMBMsgProperties*)p; -@property BOOL blocking; -/*! - @brief Date at which a Message will be destroyed automatically. Nil is ignored. - @discussion if in container exists ASFKMBContainerProperties object and it defines deletion date for messages, then the earliest date will be picked. - */ -@property (nonatomic,readonly) ASFKConditionTemporal* msgDeletionTimer; -/*! - @brief When applied to message, indicates that it may be retracted from Group/User before the specified date only. Nil date is ignored. - */ -@property (nonatomic,readonly) ASFKConditionTemporal* msgRetractionTimer; -/*! - @brief When applied to message, indicates that it may be read from Group/User after the specified date only. Nil date is ignored. - */ -@property (nonatomic,readonly) ASFKConditionTemporal* msgReadabilityTimer; - -/*! - @brief user id of message poster. Nil is interpreted as anonimous posting. - */ -@property (nonatomic,readonly) id msgAuthorId; -/*! - @brief unique id of message. Nil is ignored. - */ -@property (nonatomic,readonly) NSUUID* msgId; -/*! - @param date date to be tested. - @return YES if 'date' is earlier than setting of 'msgRetractionTimer' property; NO otherwise. - */ --(BOOL) passedRetractionDate:(NSDate *)date; -/*! - @param date date to be tested.. - @return YES if 'date' is earlier than setting of 'msgReadabilityTimer' property; NO otherwise. - */ --(BOOL) passedReadingDate:(NSDate *)date; -/*! - @param date date to be tested. - @return YES if 'date' is earlier than setting of 'msgDeletionTimer' property; NO otherwise. - */ --(BOOL) passedDeletionDate:(NSDate *)date; -/*! - @brief set message deletion date. After this period it will be automatically destroyed. Nil value will invalidate underlying properties. - @param date date when message must be terminated, if not read. - */ --(void) setPropDeleteOnDate:(NSDate *)date; -/*! - @brief set message termination date. Message can be read only before that date passed. - @param seconds delay before message's termination. - */ --(void) setPropDeleteAfterSeconds:(NSTimeInterval)seconds; -/*! - @brief set message reading date. Message can be read only after that date passed. - @param date date when message would be available for reading. - */ --(void) setPropReadOnDate:(NSDate *)date; -/*! - @brief set message reading delay. Message can be read only after that delay elapsed. - @param seconds delay before the message would be available for reading. - */ --(void) setPropReadAfterSeconds:(NSTimeInterval)seconds; -/*! - @brief set time period, during which message may be retracted. - @param msgRetractInSeconds time left to retraction, unless popped. - */ --(void) setPropMsgRetractInSeconds:(NSTimeInterval)msgRetractInSeconds; -/*! - @brief set date, until which the message could be retracted. - @param msgRetractBeforeDate last date of retraction, unless deleted in other way. - */ --(void) setPropMsgRetractBeforeDate:(NSDate *)msgRetractBeforeDate; -/*! - @brief set maximum number of reading attempts. - @param limit number of times the message can be accessed. - */ --(void) setPropMsgMaxReadLimit:(NSUInteger)limit; -/*! - @brief set message's identifier. - @param msgId identifier. - */ --(void) setPropMsgId:(NSUUID *)msgId; -/*! - @brief set identifier of message's issuer. - @param msgAuthorId issuer's identifier. - */ --(void) setPropMsgAuthorId:(id)msgAuthorId; -@end - -typedef void(^ASFKMbCallReleaseRoutine)(); diff --git a/src/ASFKMBProperties.mm b/src/ASFKMBProperties.mm index a5ce7d3..4b4a5cc 100644 --- a/src/ASFKMBProperties.mm +++ b/src/ASFKMBProperties.mm @@ -13,10 +13,9 @@ along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase.h" -#import "ASFKMBProperties.h" #pragma mark - Group member @implementation ASFKMBGroupMemberProperties @@ -160,7 +159,6 @@ -(id)init{ self.onJoinProc=nil; self.onLeaveProc=nil; self.onDiscardProc=nil; - self.feedbackProc=nil; self.runOnReadProc=nil; _containerDeleteTimer=[ASFKConditionTemporal new]; _containerKickoutTimer=[ASFKConditionTemporal new]; diff --git a/src/ASFKMBSecret.h b/src/ASFKMBSecret.h deleted file mode 100644 index 89a39b0..0000000 --- a/src/ASFKMBSecret.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. -// - -#import -#import "ASFKExpirationCondition.h" -@class ASFKSecret; -/* - Secrets are objects used to authorize operations; When API call invoked and secret is provided, it is tested against some other stored secret; if both secrets match, the operation is allowed. - Secrets are organized by types and roles. There are 3 types: Master, Private and Group. Master secret is single, global and can affect all mailboxes. Private/Group may affect only specific mailbox; Private secret should be created and used by mailbox owners only, while Group secret may be used by owner and group members. - Each secret may play different roles, while some roles are disabled for different secret types. - Available Roles: Private Group Master - 1. creation of group mailbox x - by cloning or set operation - 2. Reading x x - 3. Popping x x - 4. Discarding of mailboxes and groups x x - 5. unicast x x x - 6. multicast x x x - 7. moderation - blinding/muting of members x x - 8. security - changing secrets for Mailbox, Group, Global x x - 9. issuer - retraction/hiding of posted messages x x - 10. config - update of mailbox operational parameters x - 11. hosting - addition/removal of members to/from Group mailbox x x - - Secrets lifetime and configuration: - All secrets have unlimited lifetime by default, which however can be configured to be temporary: for limited time period, limited number of use attempts or custom lifetime shortening criteria. When lifetime is ended the secret is invalidated forever. Manual invalidation is available too. - Any secret may be configured to have different properties. Any property may be configured only once. - */ - -typedef BOOL(^ASFKSecretComparisonProc)(id secret1,id secret2); -/*! - @brief Declaration of generic secret entity. - @discussion secrets are associated with containers and tested each time the container is accessed using high-level API. - */ -@interface ASFKSecret :NSObject{ -@private - id _secretModerator; - id _secretUnicaster; - id _secretMulticaster; - id _secretPopper; - id _secretReader; - id _secretDiscarder; - id _secretCreator; - id _secretSecurity; - id _secretConfigurer; - id _secretHost; - id _secretIssuer; -} -@property (readonly) ASFKConditionTemporal* timerExpiration; --(BOOL) matchesUnicasterSecret:(ASFKSecret*)secret; --(BOOL) matchesMulticasterSecret:(ASFKSecret*)secret; --(BOOL) matchesReaderSecret:(ASFKSecret*)secret; --(BOOL) matchesPopperSecret:(ASFKSecret*)secret; --(BOOL) matchesDiscarderSecret:(ASFKSecret*)secret; --(BOOL) matchesCreatorSecret:(ASFKSecret*)secret; --(BOOL) matchesModeratorSecret:(ASFKSecret*)secret; --(BOOL) matchesHostSecret:(ASFKSecret*)secret; --(BOOL) matchesIssuerSecret:(ASFKSecret*)secret; --(BOOL) matchesConfigSecret:(ASFKSecret*)secret; --(BOOL) matchesSecuritySecret:(ASFKSecret*)secret; - --(BOOL) setMulticasterSecretOnce:(id)secret; --(BOOL) setUnicasterSecretOnce:(id)secret; --(BOOL) setReaderSecretOnce:(id)secret; --(BOOL) setPopperSecretOnce:(id)secret; --(BOOL) setDiscarderSecretOnce:(id)secret; --(BOOL) setCreatorSecretOnce:(id)secret; --(BOOL) setModeratorSecretOnce:(id)secret; --(BOOL) setIssuerSecretOnce:(id)secret; --(BOOL) setHostSecretOnce:(id)secret; --(BOOL) setConfigSecretOnce:(id)secret; --(BOOL) setSecuritySecretOnce:(id)secret; - --(BOOL) setUnicasterSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; --(BOOL) setMulticasterSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; --(BOOL) setCreatorSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; --(BOOL) setDiscarderSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; --(BOOL) setModeratorSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; --(BOOL) setIssuerSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; --(BOOL) setConfigSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; --(BOOL) setSecuritySecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; --(BOOL) setReaderSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; --(BOOL) setPopperSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; --(BOOL) setHostSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc; - --(void) invalidateUnicasterSecret; --(void) invalidateMulticasterSecret; --(void) invalidateReaderSecret; --(void) invalidatePopperSecret; --(void) invalidateDiscarderSecret; --(void) invalidateCreatorSecret; --(void) invalidateModeratorSecret; --(void) invalidateSecuritySecret; --(void) invalidateIssuerSecret; --(void) invalidateConfigSecret; --(void) invalidateHostSecret; --(void) invalidateAll; --(BOOL) validSecretModerator; --(BOOL) validSecretCreator; --(BOOL) validSecretDiscarder; --(BOOL) validSecretUnicaster; --(BOOL) validSecretMulticaster; --(BOOL) validSecretPopper; --(BOOL) validSecretReader; --(BOOL) validSecretHost; --(BOOL) validSecretSecurity; --(BOOL) validSecretConfig; --(BOOL) validSecretIssuer; --(BOOL) setExpirationDateOnce:(NSDate*)aDate; --(BOOL) setExpirationDelayOnce:(NSTimeInterval) sec; --(BOOL) passedExpirationDeadline:(NSDate*)deadline; --(BOOL) setMaxUsageCountOnce:(NSInteger)maxCount; --(BOOL) passedMaxUsageCount; -@end -/*! - @brief Declaration of master secret entity. - @discussion If applied to container having private secret - the private secret is overriden if master secret is valid and non-nil. Roles available for master key: purging of maibox, deletion of mailbox, messages and users; setting of master secret; unicast, broadcast and multicast. Master secret may not be used for moderation, reading. - */ -@interface ASFKMasterSecret :ASFKSecret - -@end -/*! - @brief Declaration of private secret entity. - @discussion only container's owner having private secret may use it. Roles available for private secret: purging of mailbox; creation of private mailbox; reading and popping; moderation - muting, blinding and so on; unicast, broadcast and multicast. - */ -@interface ASFKPrivateSecret :ASFKSecret - -@end -/*! - @brief Declaration of group secret entity. - @discussion only group owner and group members may use it. Roles available for group secret: purging of mailbox; reading and popping; moderation - muting, blinding and so on. - */ -@interface ASFKGroupSecret :ASFKPrivateSecret - -@end - diff --git a/src/ASFKMBSecret.mm b/src/ASFKMBSecret.mm index feb94d9..6fe5c88 100644 --- a/src/ASFKMBSecret.mm +++ b/src/ASFKMBSecret.mm @@ -12,10 +12,10 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase.h" -#import "ASFKMBSecret.h" + #include @interface ASFK_PrivSecretItem:NSObject{ @public std::atomic secretSet; @@ -74,6 +74,7 @@ @implementation ASFKSecret{ ASFK_PrivSecretItem* psiModerator; ASFK_PrivSecretItem* psiMulticaster; + ASFK_PrivSecretItem* psiBroadcaster; ASFK_PrivSecretItem* psiUnicaster; ASFK_PrivSecretItem* psiReader; ASFK_PrivSecretItem* psiPopper; @@ -99,6 +100,7 @@ -(id) init{ psiConfig=[ASFK_PrivSecretItem new]; psiUnicaster=[ASFK_PrivSecretItem new]; psiMulticaster=[ASFK_PrivSecretItem new]; + psiBroadcaster=[ASFK_PrivSecretItem new]; psiReader=[ASFK_PrivSecretItem new]; psiPopper=[ASFK_PrivSecretItem new]; psiCreator=[ASFK_PrivSecretItem new]; @@ -135,6 +137,18 @@ -(BOOL) setMulticasterSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc } return NO; } +-(BOOL) setBroadcasterSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc{ + if(cmpproc==nil){ + return NO; + } + BOOL tval=NO; + if(psiBroadcaster->secretCmpSet.compare_exchange_strong(tval,YES)) + { + psiBroadcaster->secretCmpProc=cmpproc; + return YES; + } + return NO; +} -(BOOL) setCreatorSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc{ if(cmpproc==nil){ return NO; @@ -312,6 +326,17 @@ -(BOOL) matchesMulticasterSecret:(ASFKSecret*)secret{ } return [psiMulticaster matchSecretHost:_secretMulticaster secretGuest:secret->_secretMulticaster usageCount:itsUsageCount]; } +-(BOOL) matchesBroadcasterSecret:(ASFKSecret*)secret{ + if(!psiBroadcaster->secretValid || secret==nil){ + return NO; + } + + if([self passedExpirationDeadline:[NSDate date]] || itsUsageCount<1){ + [self invalidateBroadcasterSecret]; + return NO; + } + return [psiBroadcaster matchSecretHost:_secretBroadcaster secretGuest:secret->_secretBroadcaster usageCount:itsUsageCount]; +} -(BOOL) matchesSecuritySecret:(ASFKSecret*)secret{ if(!psiSecurity->secretValid || secret==nil){ return NO; @@ -438,6 +463,17 @@ -(BOOL) setMulticasterSecretOnce:(id)secret{ } return NO; } +-(BOOL) setBroadcasterSecretOnce:(id)secret{ + BOOL tval=NO; + if(psiBroadcaster->secretSet.compare_exchange_strong(tval,YES)) + { + _secretBroadcaster=secret; + DASFKLog(@"ASFKMBSecret: base class called"); + return YES; + + } + return NO; +} -(BOOL) setReaderSecretOnce:(id)secret{ BOOL tval=NO; if(psiReader->secretSet.compare_exchange_strong(tval,YES)) @@ -542,6 +578,9 @@ -(void) invalidateUnicasterSecret{ -(void) invalidateMulticasterSecret{ psiMulticaster->secretValid=NO; } +-(void) invalidateBroadcasterSecret{ + psiBroadcaster->secretValid=NO; +} -(void) invalidateReaderSecret{ psiReader->secretValid=NO; } @@ -584,6 +623,9 @@ -(BOOL) validSecretUnicaster{ -(BOOL) validSecretMulticaster{ return psiMulticaster->secretValid; } +-(BOOL) validSecretBroadcaster{ + return psiBroadcaster->secretValid; +} -(BOOL) validSecretPopper{ return psiPopper->secretValid; } @@ -605,10 +647,10 @@ -(BOOL) validSecretIssuer{ -(BOOL) validSecretModerator{ return psiModerator->secretValid; } - -(void) invalidateAll{ [self invalidateUnicasterSecret]; [self invalidateMulticasterSecret]; + [self invalidateBroadcasterSecret]; [self invalidateReaderSecret]; [self invalidatePopperSecret]; [self invalidateDiscarderSecret]; @@ -622,35 +664,39 @@ -(void) invalidateAll{ -(BOOL) isValidOnDate:(NSDate*)aDate{ return (![self passedExpirationDeadline:aDate]); } --(BOOL) areValidAll{ - return (psiCreator->secretValid&& - psiUnicaster->secretValid&& - psiMulticaster->secretValid&& - psiReader->secretValid&& - psiPopper->secretValid&& - psiDiscarder->secretValid&& - psiHost->secretValid&& - psiSecurity->secretValid&& - psiConfig->secretValid&& - psiModerator->secretValid&& +-(BOOL) validAll{ + return (psiCreator->secretValid && + psiUnicaster->secretValid && + psiMulticaster->secretValid && + psiBroadcaster->secretValid && + psiReader->secretValid && + psiPopper->secretValid && + psiDiscarder->secretValid && + psiHost->secretValid && + psiSecurity->secretValid && + psiConfig->secretValid && + psiModerator->secretValid && psiIssuer->secretValid ); } --(BOOL) isValidAny{ - return ( - psiCreator->secretValid|| - psiUnicaster->secretValid|| - psiMulticaster->secretValid|| - psiReader->secretValid|| - psiPopper->secretValid|| - psiDiscarder->secretValid|| - psiSecurity->secretValid || - psiHost->secretValid || - psiConfig->secretValid|| - psiModerator->secretValid|| +-(BOOL) validAny{ + return (psiCreator->secretValid || + psiUnicaster->secretValid || + psiMulticaster->secretValid || + psiBroadcaster->secretValid || + psiReader->secretValid || + psiPopper->secretValid || + psiDiscarder->secretValid || + psiHost->secretValid || + psiSecurity->secretValid || + psiConfig->secretValid || + psiModerator->secretValid || psiIssuer->secretValid ); } +-(BOOL) validCharacteristic{ + return [self validAll]; +} @end @implementation ASFKMasterSecret @@ -667,7 +713,7 @@ -(id)init{ } return self; } --(BOOL) areValidAll{ +-(BOOL) validCharacteristic{ return ( [self validSecretUnicaster] && [self validSecretMulticaster] @@ -675,14 +721,7 @@ -(BOOL) areValidAll{ && [self validSecretSecurity] ); } --(BOOL) isValidAny{ - return ( - [self validSecretUnicaster] - || [self validSecretMulticaster] - || [self validSecretDiscarder] - || [self validSecretSecurity] - ); -} + -(BOOL) setCreatorSecretOnce:(id)secret{ return NO; } @@ -756,7 +795,7 @@ -(id)init{ } return self; } --(BOOL) areValidAll{ +-(BOOL) validCharacteristic{ return ( [self validSecretReader] && [self validSecretUnicaster] @@ -771,21 +810,6 @@ -(BOOL) areValidAll{ && [self validSecretConfig] ); } --(BOOL) isValidAny{ - return ( - [self validSecretReader] - || [self validSecretUnicaster] - || [self validSecretMulticaster] - || [self validSecretPopper] - || [self validSecretDiscarder] - || [self validSecretSecurity] - || [self validSecretHost] - || [self validSecretModerator] - || [self validSecretCreator] - || [self validSecretIssuer] - || [self validSecretConfig] - ); -} @end @@ -800,10 +824,11 @@ -(id)init{ } return self; } --(BOOL) areValidAll{ +-(BOOL) validCharacteristic{ return ( [self validSecretReader] && [self validSecretMulticaster] + && [self validSecretBroadcaster] && [self validSecretUnicaster] && [self validSecretPopper] && [self validSecretHost] @@ -811,17 +836,66 @@ -(BOOL) areValidAll{ && [self validSecretIssuer] ); } --(BOOL) isValidAny{ - return ( - [self validSecretReader] - || [self validSecretMulticaster] - || [self validSecretUnicaster] - || [self validSecretPopper] - || [self validSecretHost] - || [self validSecretModerator] - || [self validSecretIssuer] - ); + +-(BOOL) setDiscarderSecretOnce:(id)secret{ + return NO; +} +-(BOOL) matchesDiscarderSecret:(ASFKSecret *)secret{ + return NO; +} +-(BOOL) setDiscarderSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc{ + return NO; +} +-(BOOL) setSecuritySecretOnce:(id)secret{ + return NO; +} +-(BOOL) matchesSecuritySecret:(ASFKSecret *)secret{ + return NO; +} +-(BOOL) setSecuritySecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc{ + return NO; +} +-(BOOL) setConfigSecretOnce:(id)secret{ + return NO; +} +-(BOOL) matchesConfigSecret:(ASFKSecret *)secret{ + return NO; +} +-(BOOL) setConfigSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc{ + return NO; +} +-(BOOL) setCreatorSecretOnce:(id)secret{ + return NO; +} +-(BOOL) matchesCreatorSecret:(ASFKSecret *)secret{ + return NO; +} +-(BOOL) setCreatorSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc{ + return NO; +} +@end +@implementation ASFKFloatingSecret +-(id)init{ + self=[super init]; + if(self){ + [self invalidateSecuritySecret]; + [self invalidateConfigSecret]; + [self invalidateDiscarderSecret]; + [self invalidateCreatorSecret]; + [self invalidateHostSecret]; + [self invalidateIssuerSecret]; + [self invalidatePopperSecret]; + [self invalidateReaderSecret]; + [self invalidateModeratorSecret]; + [self invalidateUnicasterSecret]; + [self invalidateMulticasterSecret]; + } + return self; +} +-(BOOL) validCharacteristic{ + return [self validSecretBroadcaster]; } + -(BOOL) setDiscarderSecretOnce:(id)secret{ return NO; } @@ -831,6 +905,7 @@ -(BOOL) matchesDiscarderSecret:(ASFKSecret *)secret{ -(BOOL) setDiscarderSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc{ return NO; } + -(BOOL) setSecuritySecretOnce:(id)secret{ return NO; } @@ -840,6 +915,7 @@ -(BOOL) matchesSecuritySecret:(ASFKSecret *)secret{ -(BOOL) setSecuritySecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc{ return NO; } + -(BOOL) setConfigSecretOnce:(id)secret{ return NO; } @@ -849,6 +925,7 @@ -(BOOL) matchesConfigSecret:(ASFKSecret *)secret{ -(BOOL) setConfigSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc{ return NO; } + -(BOOL) setCreatorSecretOnce:(id)secret{ return NO; } @@ -858,4 +935,64 @@ -(BOOL) matchesCreatorSecret:(ASFKSecret *)secret{ -(BOOL) setCreatorSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc{ return NO; } + +-(BOOL) setReaderSecretOnce:(id)secret{ + return NO; +} +-(BOOL) matchesReaderSecret:(ASFKSecret *)secret{ + return NO; +} +-(BOOL) setReaderSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc{ + return NO; +} + +-(BOOL) setIssuerSecretOnce:(id)secret{ + return NO; +} +-(BOOL) matchesIssuerSecret:(ASFKSecret*)secret{ + return NO; +} +-(BOOL) setIssuerSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc{ + return NO; +} + +-(BOOL) setPopperSecretOnce:(id)secret{ + return NO; +} +-(BOOL) matchesPopperSecret:(ASFKSecret*)secret{ + return NO; +} +-(BOOL) setPopperSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc{ + return NO; +} + +-(BOOL) setUnicasterSecretOnce:(id)secret{ + return NO; +} +-(BOOL) matchesUnicasterSecret:(ASFKSecret*)secret{ + return NO; +} +-(BOOL) setUnicasterSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc{ + return NO; +} + +-(BOOL) setMulticasterSecretOnce:(id)secret{ + return NO; +} +-(BOOL) matchesMulticasterSecret:(ASFKSecret*)secret{ + return NO; +} +-(BOOL) setMulticasterSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc{ + return NO; +} + +-(BOOL) setModeratorSecretOnce:(id)secret{ + return NO; +} +-(BOOL) matchesModeratorSecret:(ASFKSecret*)secret{ + return NO; +} +-(BOOL) setModeratorSecretComparisonProcOnce:(ASFKSecretComparisonProc)cmpproc{ + return NO; +} @end diff --git a/src/ASFKMailbox.h b/src/ASFKMailbox.h index e6a46b8..0ffb278 100644 --- a/src/ASFKMailbox.h +++ b/src/ASFKMailbox.h @@ -12,13 +12,15 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// +// Created by Boris Vigman on 05/04/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #ifndef __A_S_F_K_Mailbox_h__ #define __A_S_F_K_Mailbox_h__ #import -#import "ASFKMBProperties.h" + #import "ASFKBase.h" typedef NSIndexSet* (^clbkASFKMBFilter)(NSArray* collection); typedef void(^ASFKMbMemPressureRoutine)(NSDate* timepoint, NSUInteger objectsCount); @@ -37,16 +39,24 @@ typedef void(^ASFKMbLockConditionRoutine)(id cid, BOOL group, id msgId, id msg); @protected NSMutableDictionary* groups; } -+ (ASFKMailbox *)sharedManager ; ++ (ASFKMailbox *)singleInstance ; #pragma mark - Secret /*! @brief sets master secret. - @discussion some operations require secret to be provided as parameter. Master secret overrides private secret in creation/deletion of group/user, but does not override reading/popping operations. Nil secret means that no secret exists, therefore secret check is skipped. + @discussion some operations require secret to be provided as parameter. Master secret overrides private secret in creation/deletion of group/user, but does not override reading/popping operations. Nil secret means that no secret exists, therefore secret check is skipped. Must fulfill Security role. @param oldsec old master secret; may be nil. @param newsec new master secret; may be nil, in this case master secret will be effectively removed. @return YES for successful setting, NO otherwise. */ - (BOOL)setMasterSecret:(ASFKMasterSecret*)oldsec newSecret:(ASFKMasterSecret*)newsec; +/*! + @brief sets floating secret. + @discussion some operations require secret to be provided as parameter. Floating secret is applied for broadcasting. + @param newsec new floating secret; may be nil, in this case floating secret will be effectively removed. + @param msec master secret; used to authorize this operation. Must fulfill Security role. + @return YES for successful setting, NO otherwise. + */ +- (BOOL)setFloatingSecret:(ASFKFloatingSecret*)newsec authorizeWith:(ASFKMasterSecret*) msec; /*! @brief sets private secret for a standalone mailbox. @discussion some operations require secret to be provided as parameter. Standalone mailbox operations require Private secret, which should not be shared. @@ -95,7 +105,39 @@ typedef void(^ASFKMbLockConditionRoutine)(id cid, BOOL group, id msgId, id msg); @return id of clone group, nil if operation failed. */ -(id) cloneGroup:(id)gid newId:(id)newid withProperties:(ASFKMBContainerProperties*)props secret:(ASFKPrivateSecret*)secret;; - +/*! + @brief creates new group with ALL users belonging both to group 'g0' but NOT to group 'g1'. + @discussion if group with such ID exists, nothing is created; otherwise new group with same id is created. The + @param gid desirable identifier of the new group; if nil, or such group already exists then nothing is created.. + @param g0 group ID; if nil, operation fails. + @param g1 group ID; if nil, operation fails. + @param secret secret; private secret associated with this user. The secret must be the same for g0 and g1. Resulting group will posess the same secret. If secrets do not match, thewn operation fails. + @param props group properties. If nil, then default values will be created. + @return id of newly created group, nil if operation failed. + */ +-(id) createGroup:(id)gid fromMembersOfGroup:(id)g0 excludingMembersOfGroup:(id)g1 withProperties:(ASFKMBContainerProperties*)props secret:(ASFKPrivateSecret*)secret;; +/*! + @brief creates new group with ALL users belonging to group 'g0' OR to group 'g1'. + @discussion if group with such ID exists, nothing is created; otherwise new group with same id is created. + @param gid desirable identifier of the new group; if nil, or such group already exists then nothing is created.. + @param g0 group ID; if nil, operation fails. + @param g1 group ID; if nil, operation fails. + @param secret secret; private secret associated with this user. The secret must be the same for g0 and g1. Resulting group will posess the same secret. If secrets do not match, thewn operation fails. + @param props group properties. If nil, then default values will be created. + @return id of newly created group, nil if operation failed. + */ +-(id) createGroup:(id)gid fromMembersOfGroup:(id)g0 orMembersOfGroup:(id)g1 withProperties:(ASFKMBContainerProperties*)props secret:(ASFKPrivateSecret*)secret;; +/*! + @brief delivers specified message to ALL users belonging both to group 'g0' AND to group 'g1'. + @discussion if group with such ID exists, nothing is created; otherwise new group with same id is created. + @param gid desirable identifier of the new group; if nil, or such group already exists then nothing is created.. + @param g0 group ID; if nil, operation fails. + @param g1 group ID; if nil, operation fails. + @param secret secret; master or private secret associated with this user. The secret must be the same for g0 and g1. Resulting group will posess the same secret. If secrets do not match, thewn operation fails. + @param props group properties. If nil, then default values will be created. + @return id of newly created group, nil if operation failed. + */ +-(id) createGroup:(id)gid fromMembersOfGroup:(id)g0 andMembersOfGroup:(id)g1 withProperties:(ASFKMBContainerProperties*)props secret:(ASFKPrivateSecret*)secret;; /*! @brief adds user to the specific group; if group is private or member limit is exceeded, operation fails. @param uid user ID; if nil, registration fails. @@ -105,12 +147,30 @@ typedef void(^ASFKMbLockConditionRoutine)(id cid, BOOL group, id msgId, id msg); */ -(BOOL) addUser:(id)uid toGroup:(id)gid withProperties:(ASFKMBGroupMemberProperties*)props secret:(ASFKPrivateSecret*)psecret; #pragma mark - Configuring +/*! + @brief sets limit for number of broadcast messages. + @discussion if number of submitted broadcast messages exceeds that limit, new messages are rejected until it reduces. Note: this number represents only messages taht were submitted using 'broadcast' method; it does not represent messages already delivered to their recipients. + @param limit maximum number of messages to be submitetd for broadcasting. + @param secret the master secret; may be nil. + @return YES for success, NO otherwise. + */ +-(BOOL) setBroadcastMsgUpperLimit:(NSUInteger) limit secret:(ASFKMasterSecret*)secret; +/*! + @brief sets limit for number of multicast message recipients. + @discussion if in 'multicast' call number of recipients exceeds this limit, the multicast attempt will fail. + @param limit maximum number of recipients to deliver message to. + @param secret the master secret; may be nil. + @return YES for success, NO otherwise. + */ +-(BOOL) setMulticastReceiversUpperLimit:(NSUInteger) limit secret:(ASFKMasterSecret*)secret; + /*! @brief set limits for number of members in group. @discussion if low value is 0, then there is no low limit. Same about high limit value. @param low if number of members is below this value, then message delivery will be avoided in this group. @param high if number of members is above this number then new members will not be added. @param gid group ID; if nil or not found, operation fails. + @param secret the secret associated with this group; may be nil. @return YES for success, NO otherwise. */ -(BOOL) setMemberingLimitsLow:(NSUInteger)low high:(NSUInteger)high forGroup:(id)gid secret:(ASFKPrivateSecret*)secret; @@ -137,11 +197,36 @@ typedef void(^ASFKMbLockConditionRoutine)(id cid, BOOL group, id msgId, id msg); @param low this number shows minimal size of queue; when below, reading will return empty array. @param high this number shows maximal size of queue; when achieved, newly posted messages will be rejected. @param gid group ID; if nil or not found, operation fails. + @param secret secret required for authorization; may be nil. @return YES for success, NO otherwise. */ -(BOOL) setMsgQThresholdsLow:(NSUInteger)low high:(NSUInteger)high forGroup:(id)gid secret:(ASFKPrivateSecret*)secret; +/*! + @brief set message dropping policy for group. + @discussion if internal queue is unable to accept incoming messages, the excessive messages must be dropped. There are different dropping strategies; this method sets selected strategy. + @param policy selected strategy. + @param gid group ID. + @param secret secret required for authorization; may be nil. + @return YES for success, NO otherwise. + */ -(BOOL) setMsgQDropPolicy:(eASFKQDroppingPolicy)policy forGroup:(id)gid secret:(ASFKPrivateSecret*)secret; +/*! + @brief sets Level 1 filter for incoming messages. + @discussion messages are accumulated in 2 chained queues. This sets dropping algorithm for the first queue. + @param dropAlg dropping algorithm.. + @param gid group ID. + @param secret secret required for authorization; may be nil. + @return YES for success, NO otherwise. + */ -(BOOL) setMsgQDroppingAlgorithmL1:(ASFKFilter*)dropAlg forGroup:(id)gid secret:(ASFKPrivateSecret*)secret; +/*! + @brief sets Level 2 filter for incoming messages. + @discussion messages are accumulated in 2 chained queues. This sets dropping algorithm for the second queue. + @param dropAlg dropping algorithm.. + @param gid group ID. + @param secret secret required for authorization; may be nil. + @return YES for success, NO otherwise. + */ -(BOOL) setMsgQDroppingAlgorithmL2:(clbkASFKMBFilter)dropAlg forGroup:(id)gid secret:(ASFKPrivateSecret*)secret; #pragma mark + Configuring/Queues/Mailbox /*! @@ -150,11 +235,36 @@ typedef void(^ASFKMbLockConditionRoutine)(id cid, BOOL group, id msgId, id msg); @param low this number shows minimal size of queue; when below, reading will return empty array. @param high this number shows maximal size of queue; when achieved, newly posted messages will be rejected. @param uid user ID; if nil or not found, operation fails. + @param secret secret required for authorization; may be nil. @return YES for success, NO otherwise. */ -(BOOL) setMsgQThresholdsLow:(NSUInteger)low high:(NSUInteger)high forMailbox:(id)uid secret:(ASFKPrivateSecret*)secret; +/*! + @brief set message dropping policy for standalone mailbox. + @discussion if internal queue is unable to accept incoming messages, the excessive messages must be dropped. There are different dropping strategies; this method sets selected strategy. + @param policy selected strategy. + @param uid mailbox ID. + @param secret secret required for authorization; may be nil. + @return YES for success, NO otherwise. + */ -(BOOL) setMsgQDropPolicy:(eASFKQDroppingPolicy)policy forMailbox:(id)uid secret:(ASFKPrivateSecret*)secret; +/*! + @brief sets Level 1 filter for incoming messages. + @discussion messages are accumulated in 2 chained queues. This sets dropping algorithm for first queue. + @param dropAlg dropping algorithm.. + @param uid mailbox ID. + @param secret secret required for authorization; may be nil. + @return YES for success, NO otherwise. + */ -(BOOL) setMsgQDroppingAlgorithmL1:(ASFKFilter*)dropAlg forMailbox:(id)uid secret:(ASFKPrivateSecret*)secret; +/*! + @brief sets Level 2 filter for incoming messages. + @discussion messages are accumulated in 2 chained queues. This sets dropping algorithm for the second queue. + @param dropAlg dropping algorithm.. + @param uid mailbox ID. + @param secret secret required for authorization; may be nil. + @return YES for success, NO otherwise. + */ -(BOOL) setMsgQDroppingAlgorithmL2:(clbkASFKMBFilter)dropAlg forMailbox:(id)uid secret:(ASFKPrivateSecret*)secret; #pragma mark - Configuring/Maintenance /*! @@ -406,7 +516,35 @@ typedef void(^ASFKMbLockConditionRoutine)(id cid, BOOL group, id msgId, id msg); @param props properties of message; can be nil; @return message's ID for successful delivery, nil otherwise. */ --(id) cast:(id)msg forGroup:(id)gid withProperties:(ASFKMBMsgProperties*)props secret:(ASFKSecret*)secret;; +-(id) cast:(id)msg forGroup:(id)gid withProperties:(ASFKMBMsgProperties*)props secret:(ASFKSecret*)secret; + + +/*! + @brief delivers specified message to ALL users belonging to group 'g0' but NOT belonging to group 'g1'. + @param msg the message; if nil, delivery fails. + @param g0 group ID; if nil, delivery fails. + @param g1 group ID; if nil, delivery fails. + @return message's ID for successful delivery, nil otherwise. + */ +-(id) multicast:(id)msg toMembersOfGroup:(id)g0 excludingMembersOfGroup:(id)g1 secret:(ASFKSecret*)psecret; + +/*! + @brief delivers specified message to ALL users belonging to group 'g0' OR to group 'g1'. + @param msg the message; if nil, delivery fails. + @param g0 group ID; if nil, delivery fails. + @param g1 group ID; if nil, delivery fails. + @return message's ID for successful delivery, nil otherwise. + */ +-(id) multicast:(id)msg toMembersOfGroup:(id)g0 orMembersOfGroup:(id)g1 secret:(ASFKSecret*)secret; + +/*! + @brief delivers specified message to ALL users belonging both to group 'g0' AND to group 'g1'. + @param msg the message; if nil, delivery fails. + @param g0 group ID; if nil, delivery fails. + @param g1 group ID; if nil, delivery fails. + @return message's ID for successful delivery, nil otherwise. + */ +-(id) multicast:(id)msg toMembersOfGroup:(id)g0 andMembersOfGroup:(id)g1 secret:(ASFKSecret*)secret; /*! @brief delivers specified message to ALL users belonging to group 'g0'. @@ -414,7 +552,8 @@ typedef void(^ASFKMbLockConditionRoutine)(id cid, BOOL group, id msgId, id msg); @param g0 group ID; if nil, delivery fails. @return message's ID for successful delivery, nil otherwise. */ --(id) multicast:(id)msg toMembersOfGroup:(id)g0 secret:(ASFKSecret*)secret;; +-(id) multicast:(id)msg toMembersOfGroup:(id)g0 secret:(ASFKSecret*)secret; + /*! @brief delivers specified message to ALL groups and ALL standalone mailboxes. @discussion broadcast message cannot be retracted. @@ -422,7 +561,8 @@ typedef void(^ASFKMbLockConditionRoutine)(id cid, BOOL group, id msgId, id msg); @param props properties of message; can be nil. @return YES for successful delivery, NO otherwise. */ --(BOOL) broadcast:(id)msg withProperties:(ASFKMBMsgProperties*)props secret:(ASFKSecret*)secret;; +-(BOOL) broadcast:(id)msg withProperties:(ASFKMBMsgProperties*)props secret:(ASFKFloatingSecret*)secret; + /*! @brief retracts delivered message from specific group. @discussion poster can retract posted message while it is available for retraction;the message is available for retraction until it has been popped or its lifetime has ended. @@ -430,7 +570,8 @@ typedef void(^ASFKMbLockConditionRoutine)(id cid, BOOL group, id msgId, id msg); @param gid group ID; if nil, action fails. */ #pragma mark - Message hiding & retraction --(BOOL) retractMsg:(id)msgId fromGroup:(id)gid secret:(ASFKPrivateSecret*)secret;; +-(BOOL) retractMsg:(id)msgId fromGroup:(id)gid secret:(ASFKPrivateSecret*)secret; + /*! @brief retracts delivered message from specific user. @discussion poster can retract posted message while it is available for retraction;the message is available for retraction until it has been popped or its lifetime has ended. @@ -438,7 +579,8 @@ typedef void(^ASFKMbLockConditionRoutine)(id cid, BOOL group, id msgId, id msg); @param uid user ID; if nil, action fails. @return YES for succesful retraction, NO otherwise. */ --(BOOL) retractMsg:(id)msgId fromMailbox:(id)uid secret:(ASFKPrivateSecret*)secret;; +-(BOOL) retractMsg:(id)msgId fromMailbox:(id)uid secret:(ASFKPrivateSecret*)secret; + /*! @brief prevents given user from posting in given group. @discussion muted user can access messages delivered to group but cannot deliver messages to the group; to be muted user may or may not be member of this group. @@ -449,7 +591,17 @@ typedef void(^ASFKMbLockConditionRoutine)(id cid, BOOL group, id msgId, id msg); @return YES for succesful muting, NO otherwise. */ -(BOOL) mute:(BOOL) yesno user:(id)uid inGroup:(id)gid secret:(ASFKPrivateSecret*)secret; + +/*! + @brief prevents all users from posting in given group. + @discussion muted users can access messages delivered to group but cannot deliver messages to the group; to be muted user may or may not be member of this group. + @param yesno YES for muting, NO for unmuting. + @param gid group ID; if nil, action fails. + @param secret private secret of this group; nil means no secret set. + @return YES for succesful muting, NO otherwise. + */ -(BOOL) muteAll:(BOOL) yesno inGroup:(id)gid secret:(ASFKPrivateSecret*)secret; + /*! @brief prevents given user from posting in given mailbox. @discussion muted user cannot deliver messages to the specified target. @@ -460,6 +612,15 @@ typedef void(^ASFKMbLockConditionRoutine)(id cid, BOOL group, id msgId, id msg); @return YES for succesful muting, NO otherwise. */ -(BOOL) mute:(BOOL) yesno user:(id)guestId inMailbox:(id)hostId secret:(ASFKPrivateSecret*)secret; + +/*! + @brief prevents all users from posting in given mailbox. + @discussion muted users cannot deliver messages to the specified target. + @param yesno YES for muting, NO for unmuting. + @param hostId mailbox owner's ID; if nil, action fails. + @param secret private secret of this group; nil means no secret set. + @return YES for succesful muting, NO otherwise. + */ -(BOOL) muteAll:(BOOL) yesno inMailbox:(id)hostId secret:(ASFKPrivateSecret*)secret; /*! @@ -472,6 +633,14 @@ typedef void(^ASFKMbLockConditionRoutine)(id cid, BOOL group, id msgId, id msg); @return YES for succesful blinding, NO otherwise. */ -(BOOL) blind:(BOOL) yesno user:(id)uid inGroup:(id)gid secret:(ASFKPrivateSecret*)secret; + +/*! + @brief prevents all users from accessing messages in given group. + @discussion blinded users can post messages to group but cannot read or pop; to be blinded user may or may not be member of this group. + @param yesno YES for blinding, NO for unblinding. + @param secret private secret of this group; nil means no secret set. + @return YES for succesful blinding, NO otherwise. + */ -(BOOL) blindAll:(BOOL) yesno inGroup:(id)gid secret:(ASFKPrivateSecret*)secret; @end #endif /*#define __A_S_F_K_Mailbox_h__*/ diff --git a/src/ASFKMailbox.mm b/src/ASFKMailbox.mm index e92198d..1240c8a 100644 --- a/src/ASFKMailbox.mm +++ b/src/ASFKMailbox.mm @@ -12,7 +12,9 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// +// Created by Boris Vigman on 05/04/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase.h" @@ -122,7 +124,7 @@ -(BOOL) blindAll:(BOOL) yesno secret:(ASFKPrivateSecret*)secret; -(BOOL) retractMsg:(id)msgId; -(void) purge:(NSDate*)tm; -(BOOL) setMsgQthresholdsLow:(NSUInteger)low high:(NSUInteger)high; --(BOOL) setMsgQDropPolicy:(eASFKQDroppingPolicy)policy ; +-(BOOL) setMsgQDropperPolicy:(eASFKQDroppingPolicy)policy ; -(BOOL) setMsgQDropperL1:(ASFKFilter*)dropAlg ; -(BOOL) setMsgQDropperL2:(clbkASFKMBFilter)dropAlg ; -(void) _testAndRemove:(NSDate*)tmpoint; @@ -324,7 +326,7 @@ -(BOOL) setMsgQDropperL1:(ASFKFilter*)dropAlg { return NO; } BOOL res=NO; - [entranceQ setDroppingAlgorithmL1:dropAlg]; + [entranceQ setDroppingAlgorithm:dropAlg]; res=YES; return res; } @@ -337,7 +339,7 @@ -(BOOL) setMsgQDropperL2: (clbkASFKMBFilter)dropAlg{ [lock1 lock]; itsMsgFilter=dropAlg; [lock1 unlock]; - res=YES; + res=YES; return res; } -(BOOL) setMsgQDropperPolicy:(eASFKQDroppingPolicy)policy{ @@ -468,7 +470,7 @@ -(id) addMsg:(id) msg withProperties:(ASFKMBMsgProperties *)properties group:(BO if(blacklisted){ return nil; } - if([self msgCount]>ASFK_PRIVSYM_PER_MLBX_MAX_MSG_LIMIT){ + if([self msgCount]>ASFK_PRIVSYM_MLBX_MSG_PER_CONT_LIMIT){ WASFKLog(@"Too many messages in container %@; delivery failed!",self.itsOwnerId); return nil; } @@ -512,13 +514,15 @@ -(id) addMsg:(id) msg withProperties:(ASFKMBMsgProperties *)properties group:(BO if(blk==YES){ privmsg->blocked=YES; privmsg->wlocker=[NSCondition new]; - BOOL success = [entranceQ push:privmsg]; + BOOL success = [entranceQ castObject:privmsg exParams:nil]; if(success){ [readBlocker->rlocker lock]; [readBlocker->rlocker signal]; [readBlocker->rlocker unlock]; [privmsg->wlocker lock]; - [privmsg->wlocker wait]; + while(privmsg->blocked==YES){ + [privmsg->wlocker wait]; + } [privmsg->wlocker unlock]; } @@ -528,7 +532,7 @@ -(id) addMsg:(id) msg withProperties:(ASFKMBMsgProperties *)properties group:(BO } else{ - if(![entranceQ push:privmsg]){ + if(![entranceQ castObject:privmsg exParams:nil]){ uuid=nil; } else{ @@ -545,124 +549,8 @@ -(id) addMsg:(id) msg withProperties:(ASFKMBMsgProperties *)properties group:(BO } #pragma mark - reading -(NSArray*) readBlocking:(NSUInteger)amount offset:(NSUInteger)offset forUser:(id)uid latest:(BOOL) yesno{ - if(blacklisted){ - return @[]; - } - - NSDate* tmpoint=[NSDate date]; - [self _testAndRemove:tmpoint]; - [self _testAndAccept:tmpoint]; - NSMutableArray* ma=[NSMutableArray array]; - NSMutableArray* readMsgs=[NSMutableArray array]; - NSMutableIndexSet* iset=[NSMutableIndexSet new]; - [lock1 lock]; - if(NO==itscprops.blockingReadwriteAllowed){ - [lock1 unlock]; - return @[]; - } - BOOL hasuser=[_users containsObject:uid] || [_itsOwnerId isEqualTo:uid]; - if(!hasuser){ - [lock1 unlock]; - return ma; - } - if(NO==[self _canUserRead:uid]){ - [lock1 unlock]; - return ma; - } - NSUInteger msc=[messages count]; - [lock1 unlock]; - - if(msc < 1 || amount > msc){ - [readBlocker->rlocker lock]; - - while(1){ - [self _testAndRemove:tmpoint]; - [self _testAndAccept:tmpoint]; - [lock1 lock]; - msc=[messages count]; - [lock1 unlock]; - if(msc < 1 ){ - [readBlocker->rlocker wait]; - } - else{ - break; - } - } - - [readBlocker->rlocker unlock]; - } - - - if(msc < 1 || offset >= msc){ - - return ma; - } - - if(amount > msc){ - amount=msc; - } - NSInteger lowbound=offset; - if(yesno){ - lowbound=msc-amount; - if(lowbound<0){ - lowbound=0; - } - lowbound=lowbound+offset; - } - - if(lowbound>msc){ - lowbound=msc; - } - NSInteger hibound=lowbound+amount; - if(hibound>msc){ - hibound=msc; - } - - for (NSInteger ui=lowbound; uiblocked == YES){ - if((privmsg.props.msgDeletionTimer && [privmsg.props passedDeletionDate:tmpoint]) || privmsg.props->maxAccessLimit==0){ - [iset addIndex:ui]; - } - else{ - [ma addObject:privmsg.msg]; - privmsg.props->maxAccessLimit.fetch_sub(1); - [readMsgs addObject:privmsg.msgId]; - [privmsg->wlocker lock]; - [privmsg->wlocker broadcast]; - [privmsg->wlocker unlock]; - } - } - else - { - if((privmsg.props.msgDeletionTimer && [privmsg.props passedDeletionDate:tmpoint]) || privmsg.props->maxAccessLimit==0){ - [iset addIndex:ui]; - } - else if( - (privmsg.props.msgReadabilityTimer.itsDeadline==nil - || [privmsg.props passedReadingDate:tmpoint]) - ) - { - if(privmsg.props->maxAccessLimit>0) - { - [ma addObject:privmsg.msg]; - privmsg.props->maxAccessLimit.fetch_sub(1); - [readMsgs addObject:privmsg.msgId]; - } - } - } - - } - [messages removeObjectsAtIndexes:iset]; - [lock1 lock]; - NSUInteger msgCount=[messages count]; - ASFKMbNotifyOnContainerReadRoutine crr=itscprops.onReadProc; - [lock1 unlock]; - if(crr){ - crr(self.itsOwnerId,readMsgs,msgCount); - } - return ma; + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return @[]; } -(NSArray*) read:(NSUInteger)amount offset:(NSUInteger)offset forUser:(id)uid latest:(BOOL) yesno{ if(blacklisted){ @@ -724,6 +612,7 @@ -(NSArray*) read:(NSUInteger)amount offset:(NSUInteger)offset forUser:(id)uid la [iset addIndex:ui]; if(privmsg->blocked==YES && privmsg->wlocker != nil){ [privmsg->wlocker lock]; + privmsg->blocked=NO; [privmsg->wlocker broadcast]; [privmsg->wlocker unlock]; } @@ -736,6 +625,12 @@ -(NSArray*) read:(NSUInteger)amount offset:(NSUInteger)offset forUser:(id)uid la [ma addObject:privmsg.msg]; privmsg.props->maxAccessLimit.fetch_sub(1); [readMsgs addObject:privmsg.msgId]; + if(privmsg->blocked==YES && privmsg->wlocker != nil){ + [privmsg->wlocker lock]; + privmsg->blocked=NO; + [privmsg->wlocker broadcast]; + [privmsg->wlocker unlock]; + } } } } @@ -805,6 +700,7 @@ -(NSUInteger) pop:(NSUInteger)amount offset:(NSUInteger)offset forUser:(id)uid l [poppedMsgs addObject:privmsg.msgId]; if(privmsg->blocked==YES && privmsg->wlocker != nil){ [privmsg->wlocker lock]; + privmsg->blocked=NO; [privmsg->wlocker broadcast]; [privmsg->wlocker unlock]; } @@ -846,6 +742,7 @@ -(void) purge:(NSDate*)tm{ Private_ASFKMBMsg* msg=[entranceQ pull]; if (msg->wlocker && msg->blocked==YES) { [msg->wlocker lock]; + msg->blocked=NO; [msg->wlocker broadcast]; [msg->wlocker unlock]; msg->wlocker=nil; @@ -857,6 +754,7 @@ -(void) purge:(NSDate*)tm{ Private_ASFKMBMsg* msg=(Private_ASFKMBMsg* )obj; if (msg->wlocker) { [msg->wlocker lock]; + msg->blocked=NO; [msg->wlocker broadcast]; [msg->wlocker unlock]; msg->wlocker=nil; @@ -885,8 +783,7 @@ -(void) discardAllUsers{ [lock1 lock]; [backusers removeAllObjects]; [uprops removeAllObjects]; -// [messages removeAllObjects]; -// [entranceQ reset]; + [lock1 unlock]; } -(void) discardUser:(id)uid{ @@ -1050,6 +947,7 @@ -(void) _testAndRemove:(NSDate*)tmpoint{ [retractionList removeObject:o.props.msgId]; if(o->blocked){ [o->wlocker lock]; + o->blocked=NO; [o->wlocker broadcast]; [o->wlocker unlock]; } @@ -1062,6 +960,7 @@ -(void) _testAndRemove:(NSDate*)tmpoint{ *stop = YES; if(o->blocked){ [o->wlocker lock]; + o->blocked=NO; [o->wlocker broadcast]; [o->wlocker unlock]; } @@ -1180,18 +1079,23 @@ @implementation ASFKMailbox{ NSMutableDictionary* deferredMulticastProps; NSMutableArray* blacklistedUsers; NSMutableArray* blacklistedGroups; + NSMutableArray* blacklistedAllUsers; + NSMutableArray* blacklistedAllGroups; + ASFKBatchingQueue* discardingQ; ASFKAuthorizationMgr* authmgr; + std::atomic broadcastMsgCountLimit; + std::atomic multicastRecvCountLimit; } #pragma mark Singleton Methods -+ (ASFKMailbox *)sharedManager { - static ASFKMailbox *sharedManager = nil; ++ (ASFKMailbox *)singleInstance { + static ASFKMailbox *singleInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - sharedManager = [[self alloc] init]; + singleInstance = [[self alloc] init]; }); - return sharedManager; + return singleInstance; } -(id) init{ self =[super init]; @@ -1213,14 +1117,22 @@ -(void) _mbInit{ deferredMulticastProps=[NSMutableDictionary dictionary]; blacklistedUsers=[NSMutableArray array]; blacklistedGroups=[NSMutableArray array]; + blacklistedAllUsers=[NSMutableArray array]; + blacklistedAllGroups=[NSMutableArray array]; + discardingQ=[ASFKBatchingQueue new]; authmgr=[ASFKAuthorizationMgr new]; + broadcastMsgCountLimit=ASFK_PRIVSYM_MBLX_BRCAST_MSG_LIMIT; + multicastRecvCountLimit=ASFK_PRIVSYM_MBLX_MULTICAST_RECV_LIMIT; } #pragma mark - Secret - (BOOL)setMasterSecret:(ASFKMasterSecret*)oldsec newSecret:(ASFKMasterSecret*)newsec { return [authmgr setMasterSecret:oldsec newSecret:newsec]; } --(BOOL)setPrivateSecret:(ASFKPrivateSecret *)oldsec withNew:(ASFKPrivateSecret *)newsec forUser:(id)uid{ +- (BOOL)setFloatingSecret:(ASFKFloatingSecret*)newsec authorizeWith:(ASFKMasterSecret*) msec{ + return [authmgr setFloatingSecret:newsec authorizeWith:msec]; +} +-(BOOL)setPrivateSecret:(ASFKPrivateSecret *)oldsec withNew:(ASFKPrivateSecret *)newsec forMailbox:(id)uid{ if(uid==nil){ return NO; } @@ -1256,7 +1168,8 @@ -(id) createMailbox:(id)uid withProperties:(ASFKMBContainerProperties*)props sec return nil; } - if(YES == [self _test_mailboxes_limit:ASFK_PRIVSYM_MAX_MLBX_LIMIT]){ + if(YES == [self _test_mailboxes_limit:ASFK_PRIVSYM_MLBX_MAX_GRPS_LIMIT+ASFK_PRIVSYM_MLBX_MAX_MLBX_LIMIT]){ + WASFKLog(ASFK_STR_TOO_MANY_MLBX_NOTIF); [self _discard_relaxMemoryPressure:ASFK_PRIVSYM_OBJ_RELEASE_SAMPLE_SIZE]; return nil; } @@ -1287,7 +1200,8 @@ -(id) createGroup:(id)gid withProperties:(ASFKMBContainerProperties*)props secre return nil; } - if(YES == [self _test_mailboxes_limit:ASFK_PRIVSYM_MAX_MLBX_LIMIT]){ + if(YES == [self _test_mailboxes_limit:ASFK_PRIVSYM_MLBX_MAX_GRPS_LIMIT+ASFK_PRIVSYM_MLBX_MAX_MLBX_LIMIT]){ + WASFKLog(ASFK_STR_TOO_MANY_GRPS_NOTIF); [self _discard_relaxMemoryPressure:ASFK_PRIVSYM_OBJ_RELEASE_SAMPLE_SIZE]; return nil; } @@ -1312,38 +1226,24 @@ -(id) createGroup:(id)gid withProperties:(ASFKMBContainerProperties*)props secre [lockGroupsDB unlock]; return gid; } - +-(id) createGroup:(id)gid fromMembersOfGroup:(id)g0 excludingMembersOfGroup:(id)g1 withProperties:(ASFKMBContainerProperties*)props secret:(ASFKPrivateSecret*)psecret{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return nil; +} +-(id) createGroup:(id)gid fromMembersOfGroup:(id)g0 orMembersOfGroup:(id)g1 withProperties:(ASFKMBContainerProperties*)props secret:(ASFKPrivateSecret*)psecret{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return gid; +} +-(id) createGroup:(id)gid fromMembersOfGroup:(id)g0 andMembersOfGroup:(id)g1 withProperties:(ASFKMBContainerProperties*)props secret:(ASFKPrivateSecret*)psecret{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return gid; +} -(id) cloneGroup:(id)gid newId:(id)newid withProperties:(ASFKMBContainerProperties*)props secret:(ASFKPrivateSecret*)psecret{ - if(YES == [self _test_mailboxes_limit:ASFK_PRIVSYM_MAX_MLBX_LIMIT]){ - [self _discard_relaxMemoryPressure:ASFK_PRIVSYM_OBJ_RELEASE_SAMPLE_SIZE]; - return nil; - } - if(gid!=nil && newid!=nil){ - [lockGroupsDB lock]; - ASFKSomeContainer* sg0=[groups objectForKey:gid]; - [lockGroupsDB unlock]; - BOOL ps=[sg0 isPrivateSecretValid:psecret matcher:authmgr->secretProcCreate]; - if(sg0 - && [groups objectForKey:newid]==nil - && ps - && [sg0 canShareUserList] - ){ - ASFKSomeContainer* sg1=[[ASFKSomeContainer alloc]initWithUser:newid privateSecret:psecret properties:props]; - [groups setObject:sg1 forKey:newid]; - [sg0 begin]; - NSSet* res=[NSSet setWithSet:sg0.users]; - for (id user in res) { - [sg1 addUser:user withProperties:nil]; - } - [sg0 commit]; - - return newid; - } - } + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); return nil; } -(BOOL) addUser:(id)uid toGroup:(id)gid withProperties:(ASFKMBGroupMemberProperties*)props secret:(ASFKPrivateSecret*)psecret{ - [self _cast_relaxMemoryPressure:ASFK_PRIVSYM_MEM_PRESSURE_MLBX_THRESHOLD ]; + [self _cast_relaxMemoryPressure:ASFK_PRIVSYM_MSG_RELEASE_SAMPLE_SIZE ]; if(!gid || !uid){ return NO; } @@ -1374,52 +1274,100 @@ -(BOOL) addUser:(id)uid toGroup:(id)gid withProperties:(ASFKMBGroupMemberPropert } #pragma mark - maintenance -(NSUInteger) runDiscarding:(size_t)sampleSize timepoint:(NSDate*)tm{ - dispatch_queue_t dConQ_Background=dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0); + NSUInteger pr=[[NSProcessInfo processInfo] activeProcessorCount]; + [lockDB lock]; + for(NSUInteger i=0;i0){ + [discardingQ castObjectToBatch:[blacklistedUsers firstObject]]; + [blacklistedUsers removeObjectAtIndex:0]; + } + } + [lockDB unlock]; + [discardingQ commitBatch:NO]; - NSArray* ua=[self _repackItems:blacklistedUsers sampleSize:sampleSize dispQ:dConQ_Background]; - if([ua count]>0){ - dispatch_apply([ua count], dConQ_Background, ^(size_t index) { - ASFKSomeContainer* obj=[ua objectAtIndex:index]; - [obj purge:tm]; - - }); + [lockDB lock]; + for(NSUInteger i=0;i0){ + [discardingQ castObjectToBatch:[blacklistedGroups firstObject]]; + [blacklistedGroups removeObjectAtIndex:0]; + } } - tm=[NSDate date]; - NSArray* ga=[self _repackItems:blacklistedGroups sampleSize:sampleSize dispQ:dConQ_Background]; - if([ga count]>0){ - dispatch_apply([ga count], dConQ_Background, ^(size_t index) { - - ASFKSomeContainer* obj=[ga objectAtIndex:index]; - [obj purge:tm]; - - }); - + [lockDB unlock]; + [discardingQ commitBatch:NO]; + + [lockDB lock]; + for(NSUInteger i=0;i0){ + [discardingQ castObjectToBatch:[blacklistedAllGroups firstObject]]; + [blacklistedAllGroups removeObjectAtIndex:0]; + } + } + [lockDB unlock]; + [discardingQ commitBatch:NO]; + + [lockDB lock]; + for(NSUInteger i=0;i0){ + [discardingQ castObjectToBatch:[blacklistedAllUsers firstObject]]; + [blacklistedAllUsers removeObjectAtIndex:0]; + } + } + [lockDB unlock]; + [discardingQ commitBatch:NO]; + + dispatch_queue_t dConQ_Background=dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0); + { + NSArray* arg=[discardingQ pullBatchAsArray]; + if(!arg){ + NSUInteger argc=[arg count]; + NSUInteger argshare=argc/pr; + NSUInteger argresidue=argc%pr; + NSUInteger k=argshare*(pr); + for (NSUInteger i=k; i0){ + dispatch_apply(pr, dConQ_Background, ^(size_t index) { + NSUInteger start=argshare * index; + NSUInteger end=(argshare * (index+1)) ; + for (NSUInteger i=start; i0){ + NSUInteger totBrcs=[deferredBroadcasts count]; + if(totBrcs>0){ NSMutableArray* brc=nil; NSMutableArray* brcprops=nil; - if(sampleSize>0){ + size_t defSSize=50; + if(sampleSize>0){} + else{ + sampleSize=defSSize; + } + + //if(sampleSize>0){ brc=[NSMutableArray array]; brcprops=[NSMutableArray array]; NSUInteger u=0; - NSUInteger totusers=[deferredBroadcasts count]; - for (; u0) + { + { + [lockGroupsDB lock]; + //NSArray* arg=[groups allKeys]; + NSArray* argvals=[groups allValues]; + NSUInteger argc=[argvals count]; + [lockGroupsDB unlock]; + NSUInteger argshare=argc/pr; + NSUInteger argresidue=argc%pr; + NSUInteger k=argshare*(pr); + for (NSUInteger j=k; j0){ + dispatch_apply(pr, dConQ_Background, ^(size_t index) { + NSUInteger start=argshare * index; + NSUInteger end=(argshare * (index+1)) ; + for (NSUInteger i=start; i0){ + dispatch_apply(pr, dConQ_Background, ^(size_t index) { + NSUInteger start=argshare * index; + NSUInteger end=(argshare * (index+1)); + for (NSUInteger i=start; i0){ + dispatch_apply(pr, dConQ_Background, ^(size_t index) { + NSUInteger start=argshare * index; + NSUInteger end=(argshare * (index+1)); + for (NSUInteger i=start; iASFK_PRIVSYM_MEM_PRESSURE_MSG_THRESHOLD){ + if(objCount + gc + uc + msgs > ASFK_PRIVSYM_MBLX_TOTAL_OBJ_LIMIT){ if(clbs && clbs->prMemPressure){ clbs->prMemPressure(tm,objCount); } } - //dispatch_queue_t dConQ_Background=dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0); - //dispatch_apply(2, dConQ_Background, ^(size_t index) - //{ - //if(index==0) + dispatch_queue_t dConQ_Background=dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0); + dispatch_apply(2, dConQ_Background, ^(size_t index) + { + if(index==0) { [lockUsersDB lock]; [users enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { @@ -1558,26 +1588,22 @@ -(NSUInteger) runPeriodic:(size_t)sampleSize timepoint:(NSDate*)tm callbacks:(AS if(sg){ if([sg shouldBeDeletedAtDate:tm]){ [sg markBlacklisted]; - //[blacklistedUsers addObject:sg]; } else{ [sg runPeriodicProc:tm]; } - } }]; [lockUsersDB unlock]; } -// else + else { -// [lockGroupsDB lock]; [groups enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { ASFKSomeContainer* sg=(ASFKSomeContainer*)obj; if(sg){ if([sg shouldBeDeletedAtDate:tm]){ [sg markBlacklisted]; - //[blacklistedGroups addObject:sg]; } else{ [sg runPeriodicProc:tm]; @@ -1587,9 +1613,9 @@ -(NSUInteger) runPeriodic:(size_t)sampleSize timepoint:(NSDate*)tm callbacks:(AS }]; [lockGroupsDB unlock]; } - //}; + }); - dispatch_queue_t dConQ_Background=dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0); + dConQ_Background=dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0); dispatch_apply(2, dConQ_Background, ^(size_t index){ if(index==0){ NSMutableArray* deadkeys=[NSMutableArray new]; @@ -1600,7 +1626,7 @@ -(NSUInteger) runPeriodic:(size_t)sampleSize timepoint:(NSDate*)tm callbacks:(AS [deadkeys addObject:key]; } }]; - //blacklistedUsers = [NSMutableArray new]; + [users removeObjectsForKeys:deadkeys]; [lockUsersDB unlock]; } @@ -1613,7 +1639,7 @@ -(NSUInteger) runPeriodic:(size_t)sampleSize timepoint:(NSDate*)tm callbacks:(AS [deadkeys addObject:key]; } }]; - //blacklistedGroups = [NSMutableArray new]; + [groups removeObjectsForKeys:deadkeys]; [lockGroupsDB unlock]; } @@ -1630,6 +1656,20 @@ -(NSUInteger) runDaemon:(size_t)sampleSize timepoint:(NSDate*)tm callbacks:(ASFK return 0; } #pragma mark - Configuring +-(BOOL) setBroadcastMsgUpperLimit:(NSUInteger)limit secret:(ASFKMasterSecret *)secret{ + if(NO==[authmgr isMasterSecretValid:secret matcher:authmgr->secretProcConfig]){ + return NO; + } + broadcastMsgCountLimit=limit; + return YES; +} +-(BOOL) setMulticastReceiversUpperLimit:(NSUInteger) limit secret:(ASFKMasterSecret*)secret{ + if(NO==[authmgr isMasterSecretValid:secret matcher:authmgr->secretProcConfig]){ + return NO; + } + multicastRecvCountLimit=limit; + return YES; +} -(BOOL) setProperties:(ASFKMBContainerProperties*)props forMailbox:(id)uid secret:(ASFKPrivateSecret*)secret{ if(!uid || !props){ return NO; @@ -1870,7 +1910,7 @@ -(BOOL) discardAllMailboxesWithSecret:(ASFKMasterSecret*)secret{ ASFKLog(@"Discarding all users"); [lockUsersDB lock]; [lockDB lock]; - [blacklistedUsers addObject:users]; + [blacklistedAllUsers addObjectsFromArray:[users allValues]]; [lockDB unlock]; users=[NSMutableDictionary dictionary]; @@ -1886,7 +1926,7 @@ -(BOOL) discardAllGroupsWithSecret:(ASFKMasterSecret*)secret{ } [lockGroupsDB lock]; [lockDB lock]; - [blacklistedGroups addObject:groups]; + [blacklistedAllGroups addObjectsFromArray:[groups allValues]]; [lockDB unlock]; groups=[NSMutableDictionary dictionary]; [lockGroupsDB unlock]; @@ -2116,17 +2156,7 @@ -(NSUInteger) totalUsersInGroup:(id)gid{ } #pragma mark - Read with blocking -(NSArray*) waitAndReadMsg:(NSRange)skipAndTake fromMailbox:(id)mid unblockIf:(ASFKMbLockConditionRoutine)condition withSecret:(ASFKPrivateSecret*)secret{ - if(!mid){ - return @[]; - } - [lockUsersDB lock]; - ASFKSomeContainer* sg=[users objectForKey:mid]; - [lockUsersDB unlock]; - - if(sg && ([sg isPrivateSecretValid:secret matcher:authmgr->secretProcRead])){ - NSArray* a=[sg readBlocking:skipAndTake.length offset:skipAndTake.location forUser:mid latest:YES]; - return a; - } + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); return @[]; } @@ -2249,7 +2279,7 @@ -(void) popEarliestMsg:(NSRange)skipAndTake fromGroup:(id)gid forUser:(id)uid wi #pragma mark - Unicasting -(id) cast:(id)msg forMailbox:(id)uid withProperties:(ASFKMBMsgProperties*)props secret:(ASFKPrivateSecret*)secret{ - [self _cast_relaxMemoryPressure:ASFK_PRIVSYM_MEM_PRESSURE_MSG_THRESHOLD ]; + [self _cast_relaxMemoryPressure:ASFK_PRIVSYM_MSG_RELEASE_SAMPLE_SIZE]; if(!uid || !msg){ return nil; } @@ -2262,7 +2292,7 @@ -(id) cast:(id)msg forMailbox:(id)uid withProperties:(ASFKMBMsgProperties*)props return nil; } -(id) cast:(id)msg forGroup:(id)gid withProperties:(ASFKMBMsgProperties*)props secret:(ASFKPrivateSecret*)secret{ - [self _cast_relaxMemoryPressure:ASFK_PRIVSYM_MEM_PRESSURE_MSG_THRESHOLD ]; + [self _cast_relaxMemoryPressure:ASFK_PRIVSYM_MSG_RELEASE_SAMPLE_SIZE ]; if(!gid || !msg){ return nil; } @@ -2279,41 +2309,46 @@ -(id) cast:(id)msg forGroup:(id)gid withProperties:(ASFKMBMsgProperties*)props s return res; } -(id) call:(id)msg forMailbox:(id)uid withProperties:(ASFKMBMsgProperties *)props unblockIf:(ASFKCondition*)condition secret:(ASFKPrivateSecret*)secret{ - [self _cast_relaxMemoryPressure:ASFK_PRIVSYM_MEM_PRESSURE_MSG_THRESHOLD ]; - if(!uid || !msg){ - return nil; - } - [lockUsersDB lock]; - ASFKSomeContainer* sg=[users objectForKey:uid]; - [lockUsersDB unlock]; - if(sg && [sg isPrivateSecretValid:secret matcher:authmgr->secretProcUnicast]){ - - return [sg addMsg:msg withProperties:props group:NO blockable:YES]; - } + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); return nil; } #pragma mark - Multicasting --(BOOL) broadcast:(id)msg withProperties:(ASFKMBMsgProperties*)props secret:(ASFKSecret*)secret{ - [self _cast_relaxMemoryPressure:ASFK_PRIVSYM_MEM_PRESSURE_MSG_THRESHOLD ]; +-(BOOL) broadcast:(id)msg withProperties:(ASFKMBMsgProperties*)props secret:(ASFKFloatingSecret*)secret{ + [self _cast_relaxMemoryPressure:ASFK_PRIVSYM_MSG_RELEASE_SAMPLE_SIZE ]; if(!msg){ return NO; } + BOOL res=YES; BOOL ms=NO; - ms=[authmgr isMasterSecretValid:(secret) matcher:authmgr->secretProcMulticast]; - [lockDB lock]; - [deferredBroadcasts addObject:msg]; - if(!props){ - [deferredBroadcastsProps addObject:[NSNull null]]; - }else{ - [props setPropMsgRetractBeforeDate:nil]; - [deferredBroadcastsProps addObject:props]; + ms=[authmgr isFloatingSecretValid:(secret) matcher:authmgr->secretProcBroadcast]; + if(ms){ + [lockDB lock]; + if([deferredBroadcasts count] < broadcastMsgCountLimit.load()){ + [deferredBroadcasts addObject:msg]; + if(!props){ + [deferredBroadcastsProps addObject:[NSNull null]]; + }else{ + [props setPropMsgRetractBeforeDate:nil]; + [deferredBroadcastsProps addObject:props]; + } + [lockDB unlock]; + } + else + { + [lockDB unlock]; + WASFKLog(ASFK_STR_TOO_MANY_MSG_NOTIF); + res=NO; + } } - [lockDB unlock]; - return YES; + else{ + WASFKLog(ASFK_STR_SEC_CHECK_FAIL); + res=NO; + } + return res; } -(id) multicast:(id)msg toMembersOfGroup:(id)g0 secret:(ASFKSecret*)secret{ - [self _cast_relaxMemoryPressure:ASFK_PRIVSYM_MEM_PRESSURE_MSG_THRESHOLD ]; + [self _cast_relaxMemoryPressure:ASFK_PRIVSYM_MSG_RELEASE_SAMPLE_SIZE ]; if(msg==nil){ return nil; } @@ -2337,6 +2372,10 @@ -(id) multicast:(id)msg toMembersOfGroup:(id)g0 secret:(ASFKSecret*)secret{ [sg0 begin]; NSMutableSet* res=[NSMutableSet setWithSet:sg0.users]; [sg0 commit]; + if(multicastRecvCountLimit.load()<[res count]){ + WASFKLog(ASFK_STR_TOO_MANY_MSG_NOTIF); + return nil; + } if([res count]>0){ ASFKMBMsgProperties* mprops=[ASFKMBMsgProperties new]; [self _castToSetOfUsers:res msg:msg properties:mprops]; @@ -2345,11 +2384,25 @@ -(id) multicast:(id)msg toMembersOfGroup:(id)g0 secret:(ASFKSecret*)secret{ return retval; } - [lockDB unlock]; + [lockGroupsDB unlock]; } return nil; } - +-(id) multicast:(id)msg toMembersOfGroup:(id)g0 excludingMembersOfGroup:(id)g1 secret:(ASFKSecret*)secret{ + [self _cast_relaxMemoryPressure:ASFK_PRIVSYM_MSG_RELEASE_SAMPLE_SIZE ]; + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return nil; +} +-(id) multicast:(id)msg toMembersOfGroup:(id)g0 orMembersOfGroup:(id)g1 secret:(ASFKSecret*)secret{ + [self _cast_relaxMemoryPressure:ASFK_PRIVSYM_MSG_RELEASE_SAMPLE_SIZE ]; + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return nil; +} +-(id) multicast:(id)msg toMembersOfGroup:(id)g0 andMembersOfGroup:(id)g1 secret:(ASFKSecret*)secret{ + [self _cast_relaxMemoryPressure:ASFK_PRIVSYM_MSG_RELEASE_SAMPLE_SIZE ]; + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return nil; +} #pragma mark - Message hiding & retraction -(BOOL) retractMsg:(id)msgId fromGroup:(id)gid secret:(ASFKPrivateSecret*)secret{ if(!msgId || !gid) @@ -2505,7 +2558,7 @@ -(void) _cast_relaxMemoryPressure:(size_t)sampleSize{ NSUInteger defrefcount1= [deferredMulticastUsers count]; [lockDB unlock]; - if(defrefcount0 > ASFK_PRIVSYM_MEM_PRESSURE_MSG_THRESHOLD || ASFK_PRIVSYM_MEM_PRESSURE_MSG_THRESHOLD > ASFK_PRIVSYM_MEM_PRESSURE_MSG_THRESHOLD){ + if(defrefcount0 > ASFK_PRIVSYM_MSG_RELEASE_SAMPLE_SIZE ){ [self runDelivery:sampleSize ]; } @@ -2513,7 +2566,7 @@ -(void) _cast_relaxMemoryPressure:(size_t)sampleSize{ -(void) _discard_relaxMemoryPressure:(size_t)sampleSize{ //if(NO==[self _test_mailboxes_limit:ASFK_PRIVSYM_MEM_PRESSURE_MLBX_THRESHOLD]) //{ - WASFKLog(@"Too many mailboxes or groups created!"); + //WASFKLog(@"Too many mailboxes or groups created!"); [self runDiscarding:sampleSize timepoint:[NSDate date]] ; //} @@ -2523,59 +2576,16 @@ -(BOOL) _test_mailboxes_limit:(NSUInteger)limit{ NSUInteger defrefcount0= [blacklistedUsers count]; NSUInteger defrefcount1= [blacklistedGroups count]; [lockDB unlock]; + [lockUsersDB lock]; NSUInteger ucount= [users count]; [lockUsersDB unlock]; + [lockGroupsDB lock]; NSUInteger gcount= [groups count]; [lockGroupsDB unlock]; return limit<=defrefcount0+defrefcount1+ucount+gcount; } --(NSArray*) _repackItems:(NSMutableArray*)containers sampleSize:(size_t)iter dispQ:(dispatch_queue_t)dq{ - NSMutableArray* ma=[NSMutableArray array]; - - for (NSUInteger i=0; i* chunk=[NSMutableArray array]; - NSMutableArray* obsolete=[NSMutableArray array]; - [obj enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull object, BOOL * _Nonnull stop) { - [chunk addObject:object ]; - [obsolete addObject:key]; - if([chunk count]==iter){ - *stop=YES;; - } - }]; - for (id key in obsolete) { - [obj removeObjectForKey:key]; - } - if([obj count]==0){ - [lockDB lock]; - if([containers count]>0){ - [containers removeObjectAtIndex:0]; - } - [lockDB unlock]; - } - - return chunk; - } - else{ - [ma addObject:(ASFKSomeContainer*)obj]; - [lockDB lock]; - if([containers count]>0){ - [containers removeObjectAtIndex:0]; - } - [lockDB unlock]; - } - } - - return ma; -} @end diff --git a/src/ASFKNonlinearFlow.h b/src/ASFKNonlinearFlow.h deleted file mode 100644 index dfd245e..0000000 --- a/src/ASFKNonlinearFlow.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. -// - -#ifndef ASFKNonlinearFlow_h -#define ASFKNonlinearFlow_h -@interface ASFKNonlinearFlow : ASFKBase --(BOOL) attachTrueTarget:(id)target withId:(ASFK_IDENTITY_TYPE)identity; --(BOOL) attachFalseTarget:(id)target withId:(ASFK_IDENTITY_TYPE)identity; --(BOOL) detachTrueTargetWithId:(ASFK_IDENTITY_TYPE)identity; --(BOOL) detachFalseTargetWithId:(ASFK_IDENTITY_TYPE)identity; -@end -#endif /* ASFKNonlinearFlow */ diff --git a/src/ASFKNonlinearFlow.mm b/src/ASFKNonlinearFlow.mm deleted file mode 100644 index 75b03f8..0000000 --- a/src/ASFKNonlinearFlow.mm +++ /dev/null @@ -1,40 +0,0 @@ -/* - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. -// - -#import "ASFKBase.h" - -@implementation ASFKNonlinearFlow --(id)initWithName:(NSString*)name{ - self=[super initWithName:name]; - if(self){ - - } - return self; -} --(BOOL) attachTrueTarget:(id)target withId:(ASFK_IDENTITY_TYPE)identity{ - return YES; -} --(BOOL) attachFalseTarget:(id)target withId:(ASFK_IDENTITY_TYPE)identity{ - return YES; -} --(BOOL) detachTrueTargetWithId:(ASFK_IDENTITY_TYPE)identity{ - return YES; -} --(BOOL) detachFalseTargetWithId:(ASFK_IDENTITY_TYPE)identity{ - return YES; -} -@end diff --git a/src/ASFKPipelinePar.h b/src/ASFKPipelinePar.h deleted file mode 100644 index 7f43617..0000000 --- a/src/ASFKPipelinePar.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. -// - -#ifndef ASFKPipelinePar_h -#define ASFKPipelinePar_h -/*! - @see ASFKLinearFlow - @brief This class provides pipelined execution's functionality. For N Routines it takes Routine P0 and applies it to item D0. Upon completion P0 is applied to D1 while P1 is concurrently applied to D0 and so on. - */ -@interface ASFKPipelinePar : ASFKLinearFlow - --(BOOL) isPausedSession:(_Null_unspecified ASFK_IDENTITY_TYPE)sessionId; --(long long) itemsCountForSession:(_Null_unspecified id)sessionId; - -/*! - @brief Equals YES if session with given identity exists AND is still processing data batch ; NO otherwise. - */ --(BOOL) isBusySession:(_Null_unspecified ASFK_IDENTITY_TYPE)sessionId; - --(long long) getRunningSessionsCount; --(long long) getPausedSessionsCount; - -/*! - @brief Cancels ALL sessions created by this instance. - */ --(void)cancelAll; -/*! - @brief Cancels session with given id. - */ --(void)cancelSession:(_Null_unspecified ASFK_IDENTITY_TYPE)sessionId; -/*! - @brief flushes all queued items for all sessions created by this instance. - */ --(void)flushAll; -/*! - @brief flushes all queued items for given session ID. - */ --(void)flushSession:(_Null_unspecified ASFK_IDENTITY_TYPE)sessionId; - -/*! - @brief flushes all queued items for all sessions created by this instance. - */ --(void)pauseAll; -/*! - @brief flushes all queued items for given session ID. - */ --(void)pauseSession:(_Null_unspecified ASFK_IDENTITY_TYPE)sessionId; - -/*! - @brief flushes all queued items for all sessions created by this instance. - */ --(void)resumeAll; -/*! - @brief flushes all queued items for given session ID. - */ --(void)resumeSession:(_Null_unspecified ASFK_IDENTITY_TYPE)sessionId; - -/*! - @brief sets new class of QoS (i.e. thread priority). - @param newqos required class of Quality of Service . Allowed values are:QOS_CLASS_USER_INTERACTIVE, QOS_CLASS_UTILITY, QOS_CLASS_BACKGROUND. By default QOS_CLASS_BACKGROUND is set. The parameter will be in effect after restart. - */ --(void) setQualityOfService:(long)newqos; - -/*! - @brief returns list of session ID's for all sessions created by this instance. - @return Array of session ID's. - */ --(NSArray* _Null_unspecified) getSessions; -/*! - @brief creates new non-expiring session associated with this instance. - @param exparams collection of session properties. May be nil; in that case default parameters will be adopted. - @param sid optional name of session. If nil, then random value will be assigned. - @return Dictionary of return values. - */ --(NSDictionary* _Nonnull) createSession:(ASFKExecutionParams*_Nullable) exparams sessionId:(id _Nullable ) sid; - -@end -#endif /* ASFKPipelinePar */ diff --git a/src/ASFKPipelinePar.mm b/src/ASFKPipelinePar.mm index b8c5a7e..36a96c7 100644 --- a/src/ASFKPipelinePar.mm +++ b/src/ASFKPipelinePar.mm @@ -13,17 +13,17 @@ along with this program. If not, see . */ // -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 05/04/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase.h" #import "ASFKBase+Internal.h" #import "ASFKBase+Statistics.h" -#import "ASFKLinearFlow+Internal.h" +#import "ASFKSessionalFlow+Internal.h" + #include #include -#import "ASFKGlobalThreadpool.h" -#import "ASFKPipelineSession.h" @interface ASFKPipelinePar() @end @implementation ASFKPipelinePar{ @@ -49,7 +49,7 @@ -(id)initWithName:(NSString*)name{ } -(void) _initPipeline{ isOnline=NO; - globalTPool=[ASFKGlobalThreadpool sharedManager]; + globalTPool=[ASFKGlobalThreadpool singleInstance]; } @@ -74,9 +74,9 @@ -(ASFKPipelineSession*) _resolveSessionforParams:(ASFKParamSet*)ps { } } --(ASFKPipelineSession*) _createNewSessionWithId:(ASFK_IDENTITY_TYPE)sessionId{ +-(ASFKPipelineSession*) _createNewSessionWithId:(ASFK_IDENTITY_TYPE)sessionId blkMode:(eASFKBlockingCallMode)blkMode{ ASFKLog(@"creating new session for id %@",sessionId); - ASFKPipelineSession* newseq=[[ASFKPipelineSession alloc]initWithSessionId:sessionId andSubsessionId:nil]; + ASFKPipelineSession* newseq=[[ASFKPipelineSession alloc]initWithSessionId:sessionId andSubsessionId:nil blkMode:blkMode]; newseq.sessionId=[[newseq getControlBlock]sessionId]; newseq->cancellationProc = (id)^(id sessionId){ if(sessionId){ @@ -111,21 +111,24 @@ -(void) setQualityOfService:(long)newqos{ /*! @return number of running sessions */ --(long long) getRunningSessionsCount{ +-(std::uint64_t) getRunningSessionsCount{ return [globalTPool runningSessionsCount]; } /*! @return number of paused sessions */ --(long long) getPausedSessionsCount{ +-(std::uint64_t) getPausedSessionsCount{ return [globalTPool pausedSessionsCount]; } #pragma mark - Flush/Resume/Cancel -(void)flushAll{ [lkNonLocal lock]; - for (id s in ctrlblocks) { - [globalTPool flushSession:s]; - } + [ctrlblocks enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { + [globalTPool flushSession:key]; + }]; +// for (id s in ctrlblocks) { +// [globalTPool flushSession:s]; +// } [lkNonLocal unlock]; } @@ -186,22 +189,46 @@ -(BOOL) isPausedSession:(ASFK_IDENTITY_TYPE)sessionId{ -(BOOL)isBusySession:(id)sessionId{ return [globalTPool isBusySession:sessionId]; } -//-(BOOL) isBusy{ -// return NO; -//} +-(BOOL) isBusy{ + NSInteger bcount=0; + [lkNonLocal lock]; + for (id key in ctrlblocks) { + ASFKControlBlock* res=[ctrlblocks objectForKey:key]; + id s=[res getCurrentSessionId]; + if([globalTPool isBusySession:s]){ + ++bcount; + } + } + [lkNonLocal unlock]; + return bcount>0?YES:NO; +} -(BOOL)isReady{ return YES; } --(long long) itemsCountForSession:(id)sessionId{ +-(std::uint64_t) itemsCountForSession:(id)sessionId{ return [globalTPool itemsCountForSession:sessionId]; } +-(std::uint64_t) totalSessionsCount{ + return [globalTPool totalSessionsCount]; +} - --(NSDictionary* _Nonnull) createSession:(ASFKExecutionParams*_Nullable) exparams sessionId:(id _Nullable ) sid { +-(NSDictionary* _Nonnull) createSession:(ASFKSessionConfigParams*_Nullable) exparams sessionId:(id _Nullable ) sid { uint64 main_t1=[ASFKBase getTimestamp]; dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); - ASFKParamSet* params=[self _decodeExParams:exparams forSession:sid]; + std::uint64_t count=[globalTPool totalSessionsCount]; + if(count>ASFK_PRIVSYM_TP_SESSIONS_LIMIT){ + dispatch_semaphore_signal(semHighLevelCall); + uint64 main_t2=[ASFKBase getTimestamp]; + double elapsed=(main_t2-main_t1)/1e9; + ASFKLog(ASFK_STR_UP_LIMITS_REACHED_SES); + return @{kASFKReturnCode:ASFK_RC_FAIL, + kASFKReturnResult:[NSNull null], + kASFKReturnSessionId:[NSNull null], + kASFKReturnStatsTimeSessionElapsedSec:@(elapsed), + kASFKReturnDescription:ASFK_STR_UP_LIMITS_REACHED_SES}; + } + ASFKParamSet* params=[self _decodeSessionParams:exparams forSession:sid]; if(!params.summary) { params.summary = sumProc; @@ -217,7 +244,9 @@ -(NSDictionary* _Nonnull) createSession:(ASFKExecutionParams*_Nullable) exparams //test params if(params.procs==nil || [params.procs isKindOfClass:[NSNull class]] - || [params.procs count]<1){ + || [params.procs count]<1 + || [params.procs count]>ASFK_PRIVSYM_TP_PROCS_PER_SESSION_LIMIT + ){ dispatch_semaphore_signal(semHighLevelCall); uint64 main_t2=[ASFKBase getTimestamp]; double elapsed=(main_t2-main_t1)/1e9; @@ -234,8 +263,10 @@ -(NSDictionary* _Nonnull) createSession:(ASFKExecutionParams*_Nullable) exparams else{ params.sessionId=sid; } + + //create new session - ASFKPipelineSession* seq=[self _createNewSessionWithId:params.sessionId]; + ASFKPipelineSession* seq=[self _createNewSessionWithId:params.sessionId blkMode:params.bcallMode]; //configure session ASFKPipelineSession* s=[self _prepareSession:seq withParams:params]; //set Expiration Condition @@ -273,7 +304,7 @@ -(NSArray*) getSessions{ } #pragma mark - Non-blocking methods --(NSDictionary*) _castArray:(ASFKParamSet*)params{ +-(NSDictionary*) _postArray:(ASFKParamSet*)params blocking:(BOOL) blk{ __block uint64 main_t1=[ASFKBase getTimestamp]; DASFKLog(@"ASFKPipelinePar:Object %@: trying to push data items",self.itsName); @@ -293,26 +324,29 @@ -(NSDictionary*) _castArray:(ASFKParamSet*)params{ kASFKReturnStatsTimeSessionElapsedSec:@(elapsed), kASFKReturnDescription:ASFK_STR_INVALID_PARAM}; } - ASFKLog(@"Performing non-blocking call"); ASFKPipelineSession* s=[self _resolveSessionforParams:params ]; if(s){ - //if(params.hasForeignProcs){ - if(params.excond && [params.excond isKindOfClass:[ASFKExpirationCondition class]]){ - [s setExpirationCondition:params.excond]; - } + if(params.excond && [params.excond isKindOfClass:[ASFKExpirationCondition class]]){ + [s setExpirationCondition:params.excond]; + } - [globalTPool postDataAsArray:params.input forSession:s.sessionId]; + BOOL res=[globalTPool postDataAsArray:params.input forSession:s.sessionId blocking:blk]; - uint64 main_t2=[ASFKBase getTimestamp]; - double elapsed=(main_t2-main_t1)/1e9; - + uint64 main_t2=[ASFKBase getTimestamp]; + double elapsed=(main_t2-main_t1)/1e9; + if(res==YES){ return @{kASFKReturnCode:ASFK_RC_SUCCESS, - kASFKReturnResult:[NSNull null], - kASFKReturnStatsTimeSessionElapsedSec:@(elapsed), - kASFKReturnSessionId:s.sessionId, - kASFKReturnDescription:ASFK_RC_DESCR_DEFERRED}; - //} + kASFKReturnResult:[NSNull null], + kASFKReturnStatsTimeSessionElapsedSec:@(elapsed), + kASFKReturnSessionId:s.sessionId, + kASFKReturnDescription:ASFK_RC_DESCR_DEFERRED}; + } + return @{kASFKReturnCode:ASFK_RC_FAIL, + kASFKReturnResult:[NSNull null], + kASFKReturnStatsTimeSessionElapsedSec:@(elapsed), + kASFKReturnSessionId:s.sessionId, + kASFKReturnDescription:ASFK_RC_DESCR_DEFERRED}; } uint64 main_t2=[ASFKBase getTimestamp]; double elapsed=(main_t2-main_t1)/1e9; @@ -325,7 +359,7 @@ -(NSDictionary*) _castArray:(ASFKParamSet*)params{ kASFKReturnDescription:@"Some of input parameters are invalid: missing data or Routines or summary"}; } --(NSDictionary*) _castOrderedSet:(ASFKParamSet *)params{ +-(NSDictionary*) _postOrderedSet:(ASFKParamSet *)params blocking:(BOOL) blk{ __block uint64 main_t1=[ASFKBase getTimestamp]; DASFKLog(@"ASFKPipelinePar:Object %@: trying to push data items",self.itsName); @@ -347,26 +381,31 @@ -(NSDictionary*) _castOrderedSet:(ASFKParamSet *)params{ kASFKReturnStatsTimeSessionElapsedSec:@(elapsed), kASFKReturnDescription:ASFK_STR_INVALID_PARAM}; } - ASFKLog(@"Performing non-blocking call"); ASFKPipelineSession* s=[self _resolveSessionforParams:params ]; if(s){ //if(params.hasForeignProcs){ - if(params.excond && [params.excond isKindOfClass:[ASFKExpirationCondition class]]){ - [s setExpirationCondition:params.excond]; - } - [globalTPool postDataAsOrderedSet:params.input forSession:s.sessionId]; + if(params.excond && [params.excond isKindOfClass:[ASFKExpirationCondition class]]){ + [s setExpirationCondition:params.excond]; + } + BOOL res=[globalTPool postDataAsOrderedSet:params.input forSession:s.sessionId blocking:blk]; - uint64 main_t2=[ASFKBase getTimestamp]; - double elapsed=(main_t2-main_t1)/1e9; - + uint64 main_t2=[ASFKBase getTimestamp]; + double elapsed=(main_t2-main_t1)/1e9; + if(res==YES){ return @{kASFKReturnCode:ASFK_RC_SUCCESS, kASFKReturnResult:[NSNull null], kASFKReturnStatsTimeSessionElapsedSec:@(elapsed), kASFKReturnSessionId:s.sessionId, kASFKReturnDescription:ASFK_RC_DESCR_DEFERRED}; - //} + } + return @{kASFKReturnCode:ASFK_RC_FAIL, + kASFKReturnResult:[NSNull null], + kASFKReturnStatsTimeSessionElapsedSec:@(elapsed), + kASFKReturnSessionId:s.sessionId, + kASFKReturnDescription:ASFK_RC_DESCR_DEFERRED}; + } uint64 main_t2=[ASFKBase getTimestamp]; double elapsed=(main_t2-main_t1)/1e9; @@ -378,19 +417,17 @@ -(NSDictionary*) _castOrderedSet:(ASFKParamSet *)params{ kASFKReturnStatsTimeSessionElapsedSec:@(elapsed), kASFKReturnDescription:@"Some of input parameters are invalid: missing data or Routines or summary"}; } --(NSDictionary*) _castUnorderedSet:(ASFKParamSet *)params{ +-(NSDictionary*) _postUnorderedSet:(ASFKParamSet *)params blocking:(BOOL) blk{ __block uint64 main_t1=[ASFKBase getTimestamp]; DASFKLog(@"ASFKPipelinePar:Object %@: trying to push data items",self.itsName); - + if ( params.sessionId==nil ||[params.sessionId isKindOfClass:[NSNull class]] ||params.input==nil ||[params.input isKindOfClass:[NSNull class]] ||[params.input count]<1 - ){ - uint64 main_t2=[ASFKBase getTimestamp]; double elapsed=(main_t2-main_t1)/1e9; EASFKLog(@"ASFKPipelinePar:Some of input parameters are invalid for session %@",params.sessionId); @@ -400,27 +437,31 @@ -(NSDictionary*) _castUnorderedSet:(ASFKParamSet *)params{ kASFKReturnStatsTimeSessionElapsedSec:@(elapsed), kASFKReturnDescription:ASFK_STR_INVALID_PARAM}; } - ASFKLog(@"Performing non-blocking call"); - - ASFKPipelineSession* s=[self _resolveSessionforParams:params]; + //ASFKLog(@"Performing non-blocking call"); + + ASFKPipelineSession* s=[self _resolveSessionforParams:params ]; if(s){ - // if(params.hasForeignProcs){ - - if(params.excond && [params.excond isKindOfClass:[ASFKExpirationCondition class]]){ - [s setExpirationCondition:params.excond]; - } - - [globalTPool postDataAsUnorderedSet:params.input forSession:s.sessionId]; - - uint64 main_t2=[ASFKBase getTimestamp]; - double elapsed=(main_t2-main_t1)/1e9; - + if(params.excond && [params.excond isKindOfClass:[ASFKExpirationCondition class]]){ + [s setExpirationCondition:params.excond]; + } + + BOOL res=[globalTPool postDataAsUnorderedSet:params.input forSession:s.sessionId blocking:blk]; + + uint64 main_t2=[ASFKBase getTimestamp]; + double elapsed=(main_t2-main_t1)/1e9; + if(res==YES){ return @{kASFKReturnCode:ASFK_RC_SUCCESS, kASFKReturnResult:[NSNull null], kASFKReturnStatsTimeSessionElapsedSec:@(elapsed), kASFKReturnSessionId:s.sessionId, kASFKReturnDescription:ASFK_RC_DESCR_DEFERRED}; - //} + } + return @{kASFKReturnCode:ASFK_RC_FAIL, + kASFKReturnResult:[NSNull null], + kASFKReturnStatsTimeSessionElapsedSec:@(elapsed), + kASFKReturnSessionId:s.sessionId, + kASFKReturnDescription:ASFK_RC_DESCR_DEFERRED}; + } uint64 main_t2=[ASFKBase getTimestamp]; double elapsed=(main_t2-main_t1)/1e9; @@ -433,7 +474,7 @@ -(NSDictionary*) _castUnorderedSet:(ASFKParamSet *)params{ kASFKReturnDescription:@"Some of input parameters are invalid: missing data or Routines or summary"}; } --(NSDictionary*) _castDictionary:(ASFKParamSet*)params{ +-(NSDictionary*) _postDictionary:(ASFKParamSet*)params blocking:(BOOL) blk{ __block uint64 main_t1=[ASFKBase getTimestamp]; DASFKLog(@"ASFKPipelinePar:Object %@: trying to push data items",self.itsName); @@ -456,26 +497,30 @@ -(NSDictionary*) _castDictionary:(ASFKParamSet*)params{ kASFKReturnStatsTimeSessionElapsedSec:@(elapsed), kASFKReturnDescription:ASFK_STR_INVALID_PARAM}; } - ASFKLog(@"Performing non-blocking call"); ASFKPipelineSession* s=[self _resolveSessionforParams:params ]; if(s){ - if(params.excond && [params.excond isKindOfClass:[ASFKExpirationCondition class]]){ - [s setExpirationCondition:params.excond]; - } + if(params.excond && [params.excond isKindOfClass:[ASFKExpirationCondition class]]){ + [s setExpirationCondition:params.excond]; + } - [globalTPool postDataAsDictionary:params.input forSession:s.sessionId]; + BOOL res=[globalTPool postDataAsDictionary:params.input forSession:s.sessionId blocking:blk]; - uint64 main_t2=[ASFKBase getTimestamp]; - double elapsed=(main_t2-main_t1)/1e9; - + uint64 main_t2=[ASFKBase getTimestamp]; + double elapsed=(main_t2-main_t1)/1e9; + if(res==YES){ return @{kASFKReturnCode:ASFK_RC_SUCCESS, kASFKReturnResult:[NSNull null], kASFKReturnStatsTimeSessionElapsedSec:@(elapsed), kASFKReturnSessionId:s.sessionId, kASFKReturnDescription:ASFK_RC_DESCR_DEFERRED}; - //} + } + return @{kASFKReturnCode:ASFK_RC_FAIL, + kASFKReturnResult:[NSNull null], + kASFKReturnStatsTimeSessionElapsedSec:@(elapsed), + kASFKReturnSessionId:s.sessionId, + kASFKReturnDescription:ASFK_RC_DESCR_DEFERRED}; } uint64 main_t2=[ASFKBase getTimestamp]; double elapsed=(main_t2-main_t1)/1e9; @@ -487,50 +532,7 @@ -(NSDictionary*) _castDictionary:(ASFKParamSet*)params{ kASFKReturnStatsTimeSessionElapsedSec:@(elapsed), kASFKReturnDescription:@"Some of input parameters are invalid: missing data or Routines or summary"}; } -#pragma mark - Blocking methods --(NSDictionary*) _callArray:(ASFKParamSet*)params{ - MASFKLog(@"Pipelining in blocking call not allowed for this data type"); - return @{kASFKReturnCode:ASFK_RC_FAIL, - kASFKReturnResult:[NSNull null], - kASFKReturnSessionId:[NSNull null], - kASFKReturnStatsTimeSessionElapsedSec:@(0), - kASFKReturnDescription:@"Pipelining in blocking call not allowed for this data type"}; - -} --(NSDictionary*) _callDictionary:(ASFKParamSet*)params{ - MASFKLog(@"Pipelining in blocking call not allowed for this data type"); - return @{kASFKReturnCode:ASFK_RC_FAIL, - kASFKReturnResult:[NSNull null], - kASFKReturnSessionId:[NSNull null], - kASFKReturnStatsTimeSessionElapsedSec:@(0), - kASFKReturnDescription:@"Pipelining in blocking call not allowed for this data type"}; - -} --(NSDictionary*) _callIndexSet:(ASFKParamSet *)params{ - MASFKLog(@"Pipelining in blocking call not allowed for this data type"); - return @{kASFKReturnCode:ASFK_RC_FAIL, - kASFKReturnResult:[NSNull null], - kASFKReturnSessionId:[NSNull null], - kASFKReturnStatsTimeSessionElapsedSec:@(0), - kASFKReturnDescription:@"Pipelining in blocking call not allowed for this data type"}; -} --(NSDictionary*) _callOrderedSet:(ASFKParamSet *)params{ - MASFKLog(@"Pipelining in blocking call not allowed for this data type"); - return @{kASFKReturnCode:ASFK_RC_FAIL, - kASFKReturnResult:[NSNull null], - kASFKReturnSessionId:[NSNull null], - kASFKReturnStatsTimeSessionElapsedSec:@(0), - kASFKReturnDescription:@"Pipelining in blocking call not allowed for this data type"}; -} --(NSDictionary*) _callUnorderedSet:(ASFKParamSet *)params{ - MASFKLog(@"Pipelining in blocking call not allowed for this data type"); - return @{kASFKReturnCode:ASFK_RC_FAIL, - kASFKReturnResult:[NSNull null], - kASFKReturnSessionId:[NSNull null], - kASFKReturnStatsTimeSessionElapsedSec:@(0), - kASFKReturnDescription:@"Pipelining in blocking call not allowed for this data type"}; -} @end diff --git a/src/ASFKPipelineSession+Internal.h b/src/ASFKPipelineSession+Internal.h index d8c8865..c3956f5 100644 --- a/src/ASFKPipelineSession+Internal.h +++ b/src/ASFKPipelineSession+Internal.h @@ -12,10 +12,10 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 15/02/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // -#import "ASFKPipelineSession.h" #import "ASFKBase.h" @interface ASFKPipelineSession (Internal) -(void) setResultPosition:(NSUInteger)proc; diff --git a/src/ASFKPipelineSession+Internal.mm b/src/ASFKPipelineSession+Internal.mm index a34bf13..6b0c2bc 100644 --- a/src/ASFKPipelineSession+Internal.mm +++ b/src/ASFKPipelineSession+Internal.mm @@ -12,7 +12,8 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 15/02/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKPipelineSession+Internal.h" diff --git a/src/ASFKPipelineSession.h b/src/ASFKPipelineSession.h deleted file mode 100644 index 22cae59..0000000 --- a/src/ASFKPipelineSession.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as - published by the Free Software Foundation, either version 3 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. -// - -#ifndef ASFKPipelineSession_h -#define ASFKPipelineSession_h -#import "ASFKBase.h" - -@interface ASFKPipelineSession : ASFKThreadpoolSession -@end - -#endif /* ASFKPipelineSession_h */ diff --git a/src/ASFKPipelineSession.mm b/src/ASFKPipelineSession.mm index 709584d..a7f6f3b 100644 --- a/src/ASFKPipelineSession.mm +++ b/src/ASFKPipelineSession.mm @@ -12,7 +12,9 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// +// Created by Boris Vigman on 05/04/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #define ASFK_LOCAL_REPLACE 0 #define ASFK_LOCAL_ADD 1 @@ -20,13 +22,16 @@ #import "ASFKBase+Internal.h" #import "ASFKBase+Statistics.h" #import "ASFKControlBlock+Internal.h" -#import "ASFKPipelineSession.h" -#import "ASFKExpirationCondition.h" + #import #import + +typedef long long sizeQData_t; +typedef long long sizeQProcs_t; + struct sASFKPrioritizedQueueItem{ - long priority; - long queueId; + sizeQData_t priority; + sizeQData_t queueId; }; class ASFKComparePriorities { public: @@ -53,8 +58,8 @@ -(id)init{ } return self; } --(id)initWithSessionId:(ASFK_IDENTITY_TYPE)sessionId andSubsessionId:(ASFK_IDENTITY_TYPE)subId{ - self=[super initWithSessionId:sessionId andSubsessionId:subId]; +-(id)initWithSessionId:(ASFK_IDENTITY_TYPE)sessionId andSubsessionId:(ASFK_IDENTITY_TYPE)subId blkMode:(eASFKBlockingCallMode)blkMode{ + self=[super initWithSessionId:sessionId andSubsessionId:subId blkMode:blkMode]; if(self){ [self _PSinitWithSession:sessionId andSubsession:subId]; } @@ -69,11 +74,6 @@ -(void)_PSinitWithSession:(ASFK_IDENTITY_TYPE)sessionId andSubsession:(ASFK_IDEN paused=NO; dataQueues=[NSMutableArray array]; queueZero=[[ASFKThreadpoolQueue alloc]init]; - if(sessionId){ - cblk= [self newSession:sessionId andSubsession:subId]; - }else{ - cblk= [self newSession]; - } self.sessionId=cblk.sessionId; @@ -148,35 +148,69 @@ -(void) setExpirationSummary:(ASFKExecutableRoutineSummary)sum{ } } --(void) postDataItemsAsDictionary:(NSDictionary*)dict{ +-(BOOL) postDataItemsAsDictionary:(NSDictionary*)dict blocking:(BOOL)blk{ [lock lock]; - if([dataQueues count]>0) - { - - [dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { - [[dataQueues objectAtIndex:0]queueFromItem:obj]; - }]; + if([dict count]+busyCount.load()>ASFK_PRIVSYM_TP_ITEMS_PER_SESSION_LIMIT){ + [lock unlock]; + WASFKLog(ASFK_STR_UP_LIMITS_REACHED_DATA); + return NO; + } + if([dataQueues count]>0){ + if(blk){ + ASFKExecutionParams* ep=[ASFKExecutionParams new]; + ep->preBlock=^(){ + sASFKPrioritizedQueueItem qin; + qin.queueId=0; + qin.priority=[[dataQueues objectAtIndex:0] count]; + pq.push(qin); + busyCount.fetch_add([dict count]); + [lock unlock]; + }; + [[dataQueues objectAtIndex:0]callDictionary:dict exParams:ep]; + return YES; + } + else{ + [[dataQueues objectAtIndex:0]castDictionary:dict exParams:nil]; + } + //} sASFKPrioritizedQueueItem qin; qin.queueId=0; qin.priority=[[dataQueues objectAtIndex:0] count]; pq.push(qin); - } - else{ - - [dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { - [queueZero queueFromItem:obj]; - }]; - + }else{ + [queueZero castArray:[dict allValues] exParams:nil]; } busyCount.fetch_add([dict count]); [lock unlock]; + return YES; } --(void) postDataItemsAsArray:(NSArray*)array{ +-(BOOL) postDataItemsAsArray:(NSArray*)array blocking:(BOOL)blk{ [lock lock]; + if([array count]+busyCount.load()>ASFK_PRIVSYM_TP_ITEMS_PER_SESSION_LIMIT){ + [lock unlock]; + WASFKLog(ASFK_STR_UP_LIMITS_REACHED_DATA); + return NO; + } if([dataQueues count]>0){ - for (id item in array) { - [[dataQueues objectAtIndex:0]queueFromItem:item]; + if(blk){ + ASFKExecutionParams* ep=[ASFKExecutionParams new]; + ep->preBlock=^(){ + sASFKPrioritizedQueueItem qin; + qin.queueId=0; + qin.priority=[[dataQueues objectAtIndex:0] count]; + pq.push(qin); + busyCount.fetch_add([array count]); + [lock unlock]; + + }; + + [[dataQueues objectAtIndex:0]callArray:array exParams:ep] ; + return YES; + } + else{ + [[dataQueues objectAtIndex:0]castArray:array exParams:nil]; } + sASFKPrioritizedQueueItem qin; qin.queueId=0; qin.priority=[[dataQueues objectAtIndex:0] count]; @@ -187,14 +221,34 @@ -(void) postDataItemsAsArray:(NSArray*)array{ } busyCount.fetch_add([array count]); [lock unlock]; + return YES; } --(void) postDataItemsAsUnorderedSet:(NSSet*)set{ +-(BOOL) postDataItemsAsUnorderedSet:(NSSet*)set blocking:(BOOL)blk{ [lock lock]; + if([set count]+busyCount.load()>ASFK_PRIVSYM_TP_ITEMS_PER_SESSION_LIMIT){ + [lock unlock]; + WASFKLog(ASFK_STR_UP_LIMITS_REACHED_DATA); + return NO; + } if([dataQueues count]>0){ - for (id item in set) { - [[dataQueues objectAtIndex:0]queueFromItem:item]; + if(blk){ + ASFKExecutionParams* ep=[ASFKExecutionParams new]; + ep->preBlock=^(){ + sASFKPrioritizedQueueItem qin; + qin.queueId=0; + qin.priority=[[dataQueues objectAtIndex:0] count]; + pq.push(qin); + busyCount.fetch_add([set count]); + [lock unlock]; + }; + [[dataQueues objectAtIndex:0]callUnorderedSet:set exParams:ep]; + return YES; + } + else{ + [[dataQueues objectAtIndex:0]castUnorderedSet:set exParams:nil]; } + //} sASFKPrioritizedQueueItem qin; qin.queueId=0; qin.priority=[[dataQueues objectAtIndex:0] count]; @@ -202,51 +256,92 @@ -(void) postDataItemsAsUnorderedSet:(NSSet*)set{ }else{ for (id item in set) { - [queueZero queueFromItem:item]; + [queueZero castObject:item exParams:nil]; } } busyCount.fetch_add([set count]); [lock unlock]; + return YES; } --(void) postDataItemsAsOrderedSet:(NSOrderedSet*)set{ +-(BOOL) postDataItemsAsOrderedSet:(NSOrderedSet*)set blocking:(BOOL)blk{ [lock lock]; + if([set count]+busyCount.load()>ASFK_PRIVSYM_TP_ITEMS_PER_SESSION_LIMIT){ + [lock unlock]; + WASFKLog(ASFK_STR_UP_LIMITS_REACHED_DATA); + return NO; + } if([dataQueues count]>0){ - for (id item in set) { - [[dataQueues objectAtIndex:0]queueFromItem:item];; + //for (id item in set) { + //[[dataQueues objectAtIndex:0]castOrderedSet:set];; + if(blk){ + ASFKExecutionParams* ep=[ASFKExecutionParams new]; + ep->preBlock=^(){ + sASFKPrioritizedQueueItem qin; + qin.queueId=0; + qin.priority=[[dataQueues objectAtIndex:0] count]; + pq.push(qin); + busyCount.fetch_add([set count]); + [lock unlock]; + }; + [[dataQueues objectAtIndex:0]callOrderedSet:set exParams:ep]; + return YES; } + else{ + [[dataQueues objectAtIndex:0]castOrderedSet:set exParams:nil]; + } + //} sASFKPrioritizedQueueItem qin; qin.queueId=0; qin.priority=[[dataQueues objectAtIndex:0] count]; pq.push(qin); } else{ - for (id item in set) { - [queueZero queueFromItem:item]; + [queueZero castObject:item exParams:nil]; } } busyCount.fetch_add([set count]); [lock unlock]; + return YES; } --(void) postDataItem:(id)dataItem{ +-(BOOL) postDataItem:(id)dataItem blocking:(BOOL)blk{ if(dataItem==nil) - return; - + return NO; + if(busyCount.load()+1>ASFK_PRIVSYM_TP_ITEMS_PER_SESSION_LIMIT){ + [lock unlock]; + WASFKLog(ASFK_STR_UP_LIMITS_REACHED_DATA); + return NO; + } [lock lock]; if([dataQueues count]>0){ - [[dataQueues objectAtIndex:0]queueFromItem:dataItem]; + //[[dataQueues objectAtIndex:0]castObject:dataItem]; + if(blk){ + ASFKExecutionParams* ep=[ASFKExecutionParams new]; + ep->preBlock=^(){ + sASFKPrioritizedQueueItem qin; + qin.queueId=0; + qin.priority=[[dataQueues objectAtIndex:0] count]; + pq.push(qin); + busyCount.fetch_add(1); + [lock unlock]; + }; + [[dataQueues objectAtIndex:0]callObject:dataItem exParams:nil]; + return YES; + } + else{ + [[dataQueues objectAtIndex:0]castObject:dataItem exParams:nil]; + } busyCount.fetch_add(1); sASFKPrioritizedQueueItem qin; qin.queueId=0; qin.priority=[[dataQueues objectAtIndex:0] count]; pq.push(qin); }else{ - - [queueZero queueFromItem:dataItem]; + [queueZero castObject:dataItem exParams:nil]; busyCount.fetch_add(1); } [lock unlock]; - + return YES; } //-(void) addRoutinesFromArray:(NSArray*)ps{ // @@ -254,20 +349,28 @@ -(void) postDataItem:(id)dataItem{ -(void) replaceRoutinesWithArray:(NSArray*)ps{ [lock lock]; + NSUInteger was=[procs count]; [procs removeAllObjects]; [procs addObjectsFromArray:ps]; + for(ASFKQueue* q in dataQueues){ + [q reset]; + } [dataQueues removeAllObjects]; - for (ASFKExecutableRoutine er in ps) { - [dataQueues addObject:[ASFKThreadpoolQueue new]]; + NSUInteger qcount=0; + if(ps){ + qcount=[ps count]; + if(qcount>0){ + [dataQueues addObject:[[ASFKThreadpoolQueueHyb alloc]initWithBlkMode:callMode]]; + } + for (NSUInteger i=1;iitsSig){ + result=eproc(cblk,result,itemIndex); + } + [lock lock]; if([dataQueues count]>0){ sq0.queueId=0; @@ -435,9 +542,9 @@ -(eASFKThreadpoolExecutionStatus) select:(long)selector routineCancel:(ASFKCance } [lock unlock]; if([cblk cancellationRequestedByCallback]|| [cblk cancellationRequestedByStarter]){ - [lock lock]; [self _resetPriorityQueue]; + [q unoccupy]; ASFKCancellationRoutine cru=cancellationHandler; [lock unlock]; [self flush]; @@ -445,17 +552,30 @@ -(eASFKThreadpoolExecutionStatus) select:(long)selector routineCancel:(ASFKCance [self _invokeCancellationHandler:cru identity:self.sessionId]; //cru(self.sessionId); [self forgetAllSessions]; - DASFKLog(@"Cancelling... Pt 2, session %@",self.sessionId); + DASFKLog(@"[2] Cancelling... , session %@",self.sessionId); break; } - busyCount.fetch_sub(1); + if([cblk flushRequested]){ result=nil; } + id res = result; - if(summary){ - res=summary(cblk,@{},result); + { + [q unoccupy]; + + if(summary && (result!=((ASFKThreadpoolQueueHyb*)[dataQueues objectAtIndex:0])->itsSig)){ + res=summary(cblk,@{},result); + } + + if(result==((ASFKThreadpoolQueueHyb*)[dataQueues objectAtIndex:0])->itsSig){ + [(ASFKThreadpoolQueueHyb*)[dataQueues objectAtIndex:0] _releaseBlocked]; + } + else{ + busyCount.fetch_sub(1); + } } + if(trp){ [trp setSampleLongLong:busyCount]; if([trp isConditionMet:result]){ @@ -472,35 +592,43 @@ -(eASFKThreadpoolExecutionStatus) select:(long)selector routineCancel:(ASFKCance } } - else if(curpos0){ - nextQ=(curpos+1)%dco; - }else{ + if(result!=((ASFKThreadpoolQueueHyb*)[dataQueues objectAtIndex:0])->itsSig){ + result=eproc(cblk,result,itemIndex); + if(!result){ + result=[NSNull null]; + } + } + + if([cblk flushRequested]){ + [cblk flushRequested:NO]; + } + else{ + [lock lock]; + sizeQData_t dco=[dataQueues count]; + sizeQData_t nextQ; + if(dco>0){ + nextQ=(curpos+1)%dco; + }else{ + [lock unlock]; + break; + } + sq0.queueId=nextQ; + sq0.priority=[[dataQueues objectAtIndex:nextQ] count]; + pq.push(sq0); + [[dataQueues objectAtIndex:nextQ]castObject:result exParams:nil index:itemIndex]; + if(term){ + [[dataQueues objectAtIndex:nextQ]castObject:term exParams:nil index:itemIndex]; + } [lock unlock]; - break; + [q unoccupy]; } - sq0.queueId=nextQ; - sq0.priority=[[dataQueues objectAtIndex:nextQ] count]; - pq.push(sq0); - [[dataQueues objectAtIndex:nextQ]castObject:result session:nil exParam:nil]; - [lock unlock]; - } } } else{ @@ -523,6 +651,7 @@ -(eASFKThreadpoolExecutionStatus) select:(long)selector routineCancel:(ASFKCance [lock lock]; pq.push(sq); [lock unlock]; + } } } diff --git a/src/ASFKPrjConfig.h b/src/ASFKPrjConfig.h index 543d2d6..8633a65 100644 --- a/src/ASFKPrjConfig.h +++ b/src/ASFKPrjConfig.h @@ -12,22 +12,60 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// +// Created by Boris Vigman on 05/04/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. #ifndef ASFKPrjConfig_h #define ASFKPrjConfig_h #define __ASFK_DEBUG__ 1 +#define __ASFK_WARNING__ 1 +#define __ASFK_ERROR__ 1 +#define __ASFK_MISUSE__ 1 + #define __ASFK_VERBOSE_PRINTING__ 1 #define ASFK_PRIVSYM_TP_LOAD_FACTOR 1 +#define ASFK_PRIVSYM_TP_SESSIONS_LIMIT 1000 +#define ASFK_PRIVSYM_TP_ITEMS_PER_SESSION_LIMIT 1000 +#define ASFK_PRIVSYM_TP_PROCS_PER_SESSION_LIMIT 1000 #define ASFK_PRIVSYM_QOS_CLASS QOS_CLASS_BACKGROUND -#define ASFK_PRIVSYM_MEM_PRESSURE_MSG_THRESHOLD 1000000 -#define ASFK_PRIVSYM_MEM_PRESSURE_MLBX_THRESHOLD 1000000 -#define ASFK_PRIVSYM_PER_MLBX_MAX_MSG_LIMIT 1000000 -#define ASFK_PRIVSYM_MAX_MLBX_LIMIT 100000 + +/*! + @brief Upper limit for messages per group or standalone mailbox. + */ +#define ASFK_PRIVSYM_MLBX_MSG_PER_CONT_LIMIT 1000000 + +/*! +@brief Upper limit for sum of all groups, mailboxes, posted messages. +@discussion Upper limit for sum of all groups, mailboxes, posted messages. Deleted, but not yet physically removed messages, groups and mailboxes included too. +*/ +#define ASFK_PRIVSYM_MBLX_TOTAL_OBJ_LIMIT 100000 + +/*! + @brief Maximum number of all posted messages in the system + */ +#define ASFK_PRIVSYM_MBLX_BRCAST_MSG_LIMIT 1000 + +/*! + @brief Maximum number of recipients of multicast messages + */ +#define ASFK_PRIVSYM_MBLX_MULTICAST_RECV_LIMIT 100 + +/*! + @brief Maximum number of standalone mailboxes in system + */ +#define ASFK_PRIVSYM_MLBX_MAX_MLBX_LIMIT 10000 + +/*! + @brief Maximum number of groups in system + */ +#define ASFK_PRIVSYM_MLBX_MAX_GRPS_LIMIT 10000 + #define ASFK_PRIVSYM_MSG_RELEASE_SAMPLE_SIZE 10000 #define ASFK_PRIVSYM_OBJ_RELEASE_SAMPLE_SIZE 10000 + #define ASFK_CALC_ELAPSED_TIME(starttime, endtime) (endtime-starttime)/double(1e9) #define ASFK_RC_DESCR_DONE @"OK" @@ -36,8 +74,18 @@ #define ASFK_RC_DESCR_DEFERRED @"Deferred" #define ASFK_RC_DESCR_IMPROPER @"Improper" +#define ASFK_STR_UP_LIMITS_REACHED_SES @"Maximal number of sessions reached" +#define ASFK_STR_UP_LIMITS_REACHED_DATA @"Maximal number of data items per session reached" #define ASFK_STR_INVALID_PARAM @"some of input parameters are invalid" - - +#define ASFK_STR_MISCONFIG_OP @"Operation not allowed due to inappropriate configuration" +#define ASFK_STR_UNSUPPORTED_OP @"Unsupported operation for this class" +#define ASFK_STR_WRONG_METHOD_CALL @"Method should not be called" +#define ASFK_STR_VER_UNAVAIL_OP @"Functionality unavailable in this version" +#define ASFK_STR_TOO_MANY_MSG_NOTIF @"Too many messages posted; operation canceled" +#define ASFK_STR_TOO_MANY_MLBX_NOTIF @"Too many mailboxes exist; operation canceled" +#define ASFK_STR_TOO_MANY_GRPS_NOTIF @"Too many group exist; operation canceled" +#define ASFK_STR_Q_LLIMIT_VIOLATION @"Queue's lower limit violated" +#define ASFK_STR_Q_ULIMIT_VIOLATION @"Queue's upper limit violated" +#define ASFK_STR_SEC_CHECK_FAIL @"Security check failed" #endif /* ASFKPrjConfig_h */ diff --git a/src/ASFKQueue+Internal.h b/src/ASFKQueue+Internal.h index 23a26fd..bf961f1 100644 --- a/src/ASFKQueue+Internal.h +++ b/src/ASFKQueue+Internal.h @@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase.h" diff --git a/src/ASFKQueue+Internal.mm b/src/ASFKQueue+Internal.mm index d7deb17..e054a2e 100644 --- a/src/ASFKQueue+Internal.mm +++ b/src/ASFKQueue+Internal.mm @@ -12,7 +12,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKQueue+Internal.h" diff --git a/src/ASFKQueue.mm b/src/ASFKQueue.mm index f0ead10..480861e 100644 --- a/src/ASFKQueue.mm +++ b/src/ASFKQueue.mm @@ -12,20 +12,259 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase.h" -@implementation ASFKQueue +#import "ASFKQueue+Internal.h" + +@implementation ASFKQueue{ + std::atomic condPredR; + std::atomic condPredW; + NSCondition* condR; + NSCondition* condW; +} -(id)init{ self=[super init]; if(self){ - q=[NSMutableArray array]; - lock=[NSLock new]; - + [self _initQ:NO]; + } + return self; +} + +-(id)initWithName:(NSString*)name{ + self=[super initWithName:name]; + if(self){ + [self _initQ:NO]; } return self; } +-(id) initWithName:(NSString*) name blocking:(BOOL)blk{ + self=[super initWithName:name]; + if(self){ + [self _initQ:blk]; + } + return self; +} +-(void) _initQ:(BOOL)blk{ + q=[NSMutableArray array]; + lock=[NSLock new]; + minQSize=0; + maxQSize=ULONG_MAX; + condPredR=NO; + condPredW=NO; + paused=NO; + condR=nil; + condW=nil; + blocking=blk; + if(blocking){ + condR=[NSCondition new]; + condW=[NSCondition new]; + } +} +-(BOOL) isBlocking{ + return blocking; +} +#pragma mark - Configuration +-(BOOL) setMaxQSize:(NSUInteger)size{ + BOOL r=YES; + if(size < minQSize.load()){ + r=NO; + WASFKLog(@"new upper limit is not greater than lower limit"); + } + maxQSize=size; + return r; +} +-(BOOL) setMinQSize:(NSUInteger)size{ + BOOL r=YES; + if(size > maxQSize.load()){ + r=NO; + WASFKLog(@"new lower limit is not less than upper limit"); + } + minQSize=size; + return r; +} +#pragma mark - Insertion +-(void) queueFromQueue:(ASFKQueue*)otherq{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); +} +-(void) queueFromArray:(NSArray*)array{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); +} +-(void) queueFromOrderedSet:(NSOrderedSet*)set{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); +} +-(void) queueFromUnorderedSet:(NSSet*)set{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); +} +-(void) queueFromDictionary:(NSDictionary*)dict{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); +} +#pragma mark - prepending +-(BOOL) prependFromQueue:(ASFKQueue*)otherq{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return NO; +} +-(BOOL) prependFromArray:(NSArray*)array{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return NO; +} +-(BOOL) prependFromOrderedSet:(NSOrderedSet*)set{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return NO; +} +-(BOOL) prependFromUnorderedSet:(NSSet*)set{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return NO; +} +-(BOOL) prependFromDictionary:(NSDictionary*)dict{ + if(blocking==NO && dict){ + [lock lock]; + [dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { + [q insertObject:obj atIndex:0]; + }]; + [lock unlock]; + return YES; + } + return NO; +} +#pragma mark - Non-blocking interface +-(BOOL) castQueue:(ASFKQueue* _Nullable)otherq exParams:(ASFKExecutionParams* _Nullable)ex{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return NO; +} +-(BOOL)castObject:(id _Nullable)item exParams:(ASFKExecutionParams* _Nullable)ex{ + if(item){ + [lock lock]; + BOOL insert=[q count]+1<=maxQSize?YES:NO; + if(insert){ + [q addObject:item]; + } + [lock unlock]; + if(insert==YES){ + if(blocking){ + [condR lock]; + condPredR=YES; + [condR signal]; + [condR unlock]; + } + } + + return insert; + } + return NO; +} +-(BOOL) castArray:(NSArray* _Nullable)array exParams:(ASFKExecutionParams* _Nullable)ex{ + if(array){ + [lock lock]; + BOOL insert=[q count]+[array count]<=maxQSize?YES:NO; + if(insert){ + [q addObjectsFromArray:array]; + } + [lock unlock]; + if(insert==YES){ + if(blocking){ + [condR lock]; + condPredR=YES; + [condR signal]; + [condR unlock]; + } + } + return insert; + } + return NO; +} +-(BOOL) castDictionary:(NSDictionary* _Nullable)dict exParams:(ASFKExecutionParams* _Nullable)ex{ + if(dict){ + [lock lock]; + BOOL insert=[q count]+[dict count]<=maxQSize?YES:NO; + if(insert){ + [q addObjectsFromArray:[dict allValues]]; + } + [lock unlock]; + if(insert==YES){ + if(blocking){ + [condR lock]; + condPredR=YES; + [condR signal]; + [condR unlock]; + } + } + return insert; + } + return NO; +} +-(BOOL) castOrderedSet:(NSOrderedSet* _Nullable)set exParams:(ASFKExecutionParams* _Nullable)ex{ + if(set){ + [lock lock]; + BOOL insert=[q count]+[set count]<=maxQSize?YES:NO; + if(insert){ + [q addObjectsFromArray:[set array]]; + } + [lock unlock]; + if(insert==YES){ + if(blocking){ + [condR lock]; + condPredR=YES; + [condR signal]; + [condR unlock]; + } + } + return insert; + } + return NO; +} +-(BOOL) castUnorderedSet:(NSSet* _Nullable)set exParams:(ASFKExecutionParams* _Nullable)ex{ + if(set){ + [lock lock]; + BOOL insert=[q count]+[set count]<=maxQSize?YES:NO; + if(insert){ + [q addObjectsFromArray:[set allObjects]]; + } + [lock unlock]; + if(insert==YES){ + if(blocking){ + [condR lock]; + condPredR=YES; + [condR signal]; + [condR unlock]; + } + } + return insert; + } + return NO; +} + +#pragma mark - Blocking interface +-(BOOL) callQueue:(ASFKQueue*)otherq exParams:(ASFKExecutionParams*) expar{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return NO; +} +-(BOOL) callArray:(NSArray* _Nullable)array exParams:(ASFKExecutionParams* _Nullable) expar{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + + return NO; +} +-(BOOL) callDictionary:(NSDictionary* _Nullable)dict exParams:(ASFKExecutionParams* _Nullable) expar{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return NO; +} +-(BOOL) callOrderedSet:(NSOrderedSet* _Nullable)set exParams:(ASFKExecutionParams* _Nullable) expar{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + + return NO; +} +-(BOOL) callUnorderedSet:(NSSet* _Nullable)set exParams:(ASFKExecutionParams* _Nullable) expar{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + + return NO; +} +-(BOOL) callObject:(id _Nullable)item exParams:(ASFKExecutionParams* _Nullable) expar{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + + return NO; +} +#pragma mark - querying -(BOOL) isEmpty{ [lock lock]; BOOL e=[q count]>0?NO:YES; @@ -38,30 +277,72 @@ -(NSUInteger )count{ [lock unlock]; return c; } --(BOOL)push:(id)item{ - if(item){ + +-(id)pull{ + if(paused){ + return nil; + } + if(blocking){ [lock lock]; - [q addObject:item]; + NSUInteger c=[q count]; [lock unlock]; - return YES; + if(c<=minQSize){ + [condR lock]; + condPredR=NO; + while(condPredR==NO){ + [condR wait]; + [lock lock]; + condPredR=[q count]>0?YES:NO; + [lock unlock]; + } + [condR unlock]; + } + else{ + condPredR=YES; + } } - return NO; - -} --(id)pull{ [lock lock]; - id item=[q firstObject]; - if (item) { + id item=[q count]>minQSize?[q firstObject]:nil; + if(item) + { [q removeObjectAtIndex:0]; + if(blocking){ + [condW lock]; + condPredW=YES; + [condW signal]; + [condW unlock]; + } } - [lock unlock];; + [lock unlock]; + return item; } -(void)reset{ [lock lock]; [q removeAllObjects]; + if(blocking){ + [condR lock]; + condPredR=YES; + [condR broadcast]; + [condR unlock]; + + [condW lock]; + condPredW=YES; + [condW broadcast]; + [condW unlock]; + } [lock unlock];; } - +-(void) purge{ + [lock lock]; + [q removeAllObjects]; + [lock unlock];; +} +-(void) pause{ + paused=YES; +} +-(void) resume{ + paused=NO; +} @end diff --git a/src/ASFKLinearFlow+Internal.h b/src/ASFKSessionalFlow+Internal.h similarity index 71% rename from src/ASFKLinearFlow+Internal.h rename to src/ASFKSessionalFlow+Internal.h index d4fb0c1..1fb36bb 100644 --- a/src/ASFKLinearFlow+Internal.h +++ b/src/ASFKSessionalFlow+Internal.h @@ -12,11 +12,12 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 15/02/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase.h" -#import "ASFKExpirationCondition.h" + @interface ASFKParamSet:NSObject @property (nonatomic) NSMutableArray* procs; @property (nonatomic) NSMutableDictionary* namedprocs; @@ -27,25 +28,22 @@ @property (nonatomic) ASFKOnPauseNotification onPause; @property (nonatomic) id input; @property (nonatomic) ASFK_IDENTITY_TYPE sessionId; -//@property (nonatomic) BOOL hasForeignProcs; +@property (nonatomic) eASFKBlockingCallMode bcallMode; +@property (nonatomic) ASFKReturnInfo* retInfo; +-(void) setupReturnInfo; @end -@interface ASFKLinearFlow (Internal) --(NSDictionary*) _castUnorderedSet:(ASFKParamSet*) params; --(NSDictionary*) _castOrderedSet:(ASFKParamSet*) params; --(NSDictionary*) _castArray:(ASFKParamSet*) params; --(NSDictionary*) _castDictionary:(ASFKParamSet*) params; --(NSDictionary*) _callUnorderedSet:(ASFKParamSet*) params; --(NSDictionary*) _callOrderedSet:(ASFKParamSet*) params; --(NSDictionary*) _callArray:(ASFKParamSet*) params; +@interface ASFKSessionalFlow (Internal) +-(NSDictionary*) _postUnorderedSet:(ASFKParamSet*) params blocking:(BOOL)blk; +-(NSDictionary*) _postOrderedSet:(ASFKParamSet*) params blocking:(BOOL)blk; +-(NSDictionary*) _postArray:(ASFKParamSet*) params blocking:(BOOL)blk; +-(NSDictionary*) _postDictionary:(ASFKParamSet*) params blocking:(BOOL)blk; -(NSDictionary*) _callDictionary:(ASFKParamSet*) params; -(ASFKParamSet*) _convertInputDictionary:(NSDictionary*) input to:(ASFKParamSet*)ps; -(ASFKParamSet*) _convertInputArray:(NSArray*) input to:(ASFKParamSet*)ps; -(ASFKParamSet*) _convertInputOrderedSet:(NSOrderedSet*) input to:(ASFKParamSet*)ps; -(ASFKParamSet*) _convertInputUnorderedSet:(NSSet*) input to:(ASFKParamSet*)ps; -(ASFKParamSet*) _convertInput:(id) input to:(ASFKParamSet*)ps; +-(ASFKParamSet*) _decodeSessionParams:(ASFKSessionConfigParams*)ex forSession:(id)sessionId; -(ASFKParamSet*) _decodeExParams:(ASFKExecutionParams*)ex forSession:(id)sessionId; -//-(void) _registerSession:(id)sessionId; -//-(void) _unregisterSession:(id)sessionId; -//-(void) _unregisterAllSessions; @end diff --git a/src/ASFKLinearFlow+Internal.mm b/src/ASFKSessionalFlow+Internal.mm similarity index 84% rename from src/ASFKLinearFlow+Internal.mm rename to src/ASFKSessionalFlow+Internal.mm index 18f0e84..0a42852 100644 --- a/src/ASFKLinearFlow+Internal.mm +++ b/src/ASFKSessionalFlow+Internal.mm @@ -13,12 +13,13 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 15/02/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // -#import "ASFKLinearFlow+Internal.h" +#import "ASFKSessionalFlow+Internal.h" -@implementation ASFKLinearFlow (Internal) +@implementation ASFKSessionalFlow (Internal) -(ASFKParamSet*) _convertInputDictionary:(NSDictionary*) input to:(ASFKParamSet*)ps{ if(input){ ps.input=input; @@ -73,8 +74,13 @@ -(id) init{ self.input=nil; self.excond=nil; self.sessionId=nil; + self.retInfo=nil; } return self; } - +-(void) setupReturnInfo{ + if(self.retInfo == nil){ + self.retInfo=[ASFKReturnInfo new]; + } +} @end diff --git a/src/ASFKSessionalFlow.mm b/src/ASFKSessionalFlow.mm new file mode 100644 index 0000000..ca33bee --- /dev/null +++ b/src/ASFKSessionalFlow.mm @@ -0,0 +1,348 @@ +/* + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +// Created by Boris Vigman on 28/02/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. +// + +#import "ASFKBase.h" +#import "ASFKBase+Statistics.h" +#import "ASFKSessionalFlow+Internal.h" +#import "ASFKBase+Internal.h" +#include +@interface ASFKSessionalFlow() + +@end +@implementation ASFKSessionalFlow{ + std::atomic itsSessionsLimit; + std::atomic itsSessionItemsLimit; + std::atomic itsProcsPerSessionLimit; + std::atomic itsIsReady; +} +-(id)init{ + self=[super init]; + if(self){ + [self _initSeF]; + } + return self; +} +-(id)initWithName:(NSString*)name{ + self=[super initWithName:name]; + if(self){ + [self _initSeF]; + } + return self; +} +-(void) _initSeF{ + itsIsReady=YES; + _backprocs=[[NSMutableArray alloc]init]; + lfProcs=_backprocs; + sumProc=(id)^(id controlBlock,NSDictionary* stats,id data){ + ASFKLog(@"ASFKLinearFlow: Stub summary"); + return data; + }; + cancellationHandler=nil; + progressProc=nil; + itsSessionsLimit=ASFK_PRIVSYM_TP_SESSIONS_LIMIT; + itsSessionItemsLimit=ASFK_PRIVSYM_TP_ITEMS_PER_SESSION_LIMIT; + itsProcsPerSessionLimit=ASFK_PRIVSYM_TP_PROCS_PER_SESSION_LIMIT; + semHighLevelCall=dispatch_semaphore_create(1); + +} +-(std::uint64_t) getRoutinesCount{ + [lkNonLocal lock]; + std::uint64_t count=[lfProcs count]; + [lkNonLocal unlock]; + return count; +} +-(std::uint64_t) getDataItemsCount{ + return 0; +} +-(NSArray *) getRoutines{ + [lkNonLocal lock]; + NSMutableArray * a=[NSMutableArray array]; + for (ASFKExecutableRoutine p in lfProcs) { + [a addObject:[p copy]]; + } + [lkNonLocal unlock]; + return a; +} +-(ASFKExecutableRoutineSummary) getSummaryRoutine{ + [lkNonLocal lock]; + ASFKExecutableRoutineSummary c=sumProc; + [lkNonLocal unlock]; + return c; +} +-(ASFKCancellationRoutine) getCancellationHandler{ + [lkNonLocal lock]; + ASFKCancellationRoutine c=cancellationHandler; + [lkNonLocal unlock]; + return c; +} +-(ASFKProgressRoutine) getProgressRoutine{ + [lkNonLocal lock]; + ASFKProgressRoutine p=progressProc; + [lkNonLocal unlock]; + return p; +} +-(BOOL) setProgressRoutine:(ASFKProgressRoutine)pro{ + if(pro){ + dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); + itsIsReady=NO; + [lkNonLocal lock]; + progressProc=nil; + progressProc=pro; + [lkNonLocal unlock]; + itsIsReady=YES; + dispatch_semaphore_signal(semHighLevelCall); + }else{ + EASFKLog(@"ASFKLinearFlow: Invalid Progress Handler provided"); + return NO; + } + return YES; +} +-(BOOL) addRoutine:(ASFKExecutableRoutine)proc{ + if(proc){ + dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); + itsIsReady=NO; + [lkNonLocal lock]; + [_backprocs addObject:proc]; + [lkNonLocal unlock]; + itsIsReady=YES; + dispatch_semaphore_signal(semHighLevelCall); + }else{ + EASFKLog(@"ASFKLinearFlow: Invalid Routine provided"); + return NO; + } + + return YES; +} +-(BOOL) addRoutines:(NSArray*)procs{ + if(procs && [procs count]>0){ + dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); + itsIsReady=NO; + [lkNonLocal lock]; + [_backprocs addObjectsFromArray:procs]; + [lkNonLocal unlock]; + itsIsReady=YES; + dispatch_semaphore_signal(semHighLevelCall); + }else{ + EASFKLog(@"ASFKLinearFlow: Invalid Routine(s) provided"); + return NO; + } + return YES; +} +-(BOOL) replaceRoutinesFromArray:(NSArray*)someprocs{ + BOOL replaced=NO; + dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); + itsIsReady=NO; + [lkNonLocal lock]; + [_backprocs removeAllObjects]; + if(someprocs && [someprocs count]>0){ + [_backprocs addObjectsFromArray:someprocs]; + replaced=YES; + } + [lkNonLocal unlock]; + itsIsReady=YES; + dispatch_semaphore_signal(semHighLevelCall); + if(replaced==NO){ + WASFKLog(@"ASFKLinearFlow: Routines were removed"); + } + return replaced; +} +-(BOOL) isReady{ + return itsIsReady; +} +-(BOOL) setOnPauseNotification:(ASFKOnPauseNotification)notification{ + if(notification){ + dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); + itsIsReady=NO; + [lkNonLocal lock]; + onPauseProc=notification; + [lkNonLocal unlock]; + itsIsReady=YES; + dispatch_semaphore_signal(semHighLevelCall); + } + else{ + EASFKLog(@"ASFKLinearFlow: Invalid Routine provided"); + return NO; + } + return YES; +} +-(BOOL) setSummary:(ASFKExecutableRoutineSummary)summary{ + if(summary){ + dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); + itsIsReady=NO; + [lkNonLocal lock]; + sumProc=nil; + sumProc=summary; + [lkNonLocal unlock]; + itsIsReady=YES; + dispatch_semaphore_signal(semHighLevelCall); + }else{ + EASFKLog(@"ASFKLinearFlow: Invalid Routine provided"); + return NO; + } + return YES; +} + +-(BOOL) setCancellationHandler:(ASFKCancellationRoutine)ch{ + if(ch){ + dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); + itsIsReady=NO; + [lkNonLocal lock]; + cancellationHandler=nil; + cancellationHandler=ch; + [lkNonLocal unlock]; + itsIsReady=YES; + dispatch_semaphore_signal(semHighLevelCall); + } + else{ + EASFKLog(@"ASFKLinearFlow: Invalid Cancellation Handler provided"); + return NO; + } + return YES; +} + +#pragma mark - Non-blocking methods +-(NSDictionary*) castOrderedSet:(NSOrderedSet*)set session:(id)sessionId exParams:(ASFKExecutionParams*)ex{ + dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); + ASFKParamSet* params=[ASFKParamSet new]; + params.sessionId=sessionId; + params=[self _convertInputOrderedSet:set to:params]; + dispatch_semaphore_signal(semHighLevelCall); + NSDictionary* res= [self _postOrderedSet:params blocking:NO]; + + return res; +} +-(NSDictionary*) castUnorderedSet:(NSSet*)set session:(id)sessionId exParams:(ASFKExecutionParams*)ex{ + dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); + ASFKParamSet* params=[ASFKParamSet new]; + params.sessionId=sessionId; + params=[self _convertInputUnorderedSet:set to:params]; + dispatch_semaphore_signal(semHighLevelCall); + NSDictionary* res= [self _postUnorderedSet:params blocking:NO]; + + return res; +} +-(NSDictionary*) castArray:(NSArray*)array session:(id)sessionId exParams:(ASFKExecutionParams*)ex{ + dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); + ASFKParamSet* params=[ASFKParamSet new]; + params.sessionId=sessionId; + params=[self _convertInputArray:array to:params]; + dispatch_semaphore_signal(semHighLevelCall); + + NSDictionary* res= [self _postArray:params blocking:NO]; + + return res; +} + +-(NSDictionary*) castDictionary:(NSDictionary*)dictionary session:(id)sessionId exParams:(ASFKExecutionParams*)ex{ + dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); + ASFKParamSet* params=[ASFKParamSet new]; + params.sessionId=sessionId; + params=[self _convertInputDictionary:dictionary to:params]; + dispatch_semaphore_signal(semHighLevelCall); + NSDictionary* res= [self _postDictionary:params blocking:NO]; + + return res; +} + +-(NSDictionary*) castObject:(id)uns session:(id)sessionId exParams:(ASFKExecutionParams*)ex{ + dispatch_semaphore_wait(semHighLevelCall, DISPATCH_TIME_FOREVER); + ASFKParamSet* params=[ASFKParamSet new]; + params.sessionId=sessionId; + params=[self _convertInput:uns to:params]; + dispatch_semaphore_signal(semHighLevelCall); + NSDictionary* res= [self _postArray:params blocking:NO]; + return res; +} +#pragma mark - Blocking methods +-(NSDictionary*) callOrderedSet:(NSOrderedSet*)set session:(id)sessionId exParams:(ASFKExecutionParams*)ex{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + + return @{}; +} +-(NSDictionary*) callUnorderedSet:(NSSet*)set session:(id)sessionId exParams:(ASFKExecutionParams*)ex{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + + return @{}; +} + +-(NSDictionary*) callArray:(NSArray*)array session:(id)sessionId exParams:(ASFKExecutionParams*)ex{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + + return @{}; +} + +-(NSDictionary*) callDictionary:(NSDictionary*)dictionary session:(id)sessionId exParams:(ASFKExecutionParams*)ex{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + + return @{}; +} + +-(NSDictionary*) callObject:(id)uns session:(id)sessionId exParams:(ASFKExecutionParams*)ex{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + + return @{}; +} + +#pragma mark - private methods +-(ASFKParamSet*) _decodeSessionParams:(ASFKSessionConfigParams*)ex forSession:(id)sessionId{ + ASFKParamSet* expar=[ASFKParamSet new]; + if(ex){ + expar.summary = ex->summaryRoutine?ex->summaryRoutine:sumProc; + expar.procs = [NSMutableArray array]; + NSArray* prarr=ex->procs; + if(prarr==nil || [prarr count]==0 || [prarr isKindOfClass:[NSNull class]]){ + prarr=_backprocs; + } + for (ASFKExecutableRoutine p in prarr){ + [expar.procs addObject:[p copy]]; + }; + + expar.onPause = ex->onPauseProc?ex->onPauseProc:onPauseProc; + expar.cancProc = ex->cancellationProc?ex->cancellationProc:cancellationHandler; + expar.excond=ex->expCondition; + expar.progress = ex->progressProc?ex->progressProc:progressProc; + expar.sessionId=sessionId; + expar.bcallMode=ex->blockCallMode; + } + + return expar; +} +-(ASFKParamSet*) _decodeExParams:(ASFKSessionConfigParams*)ex forSession:(id)sessionId{ + ASFKParamSet* expar=[ASFKParamSet new]; + if(ex){ + expar.summary = ex->summaryRoutine?ex->summaryRoutine:sumProc; + expar.procs = [NSMutableArray array]; + NSArray* prarr=ex->procs; + if(prarr==nil || [prarr count]==0 || [prarr isKindOfClass:[NSNull class]]){ + prarr=_backprocs; + } + for (ASFKExecutableRoutine p in prarr){ + [expar.procs addObject:[p copy]]; + }; + + expar.onPause = ex->onPauseProc?ex->onPauseProc:onPauseProc; + expar.cancProc = ex->cancellationProc?ex->cancellationProc:cancellationHandler; + expar.excond=ex->expCondition; + expar.progress = ex->progressProc?ex->progressProc:progressProc; + expar.sessionId=sessionId; + } + + return expar; +} +@end diff --git a/src/ASFKThreadpoolQueue.mm b/src/ASFKThreadpoolQueue.mm index c5b33ef..feb35d4 100644 --- a/src/ASFKThreadpoolQueue.mm +++ b/src/ASFKThreadpoolQueue.mm @@ -12,14 +12,25 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -// Copyright © 2019-2022 Boris Vigman. All rights reserved. +// Created by Boris Vigman on 23/02/2019. +// Copyright © 2019-2023 Boris Vigman. All rights reserved. // #import "ASFKBase.h" -#import "ASFKLinearFlow+Internal.h" +#import "ASFKSessionalFlow+Internal.h" #import "ASFKQueue+Internal.h" +#import + +enum eQSpecificity{ + ASFK_E_QSPEC_NONE, + ASFK_E_QSPEC_REG, + ASFK_E_QSPEC_BAT +}; + +typedef std::deque> tQMapper; + @implementation ASFKThreadpoolQueue{ - long occupant; + std::deque deqIndexes; } -(id)init{ self=[super init]; @@ -28,58 +39,46 @@ -(id)init{ } return self; } --(NSDictionary*) _castUnorderedSet:(ASFKParamSet*) params{ + +-(NSDictionary*) _postUnorderedSet:(ASFKParamSet*) params blocking:(BOOL) blk{ NSSet* input=params.input; [self _queueFromUnorderedSet:input]; return @{}; } --(NSDictionary*) _castOrderedSet:(ASFKParamSet*) params{ +-(NSDictionary*) _postOrderedSet:(ASFKParamSet*) params blocking:(BOOL) blk{ NSOrderedSet* input=params.input; [self _queueFromOrderedSet:input]; return @{}; } --(NSDictionary*) _castArray:(ASFKParamSet*) params{ +-(NSDictionary*) _postArray:(ASFKParamSet*)params blocking:(BOOL) blk{ NSArray* input=params.input; [self _queueFromArray:input]; return @{}; } -(void) _queueFromOrderedSet:(NSOrderedSet *)set{ - for (id item in set) { - [q addObject:item]; + if(set){ + for (id item in set) { + [q addObject:item]; + } } } -(void) _queueFromUnorderedSet:(NSSet *)set{ - for (id item in set) { - [q addObject:item]; + if(set){ + for (id item in set) { + [q addObject:item]; + } } } -(void) _queueFromArray:(NSArray *)array{ - for (id item in array) { - [q addObject:item]; + if(array){ + for (id item in array) { + [q addObject:item]; + } } } --(void) queueFromArray:(NSArray*)array{ - [lock lock]; - [self _queueFromArray:array]; - [lock unlock]; -} --(void) queueFromOrderedSet:(NSOrderedSet*)set{ - [lock lock]; - [self _queueFromOrderedSet:set]; - [lock unlock]; -} --(void) queueFromUnorderedSet:(NSSet*)set{ - [lock lock]; - [self _queueFromUnorderedSet:set]; - [lock unlock]; -} --(void) queueFromItem:(id)item{ - [lock lock]; - [q addObject:item]; - [lock unlock]; -} --(void) queueFromQueue:(ASFKThreadpoolQueue*)queue{ + +-(void) queueFromThreadpoolQueue:(ASFKThreadpoolQueue*)queue{ [lock lock]; [queue begin]; NSArray* data=[queue getData]; @@ -87,7 +86,49 @@ -(void) queueFromQueue:(ASFKThreadpoolQueue*)queue{ [queue commit]; [lock unlock]; } --(id)pullAndOccupyWithId:(long)itsid empty:(BOOL &)empty{ +#pragma mark - Prepending (disabled) +-(BOOL) prependFromQueue:(ASFKQueue*)otherq{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) prependFromArray:(NSArray*)array{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) prependFromOrderedSet:(NSOrderedSet*)set{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) prependFromUnorderedSet:(NSSet*)set{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) prependFromDictionary:(NSDictionary*)dict{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} + +-(BOOL)castObject:(id)item exParams:(ASFKExecutionParams*)ex index:(NSInteger)index{ + if(item){ + [lock lock]; + [q addObject:item]; + deqIndexes.push_back(index); + [lock unlock]; + + return YES; + } + return NO; +} +#pragma mark - Pulling +-(id) pullAndOccupyWithId:(long)itsid empty:(BOOL&)empty index:(NSInteger&)itemIndex term:(ASFKPriv_EndingTerm**)term{ + itemIndex=-1; +// if(paused){ +// [lock lock]; +// occupant=-1; +// empty=[q count]>0?NO:YES; +// [lock unlock]; +// return nil; +// } [lock lock]; if(occupant>=0 && occupant!=itsid){ empty=YES; @@ -100,6 +141,8 @@ -(id)pullAndOccupyWithId:(long)itsid empty:(BOOL &)empty{ id item=[q firstObject]; if (item) { + itemIndex=deqIndexes.front(); + deqIndexes.pop_front(); [q removeObjectAtIndex:0]; if([q count]>0){ occupant=itsid; @@ -116,6 +159,7 @@ -(id)pullAndOccupyWithId:(long)itsid empty:(BOOL &)empty{ [lock unlock];; return item; } +#pragma mark - Maintenance -(void)unoccupyWithId:(long)itsid{ [lock lock]; if(occupant==itsid){ @@ -138,6 +182,335 @@ -(void)reset{ [lock lock]; [q removeAllObjects]; occupant=-1; + deqIndexes.clear(); + [lock unlock];; +} +@end + +@implementation ASFKThreadpoolQueueHyb{ + std::atomic lastItem; + ASFKQueue* regQ; + ASFKBatchingQueue2* blkQ; + std::deque> qmapper; +} +-(id)init{ + self=[super init]; + if(self){ + [self _initTQHyb]; + blkQ=nil; + + } + return self; +} +-(id)initWithBlkMode:(eASFKBlockingCallMode)blockingMode{ + self=[super init]; + if(self){ + [self _initTQHyb]; + if(blockingMode==ASFK_BC_EXCLUSIVE){ + blkQ = [[ASFKBatchingQueue2 alloc]initWithName:@"blkQ" blocking:YES]; + //[blkQ setBlockingModeOn]; + } + else if(blockingMode==ASFK_BC_CONTINUOUS){ + blkQ = [[ASFKBatchingQueue3 alloc]initWithName:@"blkQ" blocking:YES]; + //[blkQ setBlockingModeOn]; + } + else + { + blkQ=nil; + } + } + return self; +} +-(void) _initTQHyb{ + + lastItem=ASFK_E_QSPEC_NONE; + regQ = [[ASFKQueue alloc]initWithName:@"regQ"]; + itsSig=self; + q=nil; + +} + +-(NSDictionary*) _postUnorderedSet:(ASFKParamSet*) params blocking:(BOOL) blk{ + NSSet* input=params.input; + [self _queueFromUnorderedSet:input]; + return @{}; +} +-(NSDictionary*) _postOrderedSet:(ASFKParamSet*) params blocking:(BOOL) blk{ + NSOrderedSet* input=params.input; + [self _queueFromOrderedSet:input]; + return @{}; +} +-(NSDictionary*) _postArray:(ASFKParamSet*)params blocking:(BOOL) blk{ + NSArray* input=params.input; + [self _queueFromArray:input]; + return @{}; +} + +-(void) _queueFromOrderedSet:(NSOrderedSet *)set{ + if(set){ + for (id item in set) { + [q addObject:item]; + } + } +} +-(void) _queueFromUnorderedSet:(NSSet *)set{ + if(set){ + for (id item in set) { + [q addObject:item]; + } + } +} +-(void) _queueFromArray:(NSArray *)array{ + if(array){ + for (id item in array) { + [q addObject:item]; + } + } +} +-(void) queueFromThreadpoolQueue:(ASFKThreadpoolQueue*)queue{ + [lock lock]; + [queue begin]; + NSArray* data=[queue getData]; + [self _queueFromArray:data]; + [queue commit]; + [lock unlock]; +} +#pragma mark - Prepending (disabled) +-(BOOL) prependFromQueue:(ASFKQueue*)otherq{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) prependFromArray:(NSArray*)array{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) prependFromOrderedSet:(NSOrderedSet*)set{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) prependFromUnorderedSet:(NSSet*)set{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +-(BOOL) prependFromDictionary:(NSDictionary*)dict{ + DASFKLog(ASFK_STR_UNSUPPORTED_OP); + return NO; +} +#pragma mark - Nonblocking interface +-(BOOL) castArray:(NSArray *)array exParams:(ASFKExecutionParams*)ex{ + if(array){ + NSUInteger c=[array count]; + if(c>0){ + [lock lock]; + qmapper.push_back(std::make_pair(ASFK_E_QSPEC_REG, c)); + [regQ castArray:array exParams:nil]; + [lock unlock]; + + } + } + return NO; +} +-(BOOL) castUnorderedSet:(NSSet *)set exParams:(ASFKExecutionParams *)ex{ + if(set){ + NSUInteger c=[set count]; + if(c>0){ + [lock lock]; + qmapper.push_back(std::make_pair(ASFK_E_QSPEC_REG, c)); + [regQ castUnorderedSet:set exParams:nil]; + [lock unlock]; + + } + } + return NO; +} +-(BOOL) castOrderedSet:(NSOrderedSet *)set exParams:(ASFKExecutionParams *)ex{ + if(set){ + NSUInteger c=[set count]; + if(c>0){ + [lock lock]; + qmapper.push_back(std::make_pair(ASFK_E_QSPEC_REG, c)); + [regQ castOrderedSet:set exParams:nil]; + [lock unlock]; + } + } + return NO; +} +-(BOOL) castDictionary:(NSDictionary *)dict exParams:(ASFKExecutionParams *)ex{ + if(dict){ + NSUInteger c=[dict count]; + if(c>0){ + [lock lock]; + qmapper.push_back(std::make_pair(ASFK_E_QSPEC_REG, c)); + [regQ castDictionary:dict exParams:nil]; + [lock unlock]; + } + } + return NO; +} +#pragma mark - blocking interface +-(BOOL) callArray:(NSArray *)array exParams:(ASFKExecutionParams *)params{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return NO; +} +-(BOOL) callUnorderedSet:(NSSet *)unoset exParams:(ASFKExecutionParams *)params{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + + return NO; +} +-(BOOL) callOrderedSet:(NSOrderedSet *)oset exParams:(ASFKExecutionParams *)params{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return NO; +} +-(BOOL) callDictionary:(NSDictionary *)dict exParams:(ASFKExecutionParams *)params{ + DASFKLog(ASFK_STR_VER_UNAVAIL_OP); + return NO; +} +#pragma mark - Reading +-(id) pullAndOccupyWithId:(long)itsid empty:(BOOL&)empty index:(NSInteger&)itemIndex term:(ASFKPriv_EndingTerm**)term{ + + itemIndex=-1; + *term=nil; + [lock lock]; + if(occupant>=0 && occupant!=itsid){ + empty=YES; + NSUInteger bc=0; + if(blkQ){ + bc=[blkQ count]; + } + if([regQ count]+bc>0){ + empty=NO; + } + [lock unlock];; + return nil; + } + id item=nil; + + if(qmapper.size()>0){ + std::pair items=qmapper.front(); + if(items.first==ASFK_E_QSPEC_REG){ + if(lastItem!=ASFK_E_QSPEC_REG){ + lastItem=ASFK_E_QSPEC_REG; + + } + item=[regQ pull]; +// lastItem=ASFK_E_QSPEC_REG; + if(item!=nil){ + itemIndex=items.second; + items.second--; + if(items.second>0){ + qmapper.front().second=items.second; + } + else{ + qmapper.pop_front(); + } + } + } + else + if(blkQ){ + NSInteger lib=0; + if(lastItem!=ASFK_E_QSPEC_BAT){ + lastItem=ASFK_E_QSPEC_BAT; + } + id term0=nil; + BOOL endb=NO; + item=[blkQ pullAndBatchStatus:lib endBatch:endb term:&term0]; + + if(item!=nil){ + itemIndex=items.second; + items.second--; + if(items.second>0){ + qmapper.front().second=items.second; + } + else{ + qmapper.pop_front(); + } + + } + if(endb){ + *term=itsSig; + } + } + + if (item) { + + //[q removeObjectAtIndex:0]; + NSUInteger blkc=0; + if(blkQ){ + blkc=[blkQ count]; + } + if([regQ count]+blkc > 0){ + occupant=itsid; + empty=NO; + } + else{ + occupant=-1; + empty=YES; + } + } + else{ + occupant=-1; + empty=YES; + + } + + } + else{ + lastItem=ASFK_E_QSPEC_NONE; + } + [lock unlock];; + return item; +} +-(void)unoccupyWithId:(long)itsid{ + [lock lock]; + if(occupant==itsid){ + occupant=-1; + } + [lock unlock]; +} +-(void)unoccupy{ + [lock lock]; + occupant=-1; + [lock unlock]; +} +-(BOOL)isEmpty{ + NSUInteger blkc=0; + [lock lock]; + if(blkQ){ + blkc=[blkQ count]; + } + BOOL e=[regQ count]+blkc>0 && occupant>=0 ?NO:YES; + [lock unlock]; + return e; +} +-(void)reset{ + [lock lock]; + if(blkQ){ + [blkQ reset]; + } + [regQ reset]; + occupant=-1; [lock unlock];; +} +-(NSUInteger )count{ + NSUInteger blkc=0; + [lock lock]; + if(blkQ){ + blkc=[blkQ count]; + } + NSUInteger c=[regQ count]+blkc; + [lock unlock]; + return c; +} +-(void) _releaseBlocked{ + [lock lock]; + if(blkQ) + { + [blkQ releaseFirst]; + } + [lock unlock]; + +} +-(void) _releaseBlockedAll{ + } @end