forked from third-party-mirrors/zfs_autobackup
exposed --min-change value as a parameter. (was hardcoded at 200000)
This commit is contained in:
parent
e737d0a79f
commit
ee03da2f9b
@ -498,7 +498,6 @@ class ZfsDataset():
|
|||||||
'volume': [ "canmount" ],
|
'volume': [ "canmount" ],
|
||||||
}
|
}
|
||||||
|
|
||||||
ZFS_MAX_UNCHANGED_BYTES=200000
|
|
||||||
|
|
||||||
def __init__(self, zfs_node, name, force_exists=None):
|
def __init__(self, zfs_node, name, force_exists=None):
|
||||||
"""name: full path of the zfs dataset
|
"""name: full path of the zfs dataset
|
||||||
@ -691,12 +690,14 @@ class ZfsDataset():
|
|||||||
return(ret)
|
return(ret)
|
||||||
|
|
||||||
|
|
||||||
def is_changed(self):
|
def is_changed(self, min_changed_bytes=1):
|
||||||
"""dataset is changed since ANY latest snapshot ?"""
|
"""dataset is changed since ANY latest snapshot ?"""
|
||||||
self.debug("Checking if dataset is changed")
|
self.debug("Checking if dataset is changed")
|
||||||
|
|
||||||
#NOTE: filesystems can have a very small amount written without actual changes in some cases
|
if min_changed_bytes==0:
|
||||||
if int(self.properties['written'])<=self.ZFS_MAX_UNCHANGED_BYTES:
|
return(True)
|
||||||
|
|
||||||
|
if int(self.properties['written'])<min_changed_bytes:
|
||||||
return(False)
|
return(False)
|
||||||
else:
|
else:
|
||||||
return(True)
|
return(True)
|
||||||
@ -820,24 +821,35 @@ class ZfsDataset():
|
|||||||
|
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def is_changed_ours(self):
|
def written_since_ours(self):
|
||||||
"""dataset is changed since OUR latest snapshot?"""
|
"""get number of bytes written since our last snapshot"""
|
||||||
|
self.debug("Getting bytes written since our last snapshot")
|
||||||
self.debug("Checking if dataset is changed since our snapshot")
|
|
||||||
|
|
||||||
if not self.our_snapshots:
|
|
||||||
return(True)
|
|
||||||
|
|
||||||
latest_snapshot=self.our_snapshots[-1]
|
latest_snapshot=self.our_snapshots[-1]
|
||||||
|
|
||||||
cmd=[ "zfs", "get","-H" ,"-ovalue", "-p", "written@"+str(latest_snapshot), self.name ]
|
cmd=[ "zfs", "get","-H" ,"-ovalue", "-p", "written@"+str(latest_snapshot), self.name ]
|
||||||
|
|
||||||
output=self.zfs_node.run(readonly=True, tab_split=False, cmd=cmd, valid_exitcodes=[ 0 ])
|
output=self.zfs_node.run(readonly=True, tab_split=False, cmd=cmd, valid_exitcodes=[ 0 ])
|
||||||
|
|
||||||
|
return(int(output[0]))
|
||||||
|
|
||||||
|
|
||||||
|
def is_changed_ours(self, min_changed_bytes=1):
|
||||||
|
"""dataset is changed since OUR latest snapshot?"""
|
||||||
|
|
||||||
|
if min_changed_bytes==0:
|
||||||
|
return(True)
|
||||||
|
|
||||||
|
if not self.our_snapshots:
|
||||||
|
return(True)
|
||||||
|
|
||||||
#NOTE: filesystems can have a very small amount written without actual changes in some cases
|
#NOTE: filesystems can have a very small amount written without actual changes in some cases
|
||||||
if int(output[0])<=self.ZFS_MAX_UNCHANGED_BYTES:
|
if self.written_since_ours<min_changed_bytes:
|
||||||
return(False)
|
return(False)
|
||||||
|
|
||||||
return(True)
|
return(True)
|
||||||
|
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def recursive_datasets(self, types="filesystem,volume"):
|
def recursive_datasets(self, types="filesystem,volume"):
|
||||||
"""get all datasets recursively under us"""
|
"""get all datasets recursively under us"""
|
||||||
@ -1293,20 +1305,18 @@ class ZfsNode(ExecuteNode):
|
|||||||
return(self.backup_name+"-"+time.strftime("%Y%m%d%H%M%S"))
|
return(self.backup_name+"-"+time.strftime("%Y%m%d%H%M%S"))
|
||||||
|
|
||||||
|
|
||||||
def consistent_snapshot(self, datasets, snapshot_name, allow_empty=True):
|
def consistent_snapshot(self, datasets, snapshot_name, min_changed_bytes):
|
||||||
"""create a consistent (atomic) snapshot of specified datasets, per pool.
|
"""create a consistent (atomic) snapshot of specified datasets, per pool.
|
||||||
|
|
||||||
allow_empty: Allow empty snapshots. (compared to our latest snapshot)
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pools={}
|
pools={}
|
||||||
|
|
||||||
#collect snapshots that we want to make, per pool
|
#collect snapshots that we want to make, per pool
|
||||||
for dataset in datasets:
|
for dataset in datasets:
|
||||||
if not allow_empty:
|
if not dataset.is_changed_ours(min_changed_bytes):
|
||||||
if not dataset.is_changed_ours:
|
dataset.verbose("No changes since {}".format(dataset.our_snapshots[-1].snapshot_name))
|
||||||
dataset.verbose("No changes since {}".format(dataset.our_snapshots[-1].snapshot_name))
|
continue
|
||||||
continue
|
|
||||||
|
|
||||||
snapshot=ZfsDataset(dataset.zfs_node, dataset.name+"@"+snapshot_name)
|
snapshot=ZfsDataset(dataset.zfs_node, dataset.name+"@"+snapshot_name)
|
||||||
|
|
||||||
@ -1399,7 +1409,8 @@ class ZfsAutobackup:
|
|||||||
parser.add_argument('--other-snapshots', action='store_true', help='Send over other snapshots as well, not just the ones created by this tool.')
|
parser.add_argument('--other-snapshots', action='store_true', help='Send over other snapshots as well, not just the ones created by this tool.')
|
||||||
parser.add_argument('--no-snapshot', action='store_true', help='Dont create new snapshots (usefull for finishing uncompleted backups, or cleanups)')
|
parser.add_argument('--no-snapshot', action='store_true', help='Dont create new snapshots (usefull for finishing uncompleted backups, or cleanups)')
|
||||||
parser.add_argument('--no-send', action='store_true', help='Dont send snapshots (usefull for cleanups, or if you want a serperate send-cronjob)')
|
parser.add_argument('--no-send', action='store_true', help='Dont send snapshots (usefull for cleanups, or if you want a serperate send-cronjob)')
|
||||||
parser.add_argument('--allow-empty', action='store_true', help='If nothing has changed, still create empty snapshots.')
|
parser.add_argument('--min-change', type=int, default=200000, help='Number of bytes written after which we consider a dataset changed (default %(default)s)')
|
||||||
|
parser.add_argument('--allow-empty', action='store_true', help='If nothing has changed, still create empty snapshots. (same as --min-change=0)')
|
||||||
parser.add_argument('--ignore-replicated', action='store_true', help='Ignore datasets that seem to be replicated some other way. (No changes since lastest snapshot. Usefull for proxmox HA replication)')
|
parser.add_argument('--ignore-replicated', action='store_true', help='Ignore datasets that seem to be replicated some other way. (No changes since lastest snapshot. Usefull for proxmox HA replication)')
|
||||||
parser.add_argument('--no-holds', action='store_true', help='Dont lock snapshots on the source. (Usefull to allow proxmox HA replication to switches nodes)')
|
parser.add_argument('--no-holds', action='store_true', help='Dont lock snapshots on the source. (Usefull to allow proxmox HA replication to switches nodes)')
|
||||||
#not sure if this ever was usefull:
|
#not sure if this ever was usefull:
|
||||||
@ -1437,6 +1448,9 @@ class ZfsAutobackup:
|
|||||||
if self.args.test:
|
if self.args.test:
|
||||||
self.args.verbose=True
|
self.args.verbose=True
|
||||||
|
|
||||||
|
if args.allow_empty:
|
||||||
|
args.min_change=0
|
||||||
|
|
||||||
self.log=Log(show_debug=self.args.debug, show_verbose=self.args.verbose)
|
self.log=Log(show_debug=self.args.debug, show_verbose=self.args.verbose)
|
||||||
|
|
||||||
|
|
||||||
@ -1488,7 +1502,7 @@ class ZfsAutobackup:
|
|||||||
else:
|
else:
|
||||||
self.set_title("Filtering already replicated filesystems")
|
self.set_title("Filtering already replicated filesystems")
|
||||||
for selected_source_dataset in selected_source_datasets:
|
for selected_source_dataset in selected_source_datasets:
|
||||||
if selected_source_dataset.is_changed():
|
if selected_source_dataset.is_changed(self.args.min_change):
|
||||||
source_datasets.append(selected_source_dataset)
|
source_datasets.append(selected_source_dataset)
|
||||||
else:
|
else:
|
||||||
selected_source_dataset.verbose("Ignoring, already replicated")
|
selected_source_dataset.verbose("Ignoring, already replicated")
|
||||||
@ -1496,7 +1510,7 @@ class ZfsAutobackup:
|
|||||||
|
|
||||||
if not self.args.no_snapshot:
|
if not self.args.no_snapshot:
|
||||||
self.set_title("Snapshotting")
|
self.set_title("Snapshotting")
|
||||||
source_node.consistent_snapshot(source_datasets, source_node.new_snapshotname(), allow_empty=self.args.allow_empty)
|
source_node.consistent_snapshot(source_datasets, source_node.new_snapshotname(), min_changed_bytes=self.args.min_change)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user