[pve-devel] [PATCH pve-zsync] Allow detecting a syncing instance of a job

Thomas Lamprecht t.lamprecht at proxmox.com
Mon Sep 30 16:38:05 CEST 2019


On 9/30/19 12:55 PM, Fabian Ebner wrote:
> Before, the check whether a syncing instance of the same job is already present
> was inside the locked section. This caused cron to continuously spawn new
> instances of pve-zsync on syncs (or rather groups of syncs) taking longer
> than 15 minutes, see [0] in the forum. This patch introduces a new locked
> section for checking the current status and a new 'waiting' status.
> The 'waiting' status is needed to mark jobs which are currently waiting
> for the lock for syncing. So if job A is syncing and job B is waiting for
> the lock then all new instances of job B will see that one instance is
> already scheduled to sync.
> 
> [0]: https://forum.proxmox.com/threads/pve-zsync-bug-spawns-endless-cron-processes.58087/
> 
> Signed-off-by: Fabian Ebner <f.ebner at proxmox.com>
> ---
>  pve-zsync | 25 ++++++++++++++++++++-----
>  1 file changed, 20 insertions(+), 5 deletions(-)
> 

Looks OK, a small style nit and proposal for eventual refactoring in-line

> diff --git a/pve-zsync b/pve-zsync
> index 425ffa2..90c1bb3 100755
> --- a/pve-zsync
> +++ b/pve-zsync
> @@ -19,6 +19,7 @@ my $PVE_DIR = "/etc/pve/local";
>  my $QEMU_CONF = "${PVE_DIR}/qemu-server";
>  my $LXC_CONF = "${PVE_DIR}/lxc";
>  my $LOCKFILE = "$CONFIG_PATH/${PROGNAME}.lock";
> +my $LOCKFILE_STATUS_CHECK = "$CONFIG_PATH/${PROGNAME}_status_check.lock";
>  my $PROG_PATH = "$PATH/${PROGNAME}";
>  my $INTERVAL = 15;
>  my $DEBUG;
> @@ -578,20 +579,34 @@ sub destroy_job {
>  sub sync {
>      my ($param) = @_;
>  
> +    my $lock_status_check_fh = IO::File->new("> $LOCKFILE_STATUS_CHECK");
> +    die "Can't open Lock File: $LOCKFILE_STATUS_CHECK $!\n" if !$lock_status_check_fh;
> +    lock($lock_status_check_fh);

Above pattern is repeated quite a few times in this file, maybe we could replace it
by something like:

sub locked {
    my ($lock_fn, $code) = @_;

    my $lock_fh = File...
 
    flock($lock_fh, LOCK_EX) || die ...;
    my $res = eval { $code->() };
    my $err = $@;

    flock($fh, LOCK_UN) || warn ...; # always unlock
    die "$err" if $err;

    close($lock_fh); # or maybe cache this one and keep around? not sure though
    return $res;
}


Then we'd have explicit locked segments where we know for sure that unlocking
is always done. But as said, that's some refactoring that could be great nothing
important.

> +
> +    my $job;
> +    eval {
> +	$job = get_job($param);
> +    };

Above could be also written as one-liner without losing expressiveness:
my $job = eval { get_job($param) };

This uses the fact that eval (and most blocks in general) in perl implicitly
return the result of the last statement, if no explicit return is (in all
branches). I know you just used a pattern already existent in this file,
but such a "cleanup" could be OK to even to then, IMO.

Not sure, depending if you want to refactor a bit here you could send a v2
else I could apply this and just fixup those "eval assignment" places here,
whatever you prefer.

> +
> +    if ($job && defined($job->{state}) && ($job->{state} eq "syncing" || $job->{state} eq "waiting")) {
> +	unlock($lock_status_check_fh);
> +	die "Job --source $param->{source} --name $param->{name} is already scheduled to sync\n";
> +    }
> +
> +    $job->{state} = "waiting";
> +    update_state($job);
> +    unlock($lock_status_check_fh);
> +
>      my $lock_fh = IO::File->new("> $LOCKFILE");
>      die "Can't open Lock File: $LOCKFILE $!\n" if !$lock_fh;
>      lock($lock_fh);
>  
> +    #job might've changed while we waited for the lock, but we can be sure it's not syncing
>      my $date = get_date();
> -    my $job;
>      eval {
>  	$job = get_job($param);
>      };
>  
> -    if ($job && defined($job->{state}) && $job->{state} eq "syncing") {
> -	die "Job --source $param->{source} --name $param->{name} is syncing at the moment";
> -    }
> -
>      my $dest = parse_target($param->{dest});
>      my $source = parse_target($param->{source});
>  
> 





More information about the pve-devel mailing list