mirror of
https://github.com/tuna/tunasync.git
synced 2025-04-21 04:42:46 +00:00
btrfs snapshot gc
This commit is contained in:
parent
61c408c8e4
commit
8ddac716d5
@ -13,7 +13,7 @@ max_retry = 2
|
||||
[btrfs]
|
||||
service_dir = {mirror_root}/{mirror_name}/_current
|
||||
working_dir = {mirror_root}/{mirror_name}/_working
|
||||
tmp_dir = {mirror_root}/{mirror_name}/_tmp
|
||||
gc_dir = {mirror_root}/{mirror_name}/_gc_{timestamp}
|
||||
|
||||
|
||||
# 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 -*-
|
||||
import sh
|
||||
import os
|
||||
from datetime import datetime
|
||||
from .hook import JobHook
|
||||
|
||||
|
||||
@ -11,10 +12,10 @@ class BtrfsVolumeError(Exception):
|
||||
|
||||
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.working_dir = working_dir
|
||||
self.tmp_dir = tmp_dir
|
||||
self.gc_dir = gc_dir
|
||||
|
||||
def before_job(self):
|
||||
self._create_working_snapshot()
|
||||
@ -44,13 +45,15 @@ class BtrfsHook(JobHook):
|
||||
def _commit_changes(self):
|
||||
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 == ""
|
||||
out = sh.mv(self.working_dir, self.service_dir)
|
||||
assert out.exit_code == 0 and out.stderr == ""
|
||||
# print("btrfs subvolume delete {}".format(self.tmp_dir))
|
||||
sh.sleep(3)
|
||||
out = sh.btrfs("subvolume", "delete", self.tmp_dir)
|
||||
assert out.exit_code == 0 and out.stderr == ""
|
||||
# sh.sleep(3)
|
||||
# out = sh.btrfs("subvolume", "delete", self.tmp_dir)
|
||||
# assert out.exit_code == 0 and out.stderr == ""
|
||||
|
||||
# vim: ts=4 sw=4 sts=4 expandtab
|
||||
|
@ -113,11 +113,11 @@ class MirrorConfig(object):
|
||||
mirror_root=parent.mirror_root,
|
||||
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_name=self.name
|
||||
)
|
||||
hooks.append(BtrfsHook(service_dir, working_dir, tmp_dir))
|
||||
hooks.append(BtrfsHook(service_dir, working_dir, gc_dir))
|
||||
|
||||
return hooks
|
||||
|
||||
@ -152,8 +152,8 @@ class TUNASync(object):
|
||||
"btrfs", "service_dir")
|
||||
self.btrfs_working_dir_tmpl = self._settings.get(
|
||||
"btrfs", "working_dir")
|
||||
self.btrfs_tmp_dir_tmpl = self._settings.get(
|
||||
"btrfs", "tmp_dir")
|
||||
self.btrfs_gc_dir_tmpl = self._settings.get(
|
||||
"btrfs", "gc_dir")
|
||||
|
||||
def hooks(self):
|
||||
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