[
https://issues.apache.org/jira/browse/JCR-4005?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15432170#comment-15432170
]
Woonsan Ko commented on JCR-4005:
---------------------------------
I think I figured out the root cause.
It occasionally fails in the {{assertNull}} line below.
{code}
protected void doDeleteRecordTest() throws Exception {
// SNIP
DataRecord rec2 = ds.addRecord(new ByteArrayInputStream(data2));
// SNIP
((MultiDataStoreAware)ds).deleteRecord(rec2.getIdentifier());
assertNull("rec2 should be null",
ds.getRecordIfStored(rec2.getIdentifier()));
{code}
The reason is as follows:
- By default, a CachingDataStore (such as VFSDataStore) writes data to the
backend asynchronously when invoking {{DataStore#addRecord()}}.
- If this asynchronous job doesn't complete before invoking
{{DataStore#deleteRecord()}}, the deletion actually didn't happen. As a result,
the assertion of the deletion fails.
For more detail, here's an invocation flow:
- CachingDataStore#addRecord()
--> VFSBackend#writeAsync()
--> new CachingDataRecord()
--> CachingDataRecord#getLength()
--> CachingDataStore#getLength()
(if not found in {{recLenCache}}, put in a new item :
{{recLenCache.put(identifier, length)}}.)
Meanwhile, the {{DataStore#deleteRecord()}} could complete its call before
{{CachingDataStore#getLength()}} completes. Therefore, the same identifier can
be just added to {{recLenCache}} even if it was supposed to be deleted in
another thread.
Also, {{DataStore#getRecordIfStored()}} returns a {{CachingDataRecord}}
instance because it finds the (deleted) item from {{recLenCache}}. (See
{{CachingDataStore#getRecordIfStored()}}).
-----
I think this is caused by the difference between how {{TestCaseBase}} was
implemented and how {{CachingDataStore}} was designed.
{{CachingDataStore}} enables asynchronous writing to the backend by default
(actually always). Therefore, unless the DataStore does something very special
when writing asynchronously and reading synchronously, this problem should
always happen.
In contrast, {{TestCaseBase}} seems to have been implemented originally for
non-Caching DataStore implementations that do not have any asynchronous writing.
At the moment, {{CachingDataStore}} doesn't care about synchronous
deleting/reading while adding(writing) something asynchronously. And it seems
more complex if we want to care about that (even in the future).
Therefore, my conclusion is:
- Simply provide an option to disable asynchronous writing in the VFSDataStore,
- and disable asynchronous writing in unit tests (with local file system).
- In reality, users can still enable asynchronous writing. In that case, they
should be aware that a delete invocation might fail. I guess this can be
acceptable in many practical use cases.
> TestVFSDataStore.testDeleteRecord() fails occasionally
> ------------------------------------------------------
>
> Key: JCR-4005
> URL: https://issues.apache.org/jira/browse/JCR-4005
> Project: Jackrabbit Content Repository
> Issue Type: Bug
> Components: jackrabbit-vfs-ext
> Reporter: Marcel Reutegger
> Priority: Minor
>
> The test failed on Jenkins and also fails occasionally on my machine:
> https://builds.apache.org/job/Jackrabbit-trunk/org.apache.jackrabbit$jackrabbit-vfs-ext/2369/console
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)