Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/borg/archiver/check_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def do_check(self, args, repository):
except IntegrityError:
pass # will try to make key later again
if not args.archives_only:
if not repository.check(repair=args.repair, max_duration=args.max_duration):
if not repository.check(repair=args.repair, max_duration=args.max_duration, progress=args.progress):
set_ec(EXIT_WARNING)
if not args.repo_only and not archive_checker.check(
repository,
Expand Down
2 changes: 1 addition & 1 deletion src/borg/helpers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
from .process import daemonize, daemonizing, ThreadRunner
from .process import signal_handler, raising_signal_handler, sig_int, ignore_sigint, SigHup, SigTerm
from .process import popen_with_error_handling, is_terminal, prepare_subprocess_env, create_filter_process
from .progress import ProgressIndicatorPercent, ProgressIndicatorMessage
from .progress import ProgressIndicatorPercent, ProgressIndicatorMessage, ProgressIndicatorCounter
from .time import parse_timestamp, timestamp, safe_timestamp, safe_s, safe_ns, MAX_S, SUPPORT_32BIT_PLATFORMS
from .time import format_time, format_timedelta, OutputTimestamp, archive_ts_now
from .yes_no import yes, TRUISH, FALSISH, DEFAULTISH
Expand Down
34 changes: 33 additions & 1 deletion src/borg/helpers/progress.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class ProgressIndicatorBase:
LOGGER = "borg.output.progress"
JSON_TYPE: str = None
JSON_TYPE: str = None # type: ignore[assignment]
Comment thread
ThomasWaldmann marked this conversation as resolved.
Outdated

operation_id_counter = 0

Expand Down Expand Up @@ -41,6 +41,38 @@ def output(self, msg):
self.logger.info(j)


class ProgressIndicatorCounter(ProgressIndicatorBase):
JSON_TYPE = "progress_counter"

def __init__(self, step=1000, msg="%d objects", msgid=None):
Comment thread
ThomasWaldmann marked this conversation as resolved.
Outdated
"""
Activity-based progress indicator, simply tracking a changing count.

:param step: step size
:param msg: output message; must contain one %d placeholder for the count.
"""
self.step = step
self.msg = msg
self.trigger_at = step
super().__init__(msgid=msgid)

def show(self, current=None):
Comment thread
ThomasWaldmann marked this conversation as resolved.
Outdated
"""
Show and output the progress message if the step condition is met.

:param current: Set the current counter value.
"""
if current is not None and current >= self.trigger_at:
Comment on lines +66 to 71
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initialize self.counter = 0 in init method, so you don't need that hasattr.

also, move the code that is not related to producing output to a progress method as you see in the percent pi.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sagar-h007 seen this? ^

# adjust trigger_at to the next step threshold
while self.trigger_at <= current:
self.trigger_at += self.step
return self.output(self.msg % current)

def output(self, message):
j = self.make_json(message=message)
self.logger.info(j)


class ProgressIndicatorPercent(ProgressIndicatorBase):
JSON_TYPE = "progress_percent"

Expand Down
9 changes: 7 additions & 2 deletions src/borg/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -954,8 +954,13 @@ def open(self, path, create=False, lock_wait=None, lock=True, exclusive=False, v
def info(self):
"""actual remoting is done via self.call in the @api decorator"""

@api(since=parse_version("1.0.0"), max_duration={"since": parse_version("1.2.0a4"), "previously": 0})
def check(self, repair=False, max_duration=0):
@api(
since=parse_version("1.0.0"),
max_duration={"since": parse_version("1.2.0a4"), "previously": 0},
# NOTE: update version when next beta is released
progress={"since": parse_version("2.0.0b21"), "dontcare": True},
)
def check(self, repair=False, max_duration=0, progress=False):
"""actual remoting is done via self.call in the @api decorator"""

@api(
Expand Down
14 changes: 11 additions & 3 deletions src/borg/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from .constants import * # NOQA
from .hashindex import ChunkIndex, ChunkIndexEntry
from .helpers import Error, ErrorWithTraceback, IntegrityError
from .helpers import Error, ErrorWithTraceback, IntegrityError, ProgressIndicatorCounter
from .helpers import Location
from .helpers import bin_to_hex, hex_to_bin
from .storelocking import Lock
Expand Down Expand Up @@ -290,7 +290,7 @@ def info(self):
info = dict(id=self.id, version=self.version)
return info

def check(self, repair=False, max_duration=0):
def check(self, repair=False, max_duration=0, progress=False):
"""Check repository consistency"""

def log_error(msg):
Expand All @@ -317,7 +317,7 @@ def check_object(obj):
else:
log_error("too small.")

# TODO: progress indicator, ...
pi = ProgressIndicatorCounter(step=1000, msg="Checked objects: %d", msgid="repository.check")
partial = bool(max_duration)
assert not (repair and partial)
mode = "partial" if partial else "full"
Expand Down Expand Up @@ -364,6 +364,8 @@ def check_object(obj):
obj_corrupted = False
check_object(obj)
objs_checked += 1
if progress:
pi.show(objs_checked)
Comment thread
ThomasWaldmann marked this conversation as resolved.
if obj_corrupted:
objs_errors += 1
if repair:
Expand Down Expand Up @@ -393,10 +395,14 @@ def check_object(obj):
logger.info(f"Checkpointing at key {key}.")
self.store.store(LAST_KEY_CHECKED, key.encode())
if partial and now > t_start + max_duration:
if progress:
pi.finish()
logger.info(f"Finished partial repository check, last key checked is {key}.")
self.store.store(LAST_KEY_CHECKED, key.encode())
break
else:
if progress:
pi.finish()
logger.info("Finished repository check.")
try:
self.store.delete(LAST_KEY_CHECKED)
Expand All @@ -411,6 +417,8 @@ def check_object(obj):
)
except StoreObjectNotFound:
# it can be that there is no "data/" at all, then it crashes when iterating infos.
if progress:
pi.finish()
pass
Comment thread
ThomasWaldmann marked this conversation as resolved.
Outdated
logger.info(f"Checked {objs_checked} repository objects, {objs_errors} errors.")
if objs_errors == 0:
Expand Down