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

James Foster smalltalk at jgfoster.net
Fri Jul 22 14:50:03 PDT 2022


Sorry, I should have addressed this to Johan rather than Otto!

> On Jul 22, 2022, at 2:13 PM, James Foster via GemStone-Smalltalk <gemstone-smalltalk at lists.gemtalksystems.com> wrote:
> 
> Otto,
> 
> I believe that GemStone’s support for weak references is limited to in-memory objects, not persistent objects. While there is some discussion of adding ephemerons to persistent objects, it isn’t there now.
> 
> Recently Martin entered our internal issue number 50024 ("Oop-fishing between vote and reclaim can result in holding a dead object”), describing it as “theoretical, not yet reproduced.” You might have demonstrated that problem (or something related).
> 
> In any case, I think that the safer thing for you to do is to assign your own unique identifiers to your objects and use that unique identifier in your logging. With that, you wouldn’t need to add an object creation date and do oop-fishing. 
> 
> James
> 
>> On Jul 22, 2022, at 12:37 PM, Wai Lun Mang via GemStone-Smalltalk <gemstone-smalltalk at lists.gemtalksystems.com <mailto:gemstone-smalltalk at lists.gemtalksystems.com>> wrote:
>> 
>> 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 <https://overview.mail.yahoo.com/?.src=iOS>
>> 
>> On Friday, July 22, 2022, 9:44 AM, Otto Behrens via GemStone-Smalltalk <gemstone-smalltalk at lists.gemtalksystems.com <mailto: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: aBlock
>> because 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 <mailto:GemStone-Smalltalk at lists.gemtalksystems.com>
>> https://lists.gemtalksystems.com/mailman/listinfo/gemstone-smalltalk <https://lists.gemtalksystems.com/mailman/listinfo/gemstone-smalltalk>
>> _______________________________________________
>> GemStone-Smalltalk mailing list
>> GemStone-Smalltalk at lists.gemtalksystems.com <mailto:GemStone-Smalltalk at lists.gemtalksystems.com>
>> https://lists.gemtalksystems.com/mailman/listinfo/gemstone-smalltalk <https://lists.gemtalksystems.com/mailman/listinfo/gemstone-smalltalk>
>> _______________________________________________
>> GemStone-Smalltalk mailing list
>> GemStone-Smalltalk at lists.gemtalksystems.com <mailto:GemStone-Smalltalk at lists.gemtalksystems.com>
>> https://lists.gemtalksystems.com/mailman/listinfo/gemstone-smalltalk <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/06278d28/attachment.htm>


More information about the GemStone-Smalltalk mailing list