Skip to content

Commit

Permalink
Merge pull request #8444 from ThomasWaldmann/refresh-lock-many-unchan…
Browse files Browse the repository at this point in the history
…ged-files

Refresh lock at more places
  • Loading branch information
ThomasWaldmann authored Oct 2, 2024
2 parents 29d16f5 + d991071 commit 5a87b41
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 1 deletion.
16 changes: 15 additions & 1 deletion src/borg/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import shutil
import stat
from collections import namedtuple
from datetime import datetime, timezone
from datetime import datetime, timezone, timedelta
from time import perf_counter

from .logger import create_logger
Expand Down Expand Up @@ -709,6 +709,8 @@ class ChunksMixin:

def __init__(self):
self._chunks = None
self.last_refresh_dt = datetime.now(timezone.utc)
self.refresh_td = timedelta(seconds=60)

@property
def chunks(self):
Expand Down Expand Up @@ -751,13 +753,18 @@ def add_chunk(
size = len(data) # data is still uncompressed
else:
raise ValueError("when giving compressed data for a chunk, the uncompressed size must be given also")
now = datetime.now(timezone.utc)
exists = self.seen_chunk(id, size)
if exists:
# if borg create is processing lots of unchanged files (no content and not metadata changes),
# there could be a long time without any repository operations and the repo lock would get stale.
self.refresh_lock(now)
return self.reuse_chunk(id, size, stats)
cdata = self.repo_objs.format(
id, meta, data, compress=compress, size=size, ctype=ctype, clevel=clevel, ro_type=ro_type
)
self.repository.put(id, cdata, wait=wait)
self.last_refresh_dt = now # .put also refreshed the lock
self.chunks.add(id, ChunkIndex.MAX_VALUE, size)
stats.update(size, not exists)
return ChunkListEntry(id, size)
Expand All @@ -767,6 +774,13 @@ def _write_chunks_cache(self, chunks):
write_chunkindex_to_repo_cache(self.repository, self._chunks, compact=True, clear=True)
self._chunks = None # nothing there (cleared!)

def refresh_lock(self, now):
if now > self.last_refresh_dt + self.refresh_td:
# the repository lock needs to get refreshed regularly, or it will be killed as stale.
# refreshing the lock is not part of the repository API, so we do it indirectly via repository.info.
self.repository.info()
self.last_refresh_dt = now


class AdHocWithFilesCache(FilesCacheMixin, ChunksMixin):
"""
Expand Down
6 changes: 6 additions & 0 deletions src/borg/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,25 +476,31 @@ def migrate_lock(self, old_id, new_id):
self.lock.migrate_lock(old_id, new_id)

def get_manifest(self):
self._lock_refresh()
try:
return self.store.load("config/manifest")
except StoreObjectNotFound:
raise NoManifestError

def put_manifest(self, data):
self._lock_refresh()
return self.store.store("config/manifest", data)

def store_list(self, name):
self._lock_refresh()
try:
return list(self.store.list(name))
except StoreObjectNotFound:
return []

def store_load(self, name):
self._lock_refresh()
return self.store.load(name)

def store_store(self, name, value):
self._lock_refresh()
return self.store.store(name, value)

def store_delete(self, name):
self._lock_refresh()
return self.store.delete(name)

0 comments on commit 5a87b41

Please sign in to comment.