objective c - Core data getting locked with multi threading (_objectStoreLockCount > 1) -


i finding hard time in fixing core data db lock situation (_objectstorelockcount count > 1 when run in debug mode).

below architecture of application (mac osx):

  1. i using 2 nsoperationqueue perform activities. each queue having 20 activities running in parallel.
  2. once these activities done, each 1 of them put result data in nsoperationqueue has maximum concurrent operation count set 1.
  3. the result operation queue puts data in core data.
  4. there 2 other threads running. 1 of reading data core data. one, based on logic, updating existing records in core data.
  5. for core data handling, have created subclass of nsobject having 3 objects. each object has own nsmanagedobjectcontext - 1 reading data, 1 writing new records , 1 updating existing records. updating read managed object context whenever there change in write managed object context. 3 mocs have common persistent store co-ordinator.
  6. the application supposed run 24*7 above code bound repeat

issue: when run application randomly hangs or locks db. reaches state random times - 2 hours, 10 hours not defined...

i attaching core data handling part of application. please let me know if missing in core data handling:

@implementation myappdatarepository  @synthesize persistentstorecoordinator = _persistentstorecoordinator; @synthesize managedobjectmodel = _managedobjectmodel; @synthesize writemanagedobjectcontext = _writemanagedobjectcontext; @synthesize readmanagedobjectcontext = _readmanagedobjectcontext; @synthesize updatemanagedobjectcontext = _updatemanagedobjectcontext;  static  myappdatarepository *sharedmyappwritedatarepository = nil; static  myappdatarepository *sharedmyappreaddatarepository = nil; static  myappdatarepository *sharedmyappupdatedatarepository = nil;  + (myappdatarepository *)sharedmyappwritedatarepositorymyapp {     static dispatch_once_t pred = 0;     dispatch_once(&pred, ^{         sharedmyappwritedatarepository = [[self alloc] init];         [sharedmyappwritedatarepository persistentstorecoordinator];         [sharedmyappwritedatarepository writemanagedobjectcontext];     });      return sharedmyappwritedatarepository; }  + (myappdatarepository *)sharedmyappreaddatarepositorymyapp {     static dispatch_once_t pred = 0;     dispatch_once(&pred, ^{         sharedmyappreaddatarepository = [[self alloc] init]; // or other init method         [sharedmyappreaddatarepository persistentstorecoordinator];         [sharedmyappreaddatarepository readmanagedobjectcontext];     });      return sharedmyappreaddatarepository; }   + (myappdatarepository *)sharedmyappupdatedatarepositorymyapp {     static dispatch_once_t pred = 0;     dispatch_once(&pred, ^{         sharedmyappupdatedatarepository = [[self alloc] init]; // or other init method         [sharedmyappupdatedatarepository persistentstorecoordinator];         [sharedmyappupdatedatarepository  updatemanagedobjectcontext];     });      return sharedmyappupdatedatarepository; }   -(id)init {     if ((self = [super init])) {         if (!self.writemanagedobjectcontext) {             myapplog(@"core data cannot initiated");         }     }     return  self; }  // returns directory application uses store core data store file. code uses directory named "com.apple.retail.myapp" in user's application support directory. - (nsurl *)applicationfilesdirectory {     nsfilemanager *filemanager = [nsfilemanager defaultmanager];     nsurl *appsupporturl = [[filemanager urlsfordirectory:nsapplicationsupportdirectory indomains:nsuserdomainmask] lastobject];     return [appsupporturl urlbyappendingpathcomponent:@"com.apple.retail.myapp"]; }  // creates if necessary , returns managed object model application. - (nsmanagedobjectmodel *)managedobjectmodel {     if (_managedobjectmodel) {         return _managedobjectmodel;     }      nsurl *modelurl = [[nsbundle mainbundle] urlforresource:@"myapp" withextension:@"momd"];     _managedobjectmodel = [[nsmanagedobjectmodel alloc] initwithcontentsofurl:modelurl];     return _managedobjectmodel; }  // returns persistent store coordinator application. implementation creates , return coordinator, having added store application it. (the directory store created, if necessary.) - (nspersistentstorecoordinator *)persistentstorecoordinator {     if (_persistentstorecoordinator) {         return _persistentstorecoordinator;     }      nsmanagedobjectmodel *mom = [self managedobjectmodel];     if (!mom) {         myapplog(@"%@:%@ no model generate store from", [self class], nsstringfromselector(_cmd));         return nil;     }      nsfilemanager *filemanager = [nsfilemanager defaultmanager];     nsurl *applicationfilesdirectory = [self applicationfilesdirectory];     nserror *error = nil;      nsdictionary *properties = [applicationfilesdirectory resourcevaluesforkeys:@[nsurlisdirectorykey] error:&error];      if (!properties) {         bool ok = no;         if ([error code] == nsfilereadnosuchfileerror) {             ok = [filemanager createdirectoryatpath:[applicationfilesdirectory path] withintermediatedirectories:yes attributes:nil error:&error];         }         if (!ok) {             [[nsapplication sharedapplication] presenterror:error];             return nil;         }     } else {         if (![properties[nsurlisdirectorykey] boolvalue]) {             // customize , localize error.             nsstring *failuredescription = [nsstring stringwithformat:@"expected folder store application data, found file (%@).", [applicationfilesdirectory path]];              nsmutabledictionary *dict = [nsmutabledictionary dictionary];             [dict setvalue:failuredescription forkey:nslocalizeddescriptionkey];             error = [nserror errorwithdomain:@"your_error_domain" code:101 userinfo:dict];              [[nsapplication sharedapplication] presenterror:error];             return nil;         }     }      //support automatic migration of core data     nsmutabledictionary *optionsdictionary = [nsmutabledictionary dictionary];     [optionsdictionary setobject:[nsnumber numberwithbool:yes]                           forkey:nsmigratepersistentstoresautomaticallyoption];     [optionsdictionary setobject:[nsnumber numberwithbool:yes] forkey:nsinfermappingmodelautomaticallyoption];      nsurl *url = [applicationfilesdirectory urlbyappendingpathcomponent:@"myapp.sqlite"];     nspersistentstorecoordinator *coordinator = [[nspersistentstorecoordinator alloc] initwithmanagedobjectmodel:mom];     if (![coordinator addpersistentstorewithtype:nssqlitestoretype configuration:nil url:url options:optionsdictionary error:&error]) {         [[nsapplication sharedapplication] presenterror:error];         return nil;     }     _persistentstorecoordinator = coordinator;      return _persistentstorecoordinator; }   // returns managed object context application (which bound persistent store coordinator application.) - (nsmanagedobjectcontext *)writemanagedobjectcontext {     if (_writemanagedobjectcontext) {         return _writemanagedobjectcontext;     }      nspersistentstorecoordinator *coordinator = [self persistentstorecoordinator];     if (!coordinator) {         nsmutabledictionary *dict = [nsmutabledictionary dictionary];         [dict setvalue:@"failed initialize store" forkey:nslocalizeddescriptionkey];         [dict setvalue:@"there error building data file." forkey:nslocalizedfailurereasonerrorkey];         nserror *error = [nserror errorwithdomain:@"your_error_domain" code:9999 userinfo:dict];         [[nsapplication sharedapplication] presenterror:error];         return nil;     }     _writemanagedobjectcontext = [[nsmanagedobjectcontext alloc] init];     [_writemanagedobjectcontext setpersistentstorecoordinator:coordinator];      return _writemanagedobjectcontext; }   - (nsmanagedobjectcontext *)readmanagedobjectcontext {     if (_readmanagedobjectcontext) {         return _readmanagedobjectcontext;     }      nspersistentstorecoordinator *coordinator = [self persistentstorecoordinator];     if (!coordinator) {         nsmutabledictionary *dict = [nsmutabledictionary dictionary];         [dict setvalue:@"failed initialize store" forkey:nslocalizeddescriptionkey];         [dict setvalue:@"there error building data file." forkey:nslocalizedfailurereasonerrorkey];         nserror *error = [nserror errorwithdomain:@"your_error_domain" code:9999 userinfo:dict];         [[nsapplication sharedapplication] presenterror:error];         return nil;     }     _readmanagedobjectcontext = [[nsmanagedobjectcontext alloc] init];     [_readmanagedobjectcontext setpersistentstorecoordinator:coordinator];      return _readmanagedobjectcontext; }   - (nsmanagedobjectcontext *)updatemanagedobjectcontext {     if (_updatemanagedobjectcontext) {         return _updatemanagedobjectcontext;     }      nspersistentstorecoordinator *coordinator = [self persistentstorecoordinator];     if (!coordinator) {         nsmutabledictionary *dict = [nsmutabledictionary dictionary];         [dict setvalue:@"failed initialize store" forkey:nslocalizeddescriptionkey];         [dict setvalue:@"there error building data file." forkey:nslocalizedfailurereasonerrorkey];         nserror *error = [nserror errorwithdomain:@"your_error_domain" code:9999 userinfo:dict];         [[nsapplication sharedapplication] presenterror:error];         return nil;     }     _updatemanagedobjectcontext = [[nsmanagedobjectcontext alloc] init];     [_updatemanagedobjectcontext setpersistentstorecoordinator:coordinator];      return _updatemanagedobjectcontext; }   // returns nsundomanager application. in case, manager returned of managed object context application. - (nsundomanager *)windowwillreturnundomanager:(nswindow *)window {     return [[self writemanagedobjectcontext] undomanager]; }  // performs save action application, send save: message application's managed object context. encountered errors presented user. - (ibaction)saveaction:(id)sender {     nserror *error = nil;      if (![[self writemanagedobjectcontext] commitediting]) {         myapplog(@"%@:%@ unable commit editing before saving", [self class], nsstringfromselector(_cmd));     }      if (![[self writemanagedobjectcontext] save:&error]) {         [[nsapplication sharedapplication] presenterror:error];     } }   - (bool)savedataindatabase:(nsmanagedobjectcontext *)icontext {     bool datasavedsuccessfully = yes;      nserror *error = nil;      if (![icontext commitediting]) {         myapplog(@"%@:%@ unable commit editing before saving", [self class], nsstringfromselector(_cmd));     }      [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(handledidsavenotification:) name:nsmanagedobjectcontextdidsavenotification object:icontext];       if (![icontext save:&error]) {         datasavedsuccessfully = no;         [[nsapplication sharedapplication] presenterror:error];     }      // unregister notification     [[nsnotificationcenter defaultcenter] removeobserver:self name:nsmanagedobjectcontextdidsavenotification object:icontext];      return datasavedsuccessfully; }   // merge changes write managed object context read managed object context - (void)handledidsavenotification:(nsnotification *)inotification {     [[myappdatarepository sharedmyappreaddatarepository].readmanagedobjectcontext mergechangesfromcontextdidsavenotification:inotification]; }   - (nsapplicationterminatereply)applicationshouldterminate:(nsapplication *)sender {     // save changes in application's managed object context before application terminates.      if (!_writemanagedobjectcontext) {         return nsterminatenow;     }      if (![[self writemanagedobjectcontext] commitediting]) {         myapplog(@"%@:%@ unable commit editing terminate", [self class], nsstringfromselector(_cmd));         return nsterminatecancel;     }      if (![[self writemanagedobjectcontext] haschanges]) {         return nsterminatenow;     }      nserror *error = nil;     if (![[self writemanagedobjectcontext] save:&error]) {          // customize code block include application-specific recovery steps.         bool result = [sender presenterror:error];         if (result) {             return nsterminatecancel;         }          nsstring *question = nslocalizedstring(@"could not save changes while quitting. quit anyway?", @"quit without saves error question message");         nsstring *info = nslocalizedstring(@"quitting lose changes have made since last successful save", @"quit without saves error question info");         nsstring *quitbutton = nslocalizedstring(@"quit anyway", @"quit anyway button title");         nsstring *cancelbutton = nslocalizedstring(@"cancel", @"cancel button title");         nsalert *alert = [[nsalert alloc] init];         [alert setmessagetext:question];         [alert setinformativetext:info];         [alert addbuttonwithtitle:quitbutton];         [alert addbuttonwithtitle:cancelbutton];          nsinteger answer = [alert runmodal];          if (answer == nsalertalternatereturn) {             return nsterminatecancel;         }     }      return nsterminatenow; }   - (void)inserttestresults:(nsarray *)itestdata withupdateflag:(int)iupdateflag withdiscarddlag:(int)idiscardflag {     nsmanagedobjectcontext *awritemanagedobjcontext = [[myappdatarepository sharedmyappwritedatarepositorymyapp] writemanagedobjectcontext];      nsmanagedobject *atestresults;     nsmutablearray *atestidarray=[nsmutablearray array];      (myapptestresultsmodel *itestresultsdata in itestdata) {         nsstring *atesttype=[itestresultsdata valueforkey:kmyapptesttype];          if ([atesttype isequaltostring:kmyapptest1type]) {             atestresults=[nsentitydescription                           insertnewobjectforentityforname:kmyapptest1resultsentity                           inmanagedobjectcontext:awritemanagedobjcontext];         } else if ([atesttype isequaltostring:kmyapptest2type]) {             atestresults=[nsentitydescription                           insertnewobjectforentityforname:kmyapptest2resultsentity                           inmanagedobjectcontext:awritemanagedobjcontext];         } else if ([atesttype isequaltostring:kmyapptest3type]) {             atestresults=[nsentitydescription                           insertnewobjectforentityforname:kmyapptest3resultsentity                           inmanagedobjectcontext:awritemanagedobjcontext];         } else if ([atesttype isequaltostring:kmyapptest4type]) {             atestresults=[nsentitydescription                           insertnewobjectforentityforname:kmyapptest4resultsentity                           inmanagedobjectcontext:awritemanagedobjcontext];         }          nserror *anerror=nil;         if (![self savedataindatabase:awritemanagedobjcontext]) {             myapplog(@"cannot save!: %@", [anerror localizeddescription]);         }         else         {             // post saved message main window             nsstring *alog = [nsstring stringwithformat:@"\n \n%@ test results saved \n %@",[itestresultsdata valueforkey:kmyapptesttype], atestresults];             myapplog(@"%@",alog);             myappinfolog(@"saved test results (in client db) test id = %@ test type = %@ app id = %@ network = %@ status = %@", [itestresultsdata valueforkey:kmyapptestid], [itestresultsdata valueforkey:kmyapptesttype], [itestresultsdata valueforkey:kmyappappidattribute], [itestresultsdata valueforkey:kmyapptestnetwork], [itestresultsdata valueforkey:kmyappteststatusattribute]);              [atestidarray addobject:[atestresults valueforkey:kmyapptestidattribute]];              // update isreadytoflag             if (iupdateflag == 1)                 [myappfetchtestconfigdetails updatereadytorunfortestid:[nsarray arraywitharray:atestidarray] withint:iupdateflag];         }     } } 

below operation queue implementation thread 2 (that has been filled multiple threads):

@implementation myappsavetestresultcontroller  - (id)init {     if ((self = [super init]) != nil) {         self.queue = [[nsoperationqueue alloc] init];         [self.queue setmaxconcurrentoperationcount:1];     }     return self; }  + (myappsavetestresultcontroller *)sharedsaveresultscontroller {     static dispatch_once_t pred = 0;     dispatch_once(&pred, ^{         sharedsaveresultscontroller = [[self alloc] init]; // or other init method     });     return sharedsaveresultscontroller; }  - (void)startsaveoperation {     myappsavetestresultsoperation *asaveoperation = [[myappsavetestresultsoperation alloc] initwithtestresults:self.testresults updateflag:self.updateflag anddiscarddlag:self.discardflag];     [self.queue addoperation:asaveoperation];  }   @implementation mysavetestresultsoperation  - (id)initwithtestresults:(nsarray *)itestdata updateflag:(int)iupdateflag anddiscarddlag:(int)idiscardflag {     if ((self = [super init]) != nil)     {         self.testresults = itestdata;         self.updateflag = iupdateflag;         self.discardflag = idiscardflag;     }      return self; }  - (void)start {     if (![nsthread ismainthread])     {         [self performselectoronmainthread:@selector(start) withobject:nil waituntildone:no];         return;     }      // check cancellation     if ([self iscancelled]) {         [self completeoperation];         return;     }      // executing     [self willchangevalueforkey:@"isexecuting"];     executing = yes;     [self didchangevalueforkey:@"isexecuting"];      // begin     [self beginoperation]; }  - (void)beginoperation {     @try {         [[myappdatarepository sharedmyappwritedatarepository] inserttestresults:results withupdateflag:self.updateflag withdiscarddlag:self.discardflag];         [self completeoperation];     } @catch(nsexception * e) {     } } 

below piece of code called activity threads (as many 20 concurrent threads) fill in data myappsavetestresultcontroller:

myappsavetestresultcontroller *asavetestresultcontroller = [myappsavetestresultcontroller sharedsaveresultscontroller];     [asavetestresultcontroller savetestresults:[nsarray arraywithobject:data] updateflag:[[nsnumber numberwithbool:[ablockself checkpendingtestsfortestid:anid]] intvalue] discardflag:0];     [asavetestresultcontroller startsaveoperation]; 


Comments

Popular posts from this blog

jquery - How can I dynamically add a browser tab? -

node.js - Getting the socket id,user id pair of a logged in user(s) -

keyboard - C++ GetAsyncKeyState alternative -