[ 
https://issues.apache.org/jira/browse/CASSANDRA-9863?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14636887#comment-14636887
 ] 

Benedict commented on CASSANDRA-9863:
-------------------------------------

Well, it actually would be necessary to call it if it's {{null}} in some 
circumstances, because we may have a large buffer that has a vint right at the 
end, that has no spare room to increase the buffer size beyond for cheaply 
performing vint reads at the end. In this case we would need to confirm we 
haven't got more to read - the easiest way being to return -1 if it's {{null}} 
in {{readNext}} as you previously suggested. Of course, we could enforce this 
earlier in {{readPaddedPrimitive}}, but we need to shuffle our data back in 
this case, so we really are best leaving this to {{readNext}} I think.

While we're here, I notice that at some point we changed {{readNext}}'s 
shuffling to use a duplicated {{ByteBuffer}}, which is probably much more 
costly than just looping ourselves calling put/get (especially since this is 
all it does). Or calling {{FastByteOperations.copy}} (and making this faster 
for this case, since {{copyMemory}} is costly).

> NIODataInputStream has problems on trunk
> ----------------------------------------
>
>                 Key: CASSANDRA-9863
>                 URL: https://issues.apache.org/jira/browse/CASSANDRA-9863
>             Project: Cassandra
>          Issue Type: Bug
>            Reporter: Sylvain Lebresne
>            Assignee: Ariel Weisberg
>            Priority: Blocker
>             Fix For: 3.0 beta 1
>
>
> As the title says, there is cases where method calls to NIODataInputStream, 
> at least {{readVInt}} calls can loop forever. This is possibly only a problem 
> for vints where the code tries to read 8 bytes minimum but there is less than 
> that available, and in that sense is related to [~benedict]'s observation in 
> CASSANDRA-9708, but it is more serious than said observation because:
> # this can happen even if the buffer passed to NIODataInputStream ctor has 
> more than 8 bytes available, and hence I'm relatively confident [~benedict]'s 
> fix in CASSANDRA-9708 is not enough.
> # this doesn't necessarily fail cleanly by raising assertions, this can loop 
> forever (which is much harder to debug).
> Due of that, and because that is at least one of the cause of CASSANDRA-9764, 
> I think the problem warrants a specific ticket (from CASSANDRA-9708 that is).
> Now, the exact reason of this is looping is if {{readVInt}} is called but the 
> buffer has less than 8 byte remaining (again, the buffer had more initially). 
> In that case, {{readMinimum(8, 1)}} is called and it calls {{readNext()}} in 
> a loop. Within {{readNext()}}, the buffer (which has {{buf.position() == 0 && 
> buf.hasRemaining()}}) is actually unchanged (through a very weird dance of 
> setting the position to the limit, then the limit to the capacity, and then 
> flipping the buffer which resets everything to what it was), and because 
> {{rbc}} is the {{emptyReadableByteChannel}}, {{rbc.read(buf)}} does nothing 
> and always return {{-1}}. Back in {{readMinimum}}, {{read == -1}} but 
> {{remaining >= require}} (and {{remaining}} never changes), and hence the 
> forever looping.
> Now, not sure what the best fix is because I'm not fully familiar with that 
> code, but that does leads me to a 2nd point: {{NIODataInputSttream}} can IMHO 
> use a bit of additional/better comments. I won't pretend having tried very 
> hard to understand the whole class, so there is probably some lack of effort, 
> but at least a few things felt like they should clarified:
> * Provided I understand {{readNext()}} correctly, it only make sense when we 
> do have a {{ReadableByteChannel}} (and the fact that it's not the case sounds 
> like the bug). If that's the case, this should be explicitly documented and 
> probably asserted. As as an aside, I wonder if using {{rbc == null}} when we 
> don't have wouldn't be better: if we don't have one, we shouldn't try to use 
> it, and having a {{null}} would make things fail loudly if we do.
> * I'm not exactly sure what {{readMinimum}} arguments do. I'd have expected 
> at least one to be called "minimum", and an explanation of the meaning of the 
> other one.
> * {{prepareReadPaddedPrimitive}} says that it "Add padding if requested" but 
> there is seemingly no argument that trigger the "if requested part". Also 
> unclear what that padding is about in the first place.
> As a final point, it looks like the case where {{NIODataInputStream}} is 
> constructed with a {{ByteBuffer}} (rather than a {{ReadableByteChannel}}) 
> seems to be completely untested by the unit tests.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to