[GemStone-Smalltalk] objectForOop: question about some errors we get + how to implement a weak reference?

Wai Lun Mang mang at acm.org
Fri Jul 22 12:37:36 PDT 2022


GemStone does have weak references support.  One of my previous project called Iris2 had been using it for a long time.
You can asked Norm Green about the weak reference support.
Mang


Sent from Yahoo Mail for iPhone


On Friday, July 22, 2022, 9:44 AM, Otto Behrens via GemStone-Smalltalk <gemstone-smalltalk at lists.gemtalksystems.com> wrote:


We only see this happening after an MFC and only occasionally and also only from within gems that have been running before the MFC. 


Ok. We never run a full MFC with seaside sessions up. MFC works better if you can stop as many processes as possible. This is because it does a complete sweep of the repository. We rely on the Epoch GC to mark objects as possibly dead. There may be a subtle difference. The reclaim gem will come later and claim the space. This is my layman's understanding. I see you use oopIsDead when the space it occupies has not been reclaimed yet. I remember there may be some more complexity around the "deadness" of an object. 
Since the oop lookup is part of rendering the log entries in our Seaside application, connected users can trigger this error. The stack trace I pasted was triggered multiple times from the same gem, while Seaside requests handled by other gems were processing the same data (i.e. log entries) without errors at the same time (probably getting a nil result for the objectForOop:, as expected).
So, the error probably occurs at the first access to the instance variable of the object we retrieved via _objectForOop:. Since the place in the stack trace where the error is thrown is indeed the first time we access the instVar with the object that is reported missing, that is probably what is happening. Indeed.

I don't understand what you mean by "the instance variable of the object we retrieved via _objectForOop:". Are you saying that the object returned by _objectForOop: (which is now marked dead by the MFC) refers to another object, which may now also be possibly dead? Is it perhaps possible that your access modifies the object? I don't see the correlation: why accessing the instVar should have anything to do with it, unless there is a side effect on the accessing. 
Unfortunately, I would expect _oopIsDead: to report the object as being dead in that case and thus not return us the object. 

I agree, unless it is somehow re-attached. I think this is possible. Getting hold of an object that was marked as dead can somehow resurrect it, even if the gem that accessed it has the reference in transient memory. Perhaps this has something to do with it: there is a reference now (after looking at it) or the dead object was moved to a location meant for objects that are not dead.
The block passed to ifNil:ifNotNil: in your code below could be a complex block, which means that there could be a copy of the invocation in memory that would now refer to "object".
I'm not sure if #ifNil:ifNotNil: is optimised by the compiler in the version you are using. I know that there are some more optimisations in 3.6. There is an issue with calling 
 (SystemRepository _oopIsDead: anInteger) ifTrue: aBlockbecause I think it cannot be optimised by the compiler (aBlock is sent to #ifTrue:ifFalse:), but if you do  (SystemRepository _oopIsDead: anInteger) ifTrue: [ aBlock value ]the ifTrue:ifFalse: call is optimised.
This probably has nothing to do with your issue.
Perhaps consider something like this. I know the multiple exit points are not as nice. But there is some logic to what the compiler can do.
privateObjectAtUniqueIdentifier: anInteger ifAbsent: aBlock | object | (object := Object _objectForOop: anInteger) ifNil: [ ^ aBlock value ]. ^ (SystemRepository _oopIsDead: anInteger)
 ifTrue: [ aBlock value ]
 ifFalse: [ object ]
I wonder what will happen if you call _oopIsDead: first. Perhaps this will guard it from failing.
Just an old hacker trying things.
:-) 
The implementation where we invoke _objectForOop: is shown below. First the version of the method as it was when the error occurred then the new version where I tried to the ‘fix’ it by wrapping the error handler around the entire code.
privateObjectAtUniqueIdentifier: anInteger ifAbsent: aBlock ^ (Object _objectForOop: anInteger) ifNil: aBlock ifNotNil:[ :object | [ (SystemRepository _oopIsDead: anInteger) ifTrue: aBlock ifFalse: [ object ] ] on: Error do: [:e | aBlock value ] ]

privateObjectAtUniqueIdentifier: anInteger ifAbsent: aBlock ^ [ (Object _objectForOop: anInteger) ifNil: aBlock ifNotNil:[ :object | (SystemRepository _oopIsDead: anInteger) ifTrue: aBlock ifFalse: [ object ] ]  ] on: Error do: [:e |  "oop fishing in GemStone may return internal objects that do not implement ifNil:ifNotNil:. _oopIsDead can also error (see method comment).  capture these objects here and return nil" aBlock value ]_______________________________________________
GemStone-Smalltalk mailing list
GemStone-Smalltalk at lists.gemtalksystems.com
https://lists.gemtalksystems.com/mailman/listinfo/gemstone-smalltalk

_______________________________________________
GemStone-Smalltalk mailing list
GemStone-Smalltalk at lists.gemtalksystems.com
https://lists.gemtalksystems.com/mailman/listinfo/gemstone-smalltalk



-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.gemtalksystems.com/mailman/archives/gemstone-smalltalk/attachments/20220722/68805d09/attachment.htm>


More information about the GemStone-Smalltalk mailing list