comparison mercurial/util.py @ 25672:050dc6eabc92

bufferedinputpipe: remove N^2 computation of buffer length (issue4735) The assumption that dynamically computing the length of the buffer was N^2, but negligible because fast was False. So we drop the dynamic computation and manually keep track of the buffer length.
author Pierre-Yves David <pierre-yves.david@fb.com>
date Fri, 26 Jun 2015 11:29:50 -0700
parents d5ac3bebaf2a
children ce26928cbe41
comparison
equal deleted inserted replaced
25671:d5ac3bebaf2a 25672:050dc6eabc92
252 252
253 def __init__(self, input): 253 def __init__(self, input):
254 self._input = input 254 self._input = input
255 self._buffer = [] 255 self._buffer = []
256 self._eof = False 256 self._eof = False
257 self._lenbuf = 0
257 258
258 @property 259 @property
259 def hasbuffer(self): 260 def hasbuffer(self):
260 """True is any data is currently buffered 261 """True is any data is currently buffered
261 262
281 def readline(self, *args, **kwargs): 282 def readline(self, *args, **kwargs):
282 if 1 < len(self._buffer): 283 if 1 < len(self._buffer):
283 # this should not happen because both read and readline end with a 284 # this should not happen because both read and readline end with a
284 # _frombuffer call that collapse it. 285 # _frombuffer call that collapse it.
285 self._buffer = [''.join(self._buffer)] 286 self._buffer = [''.join(self._buffer)]
287 self._lenbuf = len(self._buffer[0])
286 lfi = -1 288 lfi = -1
287 if self._buffer: 289 if self._buffer:
288 lfi = self._buffer[-1].find('\n') 290 lfi = self._buffer[-1].find('\n')
289 while (not self._eof) and lfi < 0: 291 while (not self._eof) and lfi < 0:
290 self._fillbuffer() 292 self._fillbuffer()
296 elif 1 < len(self._buffer): 298 elif 1 < len(self._buffer):
297 # we need to take previous chunks into account 299 # we need to take previous chunks into account
298 size += self._lenbuf - len(self._buffer[-1]) 300 size += self._lenbuf - len(self._buffer[-1])
299 return self._frombuffer(size) 301 return self._frombuffer(size)
300 302
301 @property
302 def _lenbuf(self):
303 """return the current lengh of buffered data"""
304 return sum(len(d) for d in self._buffer)
305
306 def _frombuffer(self, size): 303 def _frombuffer(self, size):
307 """return at most 'size' data from the buffer 304 """return at most 'size' data from the buffer
308 305
309 The data are removed from the buffer.""" 306 The data are removed from the buffer."""
310 if size == 0 or not self._buffer: 307 if size == 0 or not self._buffer:
315 312
316 data = buf[:size] 313 data = buf[:size]
317 buf = buf[len(data):] 314 buf = buf[len(data):]
318 if buf: 315 if buf:
319 self._buffer = [buf] 316 self._buffer = [buf]
317 self._lenbuf = len(buf)
320 else: 318 else:
321 self._buffer = [] 319 self._buffer = []
320 self._lenbuf = 0
322 return data 321 return data
323 322
324 def _fillbuffer(self): 323 def _fillbuffer(self):
325 """read data to the buffer""" 324 """read data to the buffer"""
326 data = os.read(self._input.fileno(), _chunksize) 325 data = os.read(self._input.fileno(), _chunksize)
327 if not data: 326 if not data:
328 self._eof = True 327 self._eof = True
329 else: 328 else:
329 self._lenbuf += len(data)
330 self._buffer.append(data) 330 self._buffer.append(data)
331 331
332 def popen2(cmd, env=None, newlines=False): 332 def popen2(cmd, env=None, newlines=False):
333 # Setting bufsize to -1 lets the system decide the buffer size. 333 # Setting bufsize to -1 lets the system decide the buffer size.
334 # The default for bufsize is 0, meaning unbuffered. This leads to 334 # The default for bufsize is 0, meaning unbuffered. This leads to