[MERGE] Transport.readv() closes the file handle
Vincent Ladeuil
v.ladeuil+lp at free.fr
Mon Oct 27 19:54:11 GMT 2008
>>>>> "john" == John Arbash Meinel <john at arbash-meinel.com> writes:
john> ...
>> I *can* say that it is happening, and it is a bit hard to debug or test,
>> because it only fails if you are doing something concurrently (which we
>> don't often do in bzr) and if you are on a platform that doesn't like
>> file handles left open.
>>
Thanks for the detailed explanation.
>> So if you prefer, I can make '.close()' a strictly required attribute,
>> but I don't think I can assume all callers run the iterator to
>> completion (because of the issue with zip()). I could track down all the
>> different places to put readv() first, but rememember that sometimes
>> generators are stacked, and that gets tricky to resolve.
Not worth the effort, thanks for tracking down the problematic
cases.
<snip/>
john> I ended up going with this code:
>> === modified file 'bzrlib/transport/__init__.py'
>> --- bzrlib/transport/__init__.py 2008-10-06 06:34:36 +0000
>> +++ bzrlib/transport/__init__.py 2008-10-27 15:28:44 +0000
>> @@ -688,8 +688,21 @@
>> # Now that we've read some data, see if we can yield anything back
>> while cur_offset_and_size in data_map:
>> this_data = data_map.pop(cur_offset_and_size)
>> - yield cur_offset_and_size[0], this_data
>> - cur_offset_and_size = offset_stack.next()
>> + this_offset = cur_offset_and_size[0]
>> + try:
>> + cur_offset_and_size = offset_stack.next()
>> + except StopIteration:
>> + # Close the file handle as there will be no more data
>> + # The handle would normally be cleaned up as this code goes
>> + # out of scope, but as we are a generator, not all code
>> + # will re-enter once we have consumed all the expected
>> + # data. For example:
>> + # zip(range(len(requests)), readv(foo, requests))
>> + # Will stop because the range is done, and not run the
>> + # cleanup code for the readv().
>> + fp.close()
>> + cur_offset_and_size = None
>> + yield this_offset, this_data
>>
>> def _sort_expand_and_combine(self, offsets, upper_limit):
>> """Helper for readv.
john> It means that when the iterator *is* fully consumed, we
john> will reach the end of the function, rather than exiting
john> from the exception raised by offset_stack.next() It
john> also means I don't have to have a counter tracking
john> along with the iterator. It moves the .next() before
john> the yield, but this is still safe.
I agree that is the best that can be achieved given the generator
limitations.
john> I did make fp.close() strictly required, which is a
john> small api change, but shouldn't actually cause
john> problems.
Perfect for me.
Vincent
More information about the bazaar
mailing list