--- a/mercurial/store.py Fri Mar 08 10:20:33 2019 -0800
+++ b/mercurial/store.py Thu Nov 22 15:14:24 2018 +0300
@@ -8,6 +8,7 @@
from __future__ import absolute_import
import errno
+import functools
import hashlib
import os
import stat
@@ -23,6 +24,9 @@
)
parsers = policy.importmod(r'parsers')
+# how much bytes should be read from fncache in one read
+# It is done to prevent loading large fncache files into memory
+fncache_chunksize = 10 ** 6
def _matchtrackedpath(path, matcher):
"""parses a fncache entry and returns whether the entry is tracking a path
@@ -463,7 +467,20 @@
# skip nonexistent file
self.entries = set()
return
- self.entries = set(decodedir(fp.read()).splitlines())
+
+ self.entries = set()
+ chunk = b''
+ for c in iter(functools.partial(fp.read, fncache_chunksize), b''):
+ chunk += c
+ try:
+ p = chunk.rindex(b'\n')
+ self.entries.update(decodedir(chunk[:p + 1]).splitlines())
+ chunk = chunk[p + 1:]
+ except ValueError:
+ # substring '\n' not found, maybe the entry is bigger than the
+ # chunksize, so let's keep iterating
+ pass
+
self._checkentries(fp)
fp.close()