On 03/15/2010 09:18 PM, Paul Libbrecht wrote: > > Does it mean that any transaction might actually live in the DB for a > long long time, beyond restarts of xwiki or the DB, and that a global > rollback?
=== The context === Object properties can have different logical types: StringClass, BooleanClass, NumberClass, DBListClass, etc. This is the type that is defined in the Class, and which specifies how values are presented to the user (text input, radio boxes, textarea...). They can also have different storage types: StringProperty, LargeStringProperty, StringListProperty, IntegerProperty, LongProperty, DateProperty, etc. This is the type that is stored in the database, and which determines the column type and length. There is no 1-1 relation between logical and storage types; depending on the settings, one logical type can have up to four different storage types, and different logical types can have the same storage type. For example, the NumberClass, depending on the number type, can be stored as one of: IntegerProperty, LongProperty, FloatProperty, DoubleProperty. Another example, StaticListClass, DBListClass and DBTreeListClass, which have configurable multipleSelect and relationalStorage, can be stored as: - MS=1 and RS=1 => DBStringListProperty - MS=1 and RS=0 => StringListProperty - MS=0 => StringProperty === The problem === The problem is that the storage type for a property can be changed dynamically, by changing its settings. Thus, a Number property that used to be stored as a Float can become a Double. This means that the table that stores this type of properties will change. But since this is a weak type information, and the change happens outside Hibernate, existing properties won't get moved from one table to the other. Now, Hibernate is a little tricky, it normally doesn't expect this kind of change, so it doesn't automatically detect that an entity moved between tables. Yet, since in our mapping all properties are declared as subclasses of a generic BaseProperty, a FloatProperty and its corresponding DoubleProperty have the same identifier. So, the process that causes problems is: - Create a class with a Number property of type float - Create an object for that class - Change the property type to double - Update the existing object (the same thing for other type of changes) Internally, Hibernate does this: - Load Entity XYZ as a FloatProperty - Store Entity XYZ as a DoubleProperty Now, the two XYZ should be the same entity as far as Hibernate sees, since they are both BaseProperty and have the same ID. But, since the real type differs (FloatProperty vs DoubleProperty), they are two distinct entities. Also, the initial type of the property is stored in the BaseProperty table. Hibernate can't remove the FloatProperty, since the new XYZ doesn't reference in any way the old XYZ. It also can't save the new XYZ, since the stored type differs from the current type. Now, two things happen: - The FloatProperty is ghosted; you can't remove it from the database in any normal way, just a low level SQL query can remove it. - The DoubleProperty can't be saved because the FloatProperty is blocking it. The second issue prevents the property, along with its object, and along with its document, from being saved anymore. The first issue means that this problem will NEVER be fixed. Now, to answer your question, there are two storages active in a normal XWiki engine: the Hibernate storage, and the Cache storage. For performance reasons, the cache returns the real object that is stored in it. Depending on how the document is updated, the code might get the document from the cache (storage), update it, and push it back to the storage. Although the save fails, the object remains in the changed state, and a reference to it was already present in the cache. Next time the object is retrieved from the cache, the unsaved, but changed document will be returned. This happens as long as the document is still present in the cache. === The solution? === Theoretically, this bug was fixed (see http://jira.xwiki.org/jira/browse/XWIKI-299 ) by manually moving existing affected properties to the new correct type when a problematic class change occurs. Why does it continue to happen, beats me. I'll have to investigate again. > paul > > Le 06-mars-10 à 00:21, Sergiu Dumitriu a écrit : > >>>> org.hibernate.StaleObjectStateException: Row was updated or deleted >>>> by another transaction (or unsaved-value mapping was incorrect): >>>> [com.xpn.xwiki.objects.StringProperty#<?xml version="1.0" >>>> encoding="UTF-8"?> >>>> <eduLevelFine></eduLevelFine> >>>> ] >>>> at >>>> org >>>> .hibernate >>>> .persister >>>> .entity.AbstractEntityPersister.check(AbstractEntityPersister.java: >>>> 1765) >>> >>> I am puzzled and have no idea where to go except into SQL, which is >>> not really a safe thing. >> >> But I'm afraid it's the only real solution... -- Sergiu Dumitriu http://purl.org/net/sergiu/ _______________________________________________ users mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/users
