You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is another PyPy-mostly issue; I believe it will be possible to reproduce on CPython, but the code required to do so is fairly pathological so I don't expect anyone to have run into it there.
Start with creating an item (at the latest version), with a reference attribute (call this item type R) pointing at a legacy item (for example, the item being upgraded, in an upgrader that is not to the latest version).
The newly-created Item object will have a reference to the legacy item DummyItem object in the axiom_memory_<reference attribute name> attribute.
When the legacy item is upgraded, Item.committed will set the __store attribute to None.
If a strong reference to the R item is kept (or there is no strong reference, but the item is fetched out of the cache before the object is GCed), reference.__get__ will get the old DummyItem object from the axiom_memory_<name> attribute. It will then test this by calling _currentlyValidAsReferentFor on it, which will return False due to store now being None; this, in turn, will make __get__ return None.
Once the R item is loaded from the database again, everything will be fine; however, data loss may occur as a result of the reference attribute returning None in the meantime. There is a particularly nasty interaction with powerups here; if _PowerupConnector.powerup appears as None during a call to powerupsFor(), the powerup connector will be deleted! On the plus side, it is impossible to get a reference to the item created in powerUp(), so I think triggering this particular case in CPython is impossible. In fact, in general, writing code in an upgrader that retains a strong reference to an item outside of the upgrader requires some fairly pathological code, so this is also unlikely.
However, on PyPy, GC semantics mean that such item objects may stay alive for much longer, and thus if they are loaded from the database again, they will be loaded from the item cache, without a strong reference to them being needed.
I think the fix for this is to avoid setting __store to None in Item.committed for legacy items. This is a mere change in indentation, so it is possible that this bug is actually just an error in indentation.
The text was updated successfully, but these errors were encountered:
mithrandi
changed the title
Potential data loss involving reference attributes and upgraders
Potential data loss involving reference attributes and upgraders
Feb 7, 2015
This is another PyPy-mostly issue; I believe it will be possible to reproduce on CPython, but the code required to do so is fairly pathological so I don't expect anyone to have run into it there.
referenceattribute (call this item typeR) pointing at a legacy item (for example, the item being upgraded, in an upgrader that is not to the latest version).Itemobject will have a reference to the legacy itemDummyItemobject in theaxiom_memory_<reference attribute name>attribute.Item.committedwill set the__storeattribute toNone.Ritem is kept (or there is no strong reference, but the item is fetched out of the cache before the object is GCed),reference.__get__will get the oldDummyItemobject from theaxiom_memory_<name>attribute. It will then test this by calling_currentlyValidAsReferentForon it, which will returnFalsedue tostorenow beingNone; this, in turn, will make__get__return None.Once the
Ritem is loaded from the database again, everything will be fine; however, data loss may occur as a result of thereferenceattribute returningNonein the meantime. There is a particularly nasty interaction with powerups here; if_PowerupConnector.powerupappears asNoneduring a call topowerupsFor(), the powerup connector will be deleted! On the plus side, it is impossible to get a reference to the item created inpowerUp(), so I think triggering this particular case in CPython is impossible. In fact, in general, writing code in an upgrader that retains a strong reference to an item outside of the upgrader requires some fairly pathological code, so this is also unlikely.However, on PyPy, GC semantics mean that such item objects may stay alive for much longer, and thus if they are loaded from the database again, they will be loaded from the item cache, without a strong reference to them being needed.
I think the fix for this is to avoid setting
__storetoNoneinItem.committedfor legacy items. This is a mere change in indentation, so it is possible that this bug is actually just an error in indentation.The text was updated successfully, but these errors were encountered: