Skip to content

Commit

Permalink
rename local preload() function to not overwrite keyword argument of …
Browse files Browse the repository at this point in the history
…same name

The locally defined preload() function overwrites the preload boolean keyword
argument, always evaluating to true, so preloading is done, even when not
requested by the caller, causing a memory leak.
Also move its definition outside of the loop.

This issue was found by Antonio Larrosa in borg issue borgbackup#5202.
  • Loading branch information
elho committed Jun 2, 2020
1 parent b69e98d commit 3587eba
Showing 1 changed file with 6 additions and 6 deletions.
12 changes: 6 additions & 6 deletions src/borg/archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,9 @@ def unpack_many(self, ids, filter=None, partial_extract=False, preload=False, ha
Warning: if *preload* is True then all data chunks of every yielded item have to be retrieved,
otherwise preloaded chunks will accumulate in RemoteRepository and create a memory leak.
"""
def _preload(chunks):
self.repository.preload([c.id for c in chunks])

masters_preloaded = set()
unpacker = msgpack.Unpacker(use_list=False)
for data in self.fetch_many(ids):
Expand All @@ -211,9 +214,6 @@ def unpack_many(self, ids, filter=None, partial_extract=False, preload=False, ha
if 'chunks' in item:
item.chunks = [ChunkListEntry(*e) for e in item.chunks]

def preload(chunks):
self.repository.preload([c.id for c in chunks])

if filter:
items = [item for item in items if filter(item)]

Expand All @@ -226,7 +226,7 @@ def preload(chunks):
# due to a side effect of the filter() call, we now have hardlink_masters dict populated.
for item in items:
if 'chunks' in item: # regular file, maybe a hardlink master
preload(item.chunks)
_preload(item.chunks)
# if this is a hardlink master, remember that we already preloaded it:
if 'source' not in item and hardlinkable(item.mode) and item.get('hardlink_master', True):
masters_preloaded.add(item.path)
Expand All @@ -236,13 +236,13 @@ def preload(chunks):
# we only need to preload *once* (for the 1st selected slave)
chunks, _ = hardlink_masters[source]
if chunks is not None:
preload(chunks)
_preload(chunks)
masters_preloaded.add(source)
else:
# easy: we do not have a filter, thus all items are selected, thus we need to preload all chunks.
for item in items:
if 'chunks' in item:
preload(item.chunks)
_preload(item.chunks)

for item in items:
yield item
Expand Down

0 comments on commit 3587eba

Please sign in to comment.