[
https://issues.apache.org/jira/browse/OAK-7721?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Francesco Mari resolved OAK-7721.
---------------------------------
Resolution: Fixed
Fix Version/s: 1.9.9
Fixed at r1840024.
> Records of specific size bring SegmentBufferWriter#flush to fail
> ----------------------------------------------------------------
>
> Key: OAK-7721
> URL: https://issues.apache.org/jira/browse/OAK-7721
> Project: Jackrabbit Oak
> Issue Type: Bug
> Components: segment-tar
> Reporter: Francesco Mari
> Assignee: Francesco Mari
> Priority: Major
> Fix For: 1.10, 1.9.9
>
> Attachments: OAK-7688-template-writer.patch, OAK-7721-01.patch,
> OAK-7721-02.patch, OAK-7721-03.patch, test.patch
>
>
> In a handful of cases, {{SegmentBufferWriter#flush}} has been observed to
> fail with an ISE without any other part of the system behaving incorrectly or
> suspiciously. This problem was reported before (OAK-6452) but we were unable
> to reproduce it.
> I investigated further and was able to reproduce the problem reliably in a
> test case. The trick is to craft a record of a very specific length that
> fools the {{SegmentBufferWriter}} into believing that it has enough space to
> store the record, even if the record consumes all the available space in the
> buffer, including the space reserved for the segment header. This is the
> reason why no call to {{SegmentBufferWriter#prepare}} fails, but calls to
> {{SegmentBufferWriter#flush}} do.
> The attached test case executes the following steps.
> * The test creates a new {{SegmentBufferWriter}}. The buffer is fresh, but it
> is immediately populated with the segment info, which is 38 bytes long. The
> size of the segment info is aligned to 40 bytes, so at the end of the
> initialization the segment contains 40 bytes of record data. Please note that
> at this point in time the buffer is not marked as dirty.
> * The test prepares space for a block record of 262101 bytes, which is
> aligned to 262104 bytes. The code in in {{prepare()}} figures out that adding
> this record to the current segment would exceed the maximum size of 262144
> bytes, so it flushes the current segment.
> * The flush operation is skipped because the buffer is not dirty yet. The
> segment is not flushed.
> * The code in {{prepare()}} resumes execution. Trusting that it's working on
> a fresh segment, big enough to contain the new record, {{prepare()}} updates
> the state of the {{SegmentBufferWriter}}. In particular, {{length}} is set to
> exactly {{262144}} and {{position}} to {{0}}. Even if the record consumes all
> the available space in the buffer, {{prepare()}} is happy to go on because
> {{position}} remains nonnegative.
> * The test flushes the {{SegmentBufferWriter}}. When the size of the
> resulting segment is computed, the size of the segment header is added to the
> size of the records. The size of the records is {{262144}} bytes, which is
> exactly the segment maximum size, and adding the size of the segment header
> obviously exceeds the maximum size for a segment. At this point, {{flush()}}
> fails with an ISE.
--
This message was sent by Atlassian JIRA
(v7.6.3#76005)