1
0
Fork 0
mirror of https://github.com/borgbackup/borg.git synced 2024-12-25 01:06:50 +00:00

rspace: manage reserved space in repository

This commit is contained in:
Thomas Waldmann 2024-09-01 02:07:32 +02:00
parent 1cd2f4dca3
commit b14c050f69
No known key found for this signature in database
GPG key ID: 243ACFA951F78E01
3 changed files with 120 additions and 1 deletions

View file

@ -86,6 +86,7 @@ def get_func(args):
from .rinfo_cmd import RInfoMixIn
from .rdelete_cmd import RDeleteMixIn
from .rlist_cmd import RListMixIn
from .rspace_cmd import RSpaceMixIn
from .serve_cmd import ServeMixIn
from .tar_cmds import TarMixIn
from .transfer_cmd import TransferMixIn
@ -115,6 +116,7 @@ class Archiver(
RDeleteMixIn,
RInfoMixIn,
RListMixIn,
RSpaceMixIn,
ServeMixIn,
TarMixIn,
TransferMixIn,
@ -351,6 +353,7 @@ def build_parser(self):
self.build_parser_rlist(subparsers, common_parser, mid_common_parser)
self.build_parser_recreate(subparsers, common_parser, mid_common_parser)
self.build_parser_rename(subparsers, common_parser, mid_common_parser)
self.build_parser_rspace(subparsers, common_parser, mid_common_parser)
self.build_parser_serve(subparsers, common_parser, mid_common_parser)
self.build_parser_tar(subparsers, common_parser, mid_common_parser)
self.build_parser_transfer(subparsers, common_parser, mid_common_parser)

View file

@ -48,8 +48,14 @@ def do_rcreate(self, args, repository, *, other_repository=None, other_manifest=
" borg key export -r REPOSITORY encrypted-key-backup\n"
" borg key export -r REPOSITORY --paper encrypted-key-backup.txt\n"
" borg key export -r REPOSITORY --qr-html encrypted-key-backup.html\n"
"2. Write down the borg key passphrase and store it at safe place.\n"
"2. Write down the borg key passphrase and store it at safe place."
)
logger.warning(
"\n"
"Reserve some repository storage space now for emergencies like 'disk full'\n"
"by running:\n"
" borg rspace --reserve 1G"
)
def build_parser_rcreate(self, subparsers, common_parser, mid_common_parser):
from ._common import process_epilog

View file

@ -0,0 +1,110 @@
import argparse
import math
import os
from ._common import with_repository, Highlander
from ..constants import * # NOQA
from ..helpers import parse_file_size, format_file_size
from ..logger import create_logger
logger = create_logger()
class RSpaceMixIn:
@with_repository(lock=False, manifest=False)
def do_rspace(self, args, repository):
"""Manage reserved space in repository"""
# we work without locking here because locks don't work with full disk.
if args.reserve_space > 0:
storage_space_reserve_object_size = 64 * 2**20 # 64 MiB per object
count = math.ceil(float(args.reserve_space) / storage_space_reserve_object_size) # round up
size = 0
for i in range(count):
data = os.urandom(storage_space_reserve_object_size) # counter-act fs compression/dedup
repository.store_store(f"config/space-reserve.{i}", data)
size += len(data)
print(f"There is {format_file_size(size, iec=False)} reserved space in this repository now.")
elif args.free_space:
infos = repository.store_list("config")
size = 0
for info in infos:
if info.name.startswith("space-reserve."):
size += info.size
repository.store_delete(f"config/{info.name}")
print(f"Freed {format_file_size(size, iec=False)} in repository.")
print("Now run borg prune or borg delete plus borg compact to free more space.")
print("After that, do not forget to reserve space again for next time!")
else: # print amount currently reserved
infos = repository.store_list("config")
size = 0
for info in infos:
if info.name.startswith("space-reserve."):
size += info.size
print(f"There is {format_file_size(size, iec=False)} reserved space in this repository.")
print("In case you want to change the amount, use --free first to free all reserved space,")
print("then use --reserve with the desired amount.")
def build_parser_rspace(self, subparsers, common_parser, mid_common_parser):
from ._common import process_epilog
rspace_epilog = process_epilog(
"""
This command manages reserved space in a repository.
Borg can not work in disk-full conditions (can not lock a repo and thus can
not run prune/delete or compact operations to free disk space).
To avoid running into dead-end situations like that, you can put some objects
into a repository that take up some disk space. If you ever run into a
disk-full situation, you can free that space and then borg will be able to
run normally, so you can free more disk space by using prune/delete/compact.
After that, don't forget to reserve space again, in case you run into that
situation again at a later time.
Examples::
# Create a new repository:
$ borg rcreate ...
# Reserve approx. 1GB of space for emergencies:
$ borg rspace --reserve 1G
# Check amount of reserved space in the repository:
$ borg rspace
# EMERGENCY! Free all reserved space to get things back to normal:
$ borg rspace --free
$ borg prune ...
$ borg delete ...
$ borg compact -v # only this actually frees space of deleted archives
$ borg rspace --reserve 1G # reserve space again for next time
Reserved space is always rounded up to use full reservation blocks of 64MiB.
"""
)
subparser = subparsers.add_parser(
"rspace",
parents=[common_parser],
add_help=False,
description=self.do_rspace.__doc__,
epilog=rspace_epilog,
formatter_class=argparse.RawDescriptionHelpFormatter,
help="manage reserved space in a repository",
)
subparser.set_defaults(func=self.do_rspace)
subparser.add_argument(
"--reserve",
metavar="SPACE",
dest="reserve_space",
default=0,
type=parse_file_size,
action=Highlander,
help="Amount of space to reserve (e.g. 100M, 1G). Default: 0.",
)
subparser.add_argument(
"--free",
dest="free_space",
action="store_true",
help="Free all reserved space. Don't forget to reserve space later again.",
)