mirror of
https://github.com/borgbase/vorta
synced 2024-12-22 07:43:09 +00:00
Add compaction scheduling. By @shivansh02 (#1981)
This commit is contained in:
parent
7ab769e117
commit
449b95e1b6
6 changed files with 167 additions and 1 deletions
|
@ -443,6 +443,116 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="compaction_label">
|
||||
<property name="text">
|
||||
<string>Compaction:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="compactionCheckBox">
|
||||
<property name="text">
|
||||
<string>Compact repository</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frameCompaction">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="layoutCompaction">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_8">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="interval_label">
|
||||
<property name="text">
|
||||
<string>Interval:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_interval">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>4</width>
|
||||
<height>1</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="compactionWeeksCount">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>52</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>3</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="compaction_weeks_label">
|
||||
<property name="text">
|
||||
<string>weeks</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
|
|
|
@ -5,18 +5,21 @@
|
|||
from datetime import timedelta
|
||||
from typing import Dict, NamedTuple, Optional, Tuple, Union
|
||||
|
||||
from packaging import version
|
||||
from PyQt6 import QtCore, QtDBus
|
||||
from PyQt6.QtCore import QTimer
|
||||
from PyQt6.QtWidgets import QApplication
|
||||
|
||||
from vorta import application
|
||||
from vorta.borg.check import BorgCheckJob
|
||||
from vorta.borg.compact import BorgCompactJob
|
||||
from vorta.borg.create import BorgCreateJob
|
||||
from vorta.borg.list_repo import BorgListRepoJob
|
||||
from vorta.borg.prune import BorgPruneJob
|
||||
from vorta.i18n import translate
|
||||
from vorta.notifications import VortaNotifications
|
||||
from vorta.store.models import BackupProfileModel, EventLogModel
|
||||
from vorta.utils import borg_compat
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -489,6 +492,27 @@ def post_backup_tasks(self, profile_id):
|
|||
job = BorgCheckJob(msg['cmd'], msg, profile.repo.id)
|
||||
self.app.jobs_manager.add_job(job)
|
||||
|
||||
compaction_cutoff = dt.now() - timedelta(days=7 * profile.compaction_weeks)
|
||||
recent_compactions = (
|
||||
EventLogModel.select()
|
||||
.where(
|
||||
(EventLogModel.subcommand == '--info')
|
||||
& (EventLogModel.start_time > compaction_cutoff)
|
||||
& (EventLogModel.repo_url == profile.repo.url)
|
||||
)
|
||||
.count()
|
||||
)
|
||||
|
||||
if (
|
||||
profile.compaction_on
|
||||
and recent_compactions == 0
|
||||
and version.parse(borg_compat.version) >= version.parse("1.2")
|
||||
):
|
||||
msg = BorgCompactJob.prepare(profile)
|
||||
if msg['ok']:
|
||||
job = BorgCompactJob(msg['cmd'], msg, profile.repo.id)
|
||||
self.app.jobs_manager.add_job(job)
|
||||
|
||||
logger.info('Finished background task for profile %s', profile.name)
|
||||
notifier.deliver(
|
||||
self.tr('Vorta Backup'),
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
)
|
||||
from .settings import get_misc_settings
|
||||
|
||||
SCHEMA_VERSION = 22
|
||||
SCHEMA_VERSION = 23
|
||||
|
||||
|
||||
@signals.post_save(sender=SettingsModel)
|
||||
|
|
|
@ -250,6 +250,22 @@ def run_migrations(current_schema, db_connection):
|
|||
),
|
||||
)
|
||||
|
||||
if current_schema.version < 23:
|
||||
_apply_schema_update(
|
||||
current_schema,
|
||||
23,
|
||||
migrator.add_column(
|
||||
BackupProfileModel._meta.table_name,
|
||||
'compaction_on',
|
||||
pw.BooleanField(default=True),
|
||||
),
|
||||
migrator.add_column(
|
||||
BackupProfileModel._meta.table_name,
|
||||
'compaction_weeks',
|
||||
pw.IntegerField(default=3),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _apply_schema_update(current_schema, version_after, *operations):
|
||||
with DB.atomic():
|
||||
|
|
|
@ -90,6 +90,8 @@ class BackupProfileModel(BaseModel):
|
|||
schedule_make_up_missed = pw.BooleanField(default=True)
|
||||
validation_on = pw.BooleanField(default=True)
|
||||
validation_weeks = pw.IntegerField(default=3)
|
||||
compaction_on = pw.BooleanField(default=False)
|
||||
compaction_weeks = pw.IntegerField(default=3)
|
||||
prune_on = pw.BooleanField(default=False)
|
||||
prune_hour = pw.IntegerField(default=2)
|
||||
prune_day = pw.IntegerField(default=7)
|
||||
|
|
|
@ -63,10 +63,12 @@ def __init__(self, parent=None):
|
|||
self.framePeriodic.setEnabled(False)
|
||||
self.frameDaily.setEnabled(False)
|
||||
self.frameValidation.setEnabled(False)
|
||||
self.frameCompaction.setEnabled(False)
|
||||
|
||||
self.scheduleIntervalRadio.toggled.connect(self.framePeriodic.setEnabled)
|
||||
self.scheduleFixedRadio.toggled.connect(self.frameDaily.setEnabled)
|
||||
self.validationCheckBox.toggled.connect(self.frameValidation.setEnabled)
|
||||
self.compactionCheckBox.toggled.connect(self.frameCompaction.setEnabled)
|
||||
|
||||
# POPULATE with data
|
||||
self.populate_from_profile()
|
||||
|
@ -105,6 +107,12 @@ def __init__(self, parent=None):
|
|||
self.validationWeeksCount.valueChanged.connect(
|
||||
lambda new_val, attr='validation_weeks': self.save_profile_attr(attr, new_val)
|
||||
)
|
||||
self.compactionCheckBox.stateChanged.connect(
|
||||
lambda new_val, attr='compaction_on': self.save_profile_attr(attr, new_val)
|
||||
)
|
||||
self.compactionWeeksCount.valueChanged.connect(
|
||||
lambda new_val, attr='compaction_weeks': self.save_profile_attr(attr, new_val)
|
||||
)
|
||||
|
||||
# Connect to schedule update
|
||||
self.app.scheduler.schedule_changed.connect(lambda pid: self.draw_next_scheduled_backup())
|
||||
|
@ -154,6 +162,12 @@ def populate_from_profile(self):
|
|||
)
|
||||
self.validationWeeksCount.setValue(profile.validation_weeks)
|
||||
|
||||
# set borg compact options
|
||||
self.compactionCheckBox.setCheckState(
|
||||
QtCore.Qt.CheckState.Checked if profile.compaction_on else QtCore.Qt.CheckState.Unchecked
|
||||
)
|
||||
self.compactionWeeksCount.setValue(profile.compaction_weeks)
|
||||
|
||||
# Other checkbox options
|
||||
self.pruneCheckBox.setCheckState(
|
||||
QtCore.Qt.CheckState.Checked if profile.prune_on else QtCore.Qt.CheckState.Unchecked
|
||||
|
|
Loading…
Reference in a new issue