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

Reply via email to