mirror of
https://github.com/tuna/tunasync.git
synced 2025-06-13 04:17:00 +00:00
btrfs snapshot gc
This commit is contained in:
parent
61c408c8e4
commit
8ddac716d5
@ -13,7 +13,7 @@ max_retry = 2
|
|||||||
[btrfs]
|
[btrfs]
|
||||||
service_dir = {mirror_root}/{mirror_name}/_current
|
service_dir = {mirror_root}/{mirror_name}/_current
|
||||||
working_dir = {mirror_root}/{mirror_name}/_working
|
working_dir = {mirror_root}/{mirror_name}/_working
|
||||||
tmp_dir = {mirror_root}/{mirror_name}/_tmp
|
gc_dir = {mirror_root}/{mirror_name}/_gc_{timestamp}
|
||||||
|
|
||||||
|
|
||||||
# rmirror:archlinux]
|
# rmirror:archlinux]
|
||||||
|
11
systemd/tunasync-snapshot-gc@.service
Normal file
11
systemd/tunasync-snapshot-gc@.service
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Delete garbage subvolumes generated by tunasync
|
||||||
|
Requires = network.target
|
||||||
|
After = network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/home/tuna/.virtualenvs/tunasync/bin/python -u /home/tuna/tunasync/tunasync_snapshot_gc.py %i
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy = multi-user.target
|
9
systemd/tunasync-snapshot-gc@.timer
Normal file
9
systemd/tunasync-snapshot-gc@.timer
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=TUNAsync GC every 10 minutes
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnUnitActiveSec=10min
|
||||||
|
Unit=tunasync-snapshot-gc@%i.service
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
13
systemd/tunasync.service
Normal file
13
systemd/tunasync.service
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[Unit]
|
||||||
|
Description = TUNA mirrors sync daemon
|
||||||
|
Requires = network.target
|
||||||
|
After = network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart = /home/tuna/.virtualenvs/tunasync/bin/python -u /home/tuna/tunasync/tunasync.py -c /etc/tunasync.ini
|
||||||
|
KillSignal = SIGTERM
|
||||||
|
ExecReload = /bin/kill -SIGUSR1 $MAINPID
|
||||||
|
Environment = "HOME=/home/tuna"
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy = multi-user.target
|
@ -2,6 +2,7 @@
|
|||||||
# -*- coding:utf-8 -*-
|
# -*- coding:utf-8 -*-
|
||||||
import sh
|
import sh
|
||||||
import os
|
import os
|
||||||
|
from datetime import datetime
|
||||||
from .hook import JobHook
|
from .hook import JobHook
|
||||||
|
|
||||||
|
|
||||||
@ -11,10 +12,10 @@ class BtrfsVolumeError(Exception):
|
|||||||
|
|
||||||
class BtrfsHook(JobHook):
|
class BtrfsHook(JobHook):
|
||||||
|
|
||||||
def __init__(self, service_dir, working_dir, tmp_dir):
|
def __init__(self, service_dir, working_dir, gc_dir):
|
||||||
self.service_dir = service_dir
|
self.service_dir = service_dir
|
||||||
self.working_dir = working_dir
|
self.working_dir = working_dir
|
||||||
self.tmp_dir = tmp_dir
|
self.gc_dir = gc_dir
|
||||||
|
|
||||||
def before_job(self):
|
def before_job(self):
|
||||||
self._create_working_snapshot()
|
self._create_working_snapshot()
|
||||||
@ -44,13 +45,15 @@ class BtrfsHook(JobHook):
|
|||||||
def _commit_changes(self):
|
def _commit_changes(self):
|
||||||
self._ensure_subvolume()
|
self._ensure_subvolume()
|
||||||
self._ensure_subvolume()
|
self._ensure_subvolume()
|
||||||
out = sh.mv(self.service_dir, self.tmp_dir)
|
gc_dir = self.gc_dir.format(timestamp=datetime.now().strftime("%s"))
|
||||||
|
|
||||||
|
out = sh.mv(self.service_dir, gc_dir)
|
||||||
assert out.exit_code == 0 and out.stderr == ""
|
assert out.exit_code == 0 and out.stderr == ""
|
||||||
out = sh.mv(self.working_dir, self.service_dir)
|
out = sh.mv(self.working_dir, self.service_dir)
|
||||||
assert out.exit_code == 0 and out.stderr == ""
|
assert out.exit_code == 0 and out.stderr == ""
|
||||||
# print("btrfs subvolume delete {}".format(self.tmp_dir))
|
# print("btrfs subvolume delete {}".format(self.tmp_dir))
|
||||||
sh.sleep(3)
|
# sh.sleep(3)
|
||||||
out = sh.btrfs("subvolume", "delete", self.tmp_dir)
|
# out = sh.btrfs("subvolume", "delete", self.tmp_dir)
|
||||||
assert out.exit_code == 0 and out.stderr == ""
|
# assert out.exit_code == 0 and out.stderr == ""
|
||||||
|
|
||||||
# vim: ts=4 sw=4 sts=4 expandtab
|
# vim: ts=4 sw=4 sts=4 expandtab
|
||||||
|
@ -113,11 +113,11 @@ class MirrorConfig(object):
|
|||||||
mirror_root=parent.mirror_root,
|
mirror_root=parent.mirror_root,
|
||||||
mirror_name=self.name
|
mirror_name=self.name
|
||||||
)
|
)
|
||||||
tmp_dir = parent.btrfs_tmp_dir_tmpl.format(
|
gc_dir = parent.btrfs_gc_dir_tmpl.format(
|
||||||
mirror_root=parent.mirror_root,
|
mirror_root=parent.mirror_root,
|
||||||
mirror_name=self.name
|
mirror_name=self.name
|
||||||
)
|
)
|
||||||
hooks.append(BtrfsHook(service_dir, working_dir, tmp_dir))
|
hooks.append(BtrfsHook(service_dir, working_dir, gc_dir))
|
||||||
|
|
||||||
return hooks
|
return hooks
|
||||||
|
|
||||||
@ -152,8 +152,8 @@ class TUNASync(object):
|
|||||||
"btrfs", "service_dir")
|
"btrfs", "service_dir")
|
||||||
self.btrfs_working_dir_tmpl = self._settings.get(
|
self.btrfs_working_dir_tmpl = self._settings.get(
|
||||||
"btrfs", "working_dir")
|
"btrfs", "working_dir")
|
||||||
self.btrfs_tmp_dir_tmpl = self._settings.get(
|
self.btrfs_gc_dir_tmpl = self._settings.get(
|
||||||
"btrfs", "tmp_dir")
|
"btrfs", "gc_dir")
|
||||||
|
|
||||||
def hooks(self):
|
def hooks(self):
|
||||||
return []
|
return []
|
||||||
|
36
tunasync_snapshot_gc.py
Normal file
36
tunasync_snapshot_gc.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
import re
|
||||||
|
import sh
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(prog="tunasync_snapshot_gc")
|
||||||
|
parser.add_argument("--max-level", type=int, default=2, help="max walk level to find garbage snapshots")
|
||||||
|
parser.add_argument("--pattern", default=r"^_gc_\d+", help="pattern to match garbage snapshots")
|
||||||
|
parser.add_argument("mirror_root", help="tunasync mirror root")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
pattern = re.compile(args.pattern)
|
||||||
|
|
||||||
|
def walk(_dir, level=1):
|
||||||
|
if level > 2:
|
||||||
|
return
|
||||||
|
|
||||||
|
for fname in os.listdir(_dir):
|
||||||
|
abs_fname = os.path.join(_dir, fname)
|
||||||
|
if os.path.isdir(abs_fname):
|
||||||
|
if pattern.match(fname):
|
||||||
|
print("GC: {}".format(abs_fname))
|
||||||
|
try:
|
||||||
|
ret = sh.btrfs("subvolume", "delete", abs_fname)
|
||||||
|
except sh.ErrorReturnCode:
|
||||||
|
print("Error: {}".format(ret.stderr))
|
||||||
|
else:
|
||||||
|
walk(abs_fname, level+1)
|
||||||
|
|
||||||
|
walk(args.mirror_root)
|
||||||
|
|
||||||
|
# vim: ts=4 sw=4 sts=4 expandtab
|
Loading…
x
Reference in New Issue
Block a user