[ 
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)

Reply via email to