XWikiDocuments not thread safe added to XWikiCacheStore
Description
XWikiDocument class is not thread safe. Thus XWikiDocument objects created and loaded without any synchronisation in loadXWikiDoc XWikiHibernateStore lack memory visibility guaranties. These objects are added to the XWikiCacheStore (normally Jboss implementation) again without any synchronization. Hence the XWikiDocument object which is possibly incompletely written to the main memory, is publish to multiple threads by adding to the cache (e.g. jbosscache). All threads running on a different cpu core (multicore architecture) may see an incomplete version of the loaded XWikiDocument object.
There is a junit test proving the broken multi core multi-threaded situation:
test_multiThreaded_scenario1 will fail on a multi core architecture. Yet, test_multiRuns_singleThreaded_scenario1 succeeds and shows that the test implementation is correct.
Agreed on following solution: Introducing a nested DocumentLoader class which loads the document calling the basestore loadXWikiDoc in a synchronized getDocOrLoad method. The DocumentLoader objects gets instantiated in the cacheStore on a cache miss. It then gets stored in a ConcurrentHashMap using the same key as is used for the document cache (DocumentReference including language). Using putIfAbsent to insert the DocumentLoader and calling the synchronized load method on the object in the map solves the memory visibility issue and moreover ensures that the same XWikiDocument is not loaded multiple times concurrently from the database. It is still possible to load different documents in parallel. A DocumentLoader will load the XWikiDocument only once and the returns the identical document object on any following call of the synchronized getDocOrLoad method.
XWikiDocument class is not thread safe. Thus XWikiDocument objects created and loaded without any synchronisation in loadXWikiDoc XWikiHibernateStore lack memory visibility guaranties. These objects are added to the XWikiCacheStore (normally Jboss implementation) again without any synchronization. Hence the XWikiDocument object which is possibly incompletely written to the main memory, is publish to multiple threads by adding to the cache (e.g. jbosscache). All threads running on a different cpu core (multicore architecture) may see an incomplete version of the loaded XWikiDocument object.
There is a junit test proving the broken multi core multi-threaded situation:
test_multiThreaded_scenario1 will fail on a multi core architecture. Yet, test_multiRuns_singleThreaded_scenario1 succeeds and shows that the test implementation is correct.
Agreed on following solution:
Introducing a nested DocumentLoader class which loads the document calling the basestore loadXWikiDoc in a synchronized getDocOrLoad method. The DocumentLoader objects gets instantiated in the cacheStore on a cache miss. It then gets stored in a ConcurrentHashMap using the same key as is used for the document cache (DocumentReference including language). Using putIfAbsent to insert the DocumentLoader and calling the synchronized load method on the object in the map solves the memory visibility issue and moreover ensures that the same XWikiDocument is not loaded multiple times concurrently from the database. It is still possible to load different documents in parallel. A DocumentLoader will load the XWikiDocument only once and the returns the identical document object on any following call of the synchronized getDocOrLoad method.