On 03/01/2012, at 11:15 AM, Brian Geffon wrote:

> So you're right, now that I have the full code in front of me...I understand 
> what you're saying, my previous email was wrong, but I don't see where the 
> discrepancy could be coming from because a loop over 
> TSIOBufferBlockReadStart() over all blocks appears to do the exact same thing 
> as TSIOBufferReaderAvail().
> 
> Here is what happens when you call TSIOBufferReaderAvail():
> 
> TS_INLINE int64_t
> IOBufferReader::read_avail()
> {
>  int64_t t = 0;
>  IOBufferBlock *b = block;
> 
>  while (b) {
>    t += b->read_avail();
>    b = b->next;
>  }
>  t -= start_offset;
>  if (size_limit != INT64_MAX && t > size_limit)
>    t = size_limit;
>  return t;
> }
> 
> It's summing up the sizes of all the blocks and backing out the start_offset, 
> now if we examine the code of TSIOBufferBlockReadStart(), I added two small 
> comments below to the function
> 
> const char *
> TSIOBufferBlockReadStart(TSIOBufferBlock blockp, TSIOBufferReader readerp, 
> int64_t *avail)
> {
>  sdk_assert(sdk_sanity_check_iocore_structure(blockp) == TS_SUCCESS);
>  sdk_assert(sdk_sanity_check_iocore_structure(readerp) == TS_SUCCESS);
> 
>  IOBufferBlock *blk = (IOBufferBlock *)blockp;
>  IOBufferReader *reader = (IOBufferReader *)readerp;
>  char *p;
> 
>  p = blk->start();
>  if (avail)
>    *avail = blk->read_avail(); // avail is set to the size of this block
> 
>  if (blk == reader->block) { 
>    // if this is the first block, then advance the pointer and back out the 
> start offset
>    p += reader->start_offset;
>    if (avail) {
>      *avail -= reader->start_offset;
>      if (*avail < 0) {
>        *avail = 0;
>      }
>    }
>  }
> 
>  return (const char *)p;
> }
> 
> So now looking again, the only possible issue could be that you're using 
> TSIOBufferStart() instead of TSIOBufferReaderStart(), can you try using 
> TSIOBufferReaderStart() to get the first block instead of using 
> TSIOBufferStart(), because TSIOBufferStart() will try to add new blocks if 
> the current block can't be written to, which means that you could potentially 
> bypass the first block and get a new empty block.

I switched to TSIOBufferReaderStart() and haven't been able to repro yet ... 
very promising!

thanks,
James

> 
> 
> Brian
> 
> ________________________________________
> From: James Peach [jamespe...@me.com]
> Sent: Monday, January 02, 2012 6:47 PM
> To: dev@trafficserver.apache.org
> Subject: Re: inconsistent read IOBuffer results
> 
> On 02/01/2012, at 6:13 PM, Brian Geffon wrote:
> 
>> My last email was incorrect, it will correctly return the pointer to the
>> memory of the block, but avail will not be touched and you will have no
>> idea how much data could have been read. You actually don't even need to
>> call TSIOBufferBlockReadStart(), TSIOBufferReadAvail() should just be
>> equal to the sum of all of the calls to the TSIOBufferBlockReadAvail().
> 
> Yes, that's exactly the invariant that is being violated. I can sometimes end 
> up with TSIOBufferReadAvail() claiming there are more bytes than are actually 
> available from the buffer.
> 
> I'm inside the TSVConnRead() continuation, responding to 
> TS_EVENT_VCONN_READ_READY, so I don't *think* that I need to do any 
> additional locking. It might be an internal race, but I have slightly hacked 
> up my ATS tree, so it's also possible that I caused a stale value to be 
> reported by TSIOBufferReadAvail().
> 
>> The following is untested but it appears that it should give what you want:
>> 
>> block = TSIOBufferStart(buffer);
>>  while (block) {
>> count += TSIOBufferBlockReadAvail(block,reader);
>> block = TSIOBufferBlockNext(block);
>>  }
> 
> That's a more succinct version of the code I posted, right?
> 
>> 
>> Brian
>> 
>> 
>> 
>> On 1/2/12 6:04 PM, "Brian Geffon" <briangef...@gmail.com> wrote:
>> 
>>> I dont think this is a bug, your usage of TSIOBufferBlockReadStart()
>>> is incorrect. The third parameter which you call nbytes is set to the
>>> number of bytes remaining in the buffer block after the read. Since
>>> you're setting it to zero before the call to
>>> TSIOBufferBlockReadStart() it's actually not going to read anything...
>>> 
>>> if (avail)
>>>  *avail = blk->read_avail();
>>> 
>>> So since it's not getting the correct size of the block, and thus will
>>> not reading anything anyway because before it tries to read the block
>>> it does:
>>> 
>>> if (avail) {
>>>    *avail -= reader->start_offset;
>>>    if (*avail < 0) {
>>>      *avail = 0;
>>>    }
>>>  }
>>> 
>>> So it's never going to touch avail. So that means nbytes be set to
>>> TSIOBufferBlockReadAvail() before the call
>>> 
>>> int64_t nbytes = TSIOBufferBlockReadAvail( ... )
>>> int64_t nbytes_remaining = nbytes;
>>> 
>>> and then, nbytes_remaining will be the number of bytes remaining to be
>>> read, which should actually be 0 after the call to
>>> TSIOBufferBlockReadStart(), So the total bytes contained in the block
>>> was :
>>> 
>>> ptr = TSIOBufferBlockReadStart(block, reader, &nbytes_remaining);
>>> if(ptr) {
>>> int64_t bytes_in_block = nbytes - nbytes_remaining; // that's how
>>> much we actually were able to read
>>> count += bytes_in_block;
>>> }
>>> 
>>> Does that help?
>>> 
>>> On Mon, Jan 2, 2012 at 5:45 PM, James Peach <jamespe...@me.com> wrote:
>>>> On 02/01/2012, at 1:18 PM, James Peach wrote:
>>>> 
>>>>> On 02/01/2012, at 11:30 AM, Brian Geffon wrote:
>>>>> 
>>>>>> I think you might want TSIOBufferBlockReadAvail and not
>>>>>> TSIOBufferReaderAvail.
>>>>> 
>>>>> Hmm, so my code is assuming that all the data is in the first buffer
>>>>> block. It sounds like that it not guaranteed and that I ought to be
>>>>> calling TSIOBufferBlockNext() if the first buffer block doesn't have
>>>>> all the data.
>>>> 
>>>> After some more testing, I think that this is a bug.
>>>> TSIOBufferReaderAvail() returns 43, but there are subsequently 0 bytes
>>>> available. Iterating the buffer blocks as below confirms this. My
>>>> understanding of TSIOBufferReaderAvail() and the assumption of other
>>>> usages of it that I have seen is that the data in teh buffer blocks
>>>> should all add up to the available count from the buffer reader. I
>>>> haven't seen any indication that TSIOBufferReaderAvail() is advisory.
>>>> 
>>>> static size_t
>>>> count_bytes_available(
>>>>      TSIOBuffer          buffer,
>>>>      TSIOBufferReader    reader)
>>>> {
>>>>  TSIOBufferBlock block;
>>>>  size_t count = 0;
>>>> 
>>>>  block = TSIOBufferStart(buffer);
>>>>  while (block) {
>>>>      const char * ptr;
>>>>      int64_t nbytes = 0;
>>>> 
>>>>      ptr = TSIOBufferBlockReadStart(block, reader, &nbytes);
>>>>      if (ptr && nbytes) {
>>>>          count += nbytes;
>>>>      }
>>>> 
>>>>      block = TSIOBufferBlockNext(block);
>>>>  }
>>>> 
>>>>  return count;
>>>> }
>>>> 
>>>>> 
>>>>> thanks,
>>>>> James
>>>>> 
>>>>>> 
>>>>>> Brian
>>>>>> ________________________________________
>>>>>> From: James Peach [jamespe...@me.com]
>>>>>> Sent: Saturday, December 31, 2011 10:07 PM
>>>>>> To: dev@trafficserver.apache.org
>>>>>> Subject: inconsistent read IOBuffer results
>>>>>> 
>>>>>> Hi all,
>>>>>> 
>>>>>> In my proxy code, I have something that looks roughly like this:
>>>>>> 
>>>>>>     if (TSIOBufferReaderAvail(reader) >= 10) {
>>>>>>             blk = TSIOBufferStart(buffer);
>>>>>>             ptr = (const uint8_t *)TSIOBufferBlockReadStart(blk,
>>>>>> reader, &nbytes);
>>>>>> 
>>>>>>             TSReleaseAssert(nbytes >= 10);
>>>>>>     }
>>>>>> 
>>>>>> Occasionally, the assertion will trigger; is that something that I
>>>>>> should expect and handle?
>>>>>> 
>>>>>> cheers,
>>>>>> James
>>>>> 
>>>> 
>> 
> 

Reply via email to