Just a quick followup: I've tested further, and alas, looks like the very same 
problem may happen regardless the fetchTimestamp due to inverse flattened M:N 
relationships.

Test case same as below, just without 1/4, but with a flattened M:N two-side 
relationship; culprit in (vii) very slightly different — the original 
relationship gets filled from the snapshot without any problem, but the inverse 
may (quite probably) need to be fetched, with precisely the same outcome. Sigh.

> On 9. 6. 2024, at 2:46, ocs--- via Webobjects-dev 
> <webobjects-dev@lists.apple.com> wrote:
> 
> Hi there again,
> 
> I was eventually able to repeat the problem and it sort of stinks by a bug in 
> EOF (or I am doing something wrong, of course, as so often :)) My test code 
> is just a wee bit at the convoluted side, based on my own model and besides 
> written in Groovy, thus there's no point in quoting it; but the gist is this:
> 
> 1. create an EC1, assign it a fetchTimestamp in future (something like 
> System.currentTimeMillis()+1500 should suffice)
> 2. lock EC1
> 3. fetch into EC1 an object with a :N relationship and change that 
> relationship, not saving the changes
> 4. wait until the fetchTimestamp expires
> 5. in a separate thread with its own EC2 (locked) change the same 
> relationship of the same object (localInstanceIn(EC2) of course)
> 6. save the changes in EC2
> 7. back in the original thread, wait until the thread with steps 5 and 6 
> ends. Then unlock EC1
> 8. finally, in an unrelated EC3 insert some unrelated new object and 
> saveChanges...
> 
> ... and at least at my side, I get “Cannot obtain globalId for an object 
> which is registered in an other than the databaseContext's active 
> editingContext“ exception all right!
> 
> I believe the steps above are completely valid and should not cause problems, 
> or do I overlook something here?
> 
> I might be wrong, it is a bit at the complex side, but I think this is what 
> happens under the hood:
> (i) EC3 saveChanges of step 8 just calls 
> EOObjectStoreCoordinator.saveChangesInEditingContext ...
> (ii) which first makes sure there's a proper source (happens to be 
> EODatabaseContext) for each inserted object in its _sources; this 
> EODatabaseContext happens to be the only shared EODatabaseContext a simple 
> application like this one uses (no more OSCs, no concurrent DB access)
> (iii) each _source gets _willPrepareForSave and then each _source gets 
> prepareForSaveWithCoordinator — and this sets its _editingContext to EC3!
> (iv) furthermore each _source gets recordChangesInEditingContext, 
> performChanges, and eventually commitChanges
> (v) inside of commitChanges, EODatabaseContext finds that some changes really 
> happened and posts EOGlobalIDChangedNotification
> (vi) EC1, which up to this moment was dormant, observes this notification and 
> through _globalIDChanged, _sendOrEnqueueNotification, yadda yadda, eventually 
> gets to merge the change into its own object
> (vii) which change includes checking the current relationship value. Since 
> the fetchTimestamp is already in the past, this involves re-fetching the 
> relationship in EC1 ...
> (viii) ... which goes through the one and only shared EODatabaseContext we 
> have. That EODatabaseContext though still has its _editingContext set to EC3 
> from the step (iii))!
> 
> Hilarity ensues, the “Cannot obtain globalId for an object which is 
> registered in an other...” exception gets thrown (if this did not happen, the 
> EODatabaseContext's _editingContext would get nulled at the very end of 
> commitChanges, too late for us).
> 
> Do I overlook something of importance? Seems me not to; I guess anyone can 
> repeat the test code 1-8 outlined above (just beware logs — they might fire 
> the fault prematurely; also I've found essentially each localInstanceIn locks 
> ECs and thus disrupts the normal processing — best to prepare all the ECs and 
> all their local instances at the very start, around the step 1).
> 
> What would be the best fix/work-around? I can't see any simple one; and I 
> would rather not override and re-implement the complete and rather 
> non-trivial commitChanges method.
> 
> Thanks and all the best,
> OC
> 
>> On 8. 6. 2024, at 4:38, ocs--- via Webobjects-dev 
>> <webobjects-dev@lists.apple.com <mailto:webobjects-dev@lists.apple.com>> 
>> wrote:
>> 
>> Hi there,
>> 
>> again in about 2 years the $subject did happen:
>> 
>> “Cannot obtain globalId for an object which is registered in an other than 
>> the databaseContext's active editingContext, object: 
>> [USER#1000175@EC:34ea315d/OSC:77b7ffa4], databaseContext: 
>> com.webobjects.eoaccess.EODatabaseContext@512d92b, object's editingContext: 
>> EC:34ea315d/OSC:77b7ffa4, databaseContext's active editingContext: 
>> EC:7de5b11a/OSC:77b7ffa4“
>> 
>> (ECs are my subclasses which log out the appropriate OSC, too; did that when 
>> I've hunted for bugs in multi-OSC environment. Unimportant here, in this 
>> case all OSCs are same.)
>> 
>> Again, as before, the cause were the changes previously stored for later in 
>> another EC (since when they actually happened, the EC was locked). The 
>> important stack items (far as I can say) are here (full stack at the end of 
>> the message, should it help):
>> 
>> - EODatabaseContext._globalIDForObject(EODatabaseContext.java:4660) # 
>> failed, since this._editingContext=EC:7de5b11a, 
>> object.editingContext=EC:34ea315d
>> - EOCustomObject.includeObjectIntoPropertyWithKey(EOCustomObject.java:904) # 
>> pretty sure both were in the same EC, 34ea315d
>> - EOEditingContext._processNotificationQueue(EOEditingContext.java:4741) # 
>> should be EC:34ea315d, whose merge queue happens to be non-empty
>> - EOEditingContext._globalIDChanged(EOEditingContext.java:2038) # 
>> EC:34ea315d received the notification and tries to merge stored changes
>> - EODatabaseContext.commitChanges(EODatabaseContext.java:6377) # 
>> postNotification "EOGlobalIDChangedNotification"
>> - 
>> EOObjectStoreCoordinator.saveChangesInEditingContext(EOObjectStoreCoordinator.java:386)
>>  # EC:7de5b11a, normal save, happens to be a single insert, which is 
>> quadruple weird :-O (I believe a single insert actually should not trigger 
>> change merging?!?)
>> 
>> I've spent a cosy night over the logs and Wonder sources and the 
>> documentation etc., and found sweet nothing — I'm still not the slightest 
>> bit smarter than 2 yrs ago :(
>> 
>> It seems to me that
>> (a) it is quite normal that during save of EC:A, any number of ECs:B,C,D... 
>> could be merging changes saved for later in their 
>> EOGlobalIDChangedNotification handlers
>> (b) which should, though, never ever happen while EC:A is set as the EODBC's 
>> active context — actually the contexts should be set properly for each the 
>> EC.
>> 
>> Can anybody perhaps see the possible culprit?
>> 
>> It really does not seem a cross-EC relationship can be the culprit. I might 
>> still overlook something, but I am pretty darn sure that the 
>> includeObjectIntoPropertyWithKey method has been called with both the 
>> receiver and object in the same EC, the one which was merging its previously 
>> stored changes, 34ea315d.
>> 
>> I am pretty sure the culprit was that at the moment this happened, the 
>> EODBC's active context was the one which did run the original save, 7de5b11a.
>> 
>> How the B.H. is that possible though?
>> 
>> Note: far as I can say with my logs, there happened to be *NO* thread 
>> concurrency at the moment, which makes it even more weird. Far as my logs 
>> say, no other thread did *anything* when my worker thread (a) saved a single 
>> simple insert in EC:7de5b11a, (b) which, as as side-effect, caused the 
>> EC:34ea315d to merge its previously saved changes, (c) which threw the 
>> exception as detailed above. Sigh.
>> 
>> On the other hand, a (successful, uneventful) save in EC:7de5b11a which _did 
>> change_ the very USER#1000175 object did happen _very shortly_ before (about 
>> 20 ms before). In the same thread, in the same EC. I can't quite see how it 
>> can be important (far as I can say, there's no timer like “having saved X, 
>> merge changes to other ECs in couple of millis“ or so), but then, I still 
>> can be overlooking something of great importance.
>> 
>> Thanks a lot for any insight,
>> OC
>> 
>> === full stack in case it helps (did not to me :/ )
>> Note please OCSEC is my own ERXEC subclass, which in this case does 
>> essentially nothing but logs out. Especially 
>> OCSEC._processObjectStoreChanges just logs (so that I know whether the merge 
>> happens or not, and if it does, with what data) and then calls super. Same 
>> with my own lock(), it does essentially nothing (first calls super and only 
>> then logs out, which in this case did not happen, for the exception happened 
>> inside of super.lock):
>> 
>> - EODatabaseContext._globalIDForObject(EODatabaseContext.java:4660)
>> - EODatabaseContext.databaseOperationForObject(EODatabaseContext.java:4767)
>> - EODatabaseContext.valuesForKeys(EODatabaseContext.java:6535)
>> - EOObjectStoreCoordinator.valuesForKeys(EOObjectStoreCoordinator.java:326)
>> - 
>> EOQualifierSQLGeneration$_KeyValueQualifierSupport.schemaBasedQualifierWithRootEntity(EOQualifierSQLGeneration.java:439)
>> - 
>> ERXExtensions$KeyValueQualifierSQLGenerationSupport.schemaBasedQualifierWithRootEntity(ERXExtensions.java:661)
>> - 
>> EOQualifierSQLGeneration$Support._schemaBasedQualifierWithRootEntity(EOQualifierSQLGeneration.java:179)
>> - 
>> EODatabaseChannel.selectObjectsWithFetchSpecification(EODatabaseChannel.java:227)
>> - 
>> EODatabaseContext._objectsWithFetchSpecificationEditingContext(EODatabaseContext.java:3055)
>> - 
>> EODatabaseContext.objectsWithFetchSpecification(EODatabaseContext.java:3195)
>> - 
>> EOObjectStoreCoordinator.objectsWithFetchSpecification(EOObjectStoreCoordinator.java:488)
>> - EOEditingContext.objectsWithFetchSpecification(EOEditingContext.java:4069)
>> - ERXEC.objectsWithFetchSpecification(ERXEC.java:1307)
>> - EODatabaseContext.objectsForSourceGlobalID(EODatabaseContext.java:4084)
>> - 
>> EOObjectStoreCoordinator.objectsForSourceGlobalID(EOObjectStoreCoordinator.java:634)
>> - EOEditingContext.objectsForSourceGlobalID(EOEditingContext.java:3923)
>> - ERXEC.objectsForSourceGlobalID(ERXEC.java:1267)
>> - EODatabaseContext._fireArrayFault(EODatabaseContext.java:4245)
>> - 
>> EOAccessArrayFaultHandler.completeInitializationOfObject(EOAccessArrayFaultHandler.java:77)
>> - _EOCheapCopyMutableArray.willRead(_EOCheapCopyMutableArray.java:39)
>> - _EOCheapCopyMutableArray.count(_EOCheapCopyMutableArray.java:99)
>> - NSArray.containsObject(NSArray.java:459)
>> - EOCustomObject.includeObjectIntoPropertyWithKey(EOCustomObject.java:904)
>> - 
>> ERXGenericRecord.includeObjectIntoPropertyWithKey(ERXGenericRecord.java:1291)
>> - ERXGenericRecord$includeObjectIntoPropertyWithKey$6.callCurrent(:-1)
>> - ERXGenericRecord$includeObjectIntoPropertyWithKey$6.callCurrent(:-1)
>> - _DBUser.addToAuctionAccess(_DBUser.groovy:277)
>> - NSSelector._safeInvokeMethod(NSSelector.java:122)
>> - EOCustomObject.addObjectToPropertyWithKey(EOCustomObject.java:940)
>> - EOEditingContext._mergeValueForKey(EOEditingContext.java:660)
>> - EOEditingContext._mergeObjectWithChanges(EOEditingContext.java:3457)
>> - EOEditingContext._processObjectStoreChanges(EOEditingContext.java:3546)
>> - ERXEC._processObjectStoreChanges(ERXEC.java:1555)
>> - OCSEC.super$4$_processObjectStoreChanges(OCSEnterpriseObject.groovy:-1)
>> - OCSEC._processObjectStoreChanges(OCSEnterpriseObject.groovy:137)
>> - NSSelector.invoke(NSSelector.java:358)
>> - NSSelector._safeInvokeSelector(NSSelector.java:110)
>> - EOEditingContext._processNotificationQueue(EOEditingContext.java:4741)
>> - EOEditingContext.lock(EOEditingContext.java:4620)
>> - ERXEC.lock(ERXEC.java:568)
>> - OCSEC.super$4$lock(OCSEnterpriseObject.groovy:-1)
>> - OCSEC.lock(OCSEnterpriseObject.groovy:224)
>> - EOEditingContext.tryLock(EOEditingContext.java:4632)
>> - EOEditingContext._sendOrEnqueueNotification(EOEditingContext.java:4705)
>> - EOEditingContext._globalIDChanged(EOEditingContext.java:2038)
>> - NSSelector._safeInvokeMethod(NSSelector.java:122)
>> - NSNotificationCenter$_Entry.invokeMethod(NSNotificationCenter.java:588)
>> - NSNotificationCenter.postNotification(NSNotificationCenter.java:532)
>> - NSNotificationCenter.postNotification(NSNotificationCenter.java:562)
>> - 
>> EOObjectStoreCoordinator._globalIDsChangedInSubStore(EOObjectStoreCoordinator.java:698)
>> - NSSelector._safeInvokeMethod(NSSelector.java:122)
>> - NSNotificationCenter$_Entry.invokeMethod(NSNotificationCenter.java:588)
>> - NSNotificationCenter.postNotification(NSNotificationCenter.java:532)
>> - NSNotificationCenter.postNotification(NSNotificationCenter.java:562)
>> - EODatabaseContext.commitChanges(EODatabaseContext.java:6377)
>> - 
>> EOObjectStoreCoordinator.saveChangesInEditingContext(EOObjectStoreCoordinator.java:386)
>> - EOEditingContext.saveChanges(EOEditingContext.java:3192)
>> - ERXEC._saveChanges(ERXEC.java:1178)
>> - ERXEC.saveChanges(ERXEC.java:1099)
>> - OCSEC.super$4$saveChanges(OCSEnterpriseObject.groovy:-1)
>> - OCSEC.saveChanges(OCSEnterpriseObject.groovy:106)
>> - OCSEC$saveChanges.call(:-1)
>> 
>> _______________________________________________
>> Do not post admin requests to the list. They will be ignored.
>> Webobjects-dev mailing list      (Webobjects-dev@lists.apple.com 
>> <mailto:Webobjects-dev@lists.apple.com>)
>> Help/Unsubscribe/Update your Subscription:
>> https://lists.apple.com/mailman/options/webobjects-dev/ocs%40ocs.cz
>> 
>> This email sent to o...@ocs.cz
> 
> _______________________________________________
> Do not post admin requests to the list. They will be ignored.
> Webobjects-dev mailing list      (Webobjects-dev@lists.apple.com)
> Help/Unsubscribe/Update your Subscription:
> https://lists.apple.com/mailman/options/webobjects-dev/ocs%40ocs.cz
> 
> This email sent to o...@ocs.cz

 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list      (Webobjects-dev@lists.apple.com)
Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to