소스 검색

btrfs snapshot gc

bigeagle 11 년 전
부모
커밋
8ddac716d5
7개의 변경된 파일83개의 추가작업 그리고 11개의 파일을 삭제
  1. 1 1
      examples/tunasync.ini
  2. 11 0
      systemd/tunasync-snapshot-gc@.service
  3. 9 0
      systemd/tunasync-snapshot-gc@.timer
  4. 13 0
      systemd/tunasync.service
  5. 9 6
      tunasync/btrfs_snapshot.py
  6. 4 4
      tunasync/tunasync.py
  7. 36 0
      tunasync_snapshot_gc.py

+ 1 - 1
examples/tunasync.ini

@@ -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 - 0
systemd/tunasync-snapshot-gc@.service

@@ -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 - 0
systemd/tunasync-snapshot-gc@.timer

@@ -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 - 0
systemd/tunasync.service

@@ -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

+ 9 - 6
tunasync/btrfs_snapshot.py

@@ -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

+ 4 - 4
tunasync/tunasync.py

@@ -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 - 0
tunasync_snapshot_gc.py

@@ -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