Skip to content

Commit

Permalink
Speed up backups by increasing buffer size (#4229)
Browse files Browse the repository at this point in the history
* Speed up backups by increasing buffer size

This is the same change as home-assistant/core#90613
but for supervisor

If the backup takes too long, core will release the lock on the database
and the backup will be no good

https://github.com/home-assistant/core/blob/2fc34e7cced87a8e042919e059d3a07bb760c77f/homeassistant/components/recorder/core.py#L926

cpython uses copyfileobj under the hood for fast copies but the default buffer size is quite low which increases the amount of time in python code when copying the sqlite database. As this is the usually the bulk of the backup, increasing the buffer can help reduce the backup time quite a bit.

Ideally this would all use sendfile under the hood as it would shift nearly all the burden out of userspace but tarfile doesn't currently try that https://github.com/python/cpython/blob/4664a7cf689946f0c9854cadee7c6aa9c276a8cf/Lib/shutil.py#L106

related:
In testing (non encrypted) improvement was at least as good as python/cpython#71386

* add the const
  • Loading branch information
bdraco committed Apr 19, 2023
1 parent b3ca08f commit 744cd4e
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 7 deletions.
26 changes: 19 additions & 7 deletions supervisor/backups/backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
from ..utils import remove_folder
from ..utils.dt import parse_datetime, utcnow
from ..utils.json import write_json_file
from .const import BackupType
from .const import BUF_SIZE, BackupType
from .utils import key_to_iv, password_to_key
from .validate import SCHEMA_BACKUP

Expand Down Expand Up @@ -330,7 +330,11 @@ async def _addon_save(addon: Addon):
"""Task to store an add-on into backup."""
tar_name = f"{addon.slug}.tar{'.gz' if self.compressed else ''}"
addon_file = SecureTarFile(
Path(self._tmp.name, tar_name), "w", key=self._key, gzip=self.compressed
Path(self._tmp.name, tar_name),
"w",
key=self._key,
gzip=self.compressed,
bufsize=BUF_SIZE,
)

# Take backup
Expand Down Expand Up @@ -365,7 +369,11 @@ async def _addon_restore(addon_slug: str):
"""Task to restore an add-on into backup."""
tar_name = f"{addon_slug}.tar{'.gz' if self.compressed else ''}"
addon_file = SecureTarFile(
Path(self._tmp.name, tar_name), "r", key=self._key, gzip=self.compressed
Path(self._tmp.name, tar_name),
"r",
key=self._key,
gzip=self.compressed,
bufsize=BUF_SIZE,
)

# If exists inside backup
Expand Down Expand Up @@ -406,7 +414,7 @@ def _folder_save(name: str):
# Take backup
_LOGGER.info("Backing up folder %s", name)
with SecureTarFile(
tar_name, "w", key=self._key, gzip=self.compressed
tar_name, "w", key=self._key, gzip=self.compressed, bufsize=BUF_SIZE
) as tar_file:
atomic_contents_add(
tar_file,
Expand Down Expand Up @@ -453,7 +461,11 @@ def _restore() -> None:
try:
_LOGGER.info("Restore folder %s", name)
with SecureTarFile(
tar_name, "r", key=self._key, gzip=self.compressed
tar_name,
"r",
key=self._key,
gzip=self.compressed,
bufsize=BUF_SIZE,
) as tar_file:
tar_file.extractall(path=origin_dir, members=tar_file)
_LOGGER.info("Restore folder %s done", name)
Expand All @@ -479,7 +491,7 @@ async def store_homeassistant(self):
self._tmp.name, f"homeassistant.tar{'.gz' if self.compressed else ''}"
)
homeassistant_file = SecureTarFile(
tar_name, "w", key=self._key, gzip=self.compressed
tar_name, "w", key=self._key, gzip=self.compressed, bufsize=BUF_SIZE
)

await self.sys_homeassistant.backup(homeassistant_file)
Expand All @@ -496,7 +508,7 @@ async def restore_homeassistant(self) -> Awaitable[None]:
self._tmp.name, f"homeassistant.tar{'.gz' if self.compressed else ''}"
)
homeassistant_file = SecureTarFile(
tar_name, "r", key=self._key, gzip=self.compressed
tar_name, "r", key=self._key, gzip=self.compressed, bufsize=BUF_SIZE
)

await self.sys_homeassistant.restore(homeassistant_file)
Expand Down
2 changes: 2 additions & 0 deletions supervisor/backups/const.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""Backup consts."""
from enum import Enum

BUF_SIZE = 2**20 * 4 # 4MB


class BackupType(str, Enum):
"""Backup type enum."""
Expand Down

0 comments on commit 744cd4e

Please sign in to comment.