File Coverage

lockapi.pm
Criterion Covered Total %
statement 144 160 93.7
total 144 160 93.7


line stmt code
1   # Copyright 2015-2021 SUSE LLC
2   # SPDX-License-Identifier: GPL-2.0-or-later
3    
4   ## synchronization API
5    
6   use Mojo::Base 'Exporter', -signatures;
7 1 use Scalar::Util 'looks_like_number';
  1  
  1  
8 1 use Time::Seconds;
  1  
  1  
9 1 our @EXPORT = qw(mutex_create mutex_lock mutex_unlock mutex_try_lock mutex_wait
  1  
  1  
10   barrier_create barrier_wait barrier_try_wait barrier_destroy);
11    
12   require bmwqemu;
13   use mmapi qw(api_call_2 get_job_info);
14 1 use testapi ();
  1  
  1  
15 1  
  1  
  1  
16   use constant RETRY_COUNT => $ENV{OS_AUTOINST_LOCKAPI_RETRY_COUNT} // 7;
17 1 use constant RETRY_INTERVAL => $ENV{OS_AUTOINST_LOCKAPI_RETRY_INTERVAL} // 10;
  1  
  1  
18 1 use constant POLL_INTERVAL => $ENV{OS_AUTOINST_LOCKAPI_POLL_INTERVAL} // 5;
  1  
  1  
19 1  
  1  
  1  
20   my $log_ctx = "acquiring $type '$name'";
21 12 my %expected_return_codes = (200 => 1, 409 => 1, 410 => 1);
  12  
  12  
  12  
  12  
22 12 my $actual_return_code;
23 12 for (1 .. RETRY_COUNT) {
24 12 my $tx = api_call_2(post => "$type/$name", $param, \%expected_return_codes);
25 12 $actual_return_code = $tx->res->code;
26 12 last unless mmapi::handle_api_error($tx, $log_ctx, \%expected_return_codes);
27 12 last unless ($actual_return_code // 0) == 410;
28 12 bmwqemu::fctinfo("Retry $_ of " . RETRY_COUNT); # uncoverable statement
29 4 sleep RETRY_INTERVAL; # uncoverable statement
30 0 }
31 0 if ($actual_return_code) {
32   return 1 if $actual_return_code == 200;
33 12 bmwqemu::mydie "$log_ctx: lock owner already finished" if $actual_return_code == 410;
34 10 }
35 5 return 0;
36   }
37 6  
38   my $param = {action => 'lock'};
39   $param->{where} = $where if $where;
40 6 return _try_lock('mutex', $name, $param);
  6  
  6  
  6  
41 6 }
42 6  
43 6 # Log info about event and it's location
44   # Generate log message
45   my $job = $args{where} ? ((get_job_info($args{where}) // {})->{settings}->{TEST} // '?') . " #$args{where}" : 'parent job';
46   my $msg = "Wait for $name (on $job)";
47 4 $msg .= " - $args{info}" if $args{info};
  4  
  4  
  4  
48   my $subject = 'Paused';
49 4 if (defined $args{amend}) {
50 4 # amend log info with wait duration
51 4 $autotest::current_test->remove_last_result;
52 4 $subject .= ' ' . int($args{amend} / ONE_MINUTE) . 'm' . $args{amend} % ONE_MINUTE . 's';
53 4 }
54   testapi::record_info $subject, $msg;
55 2 }
56 2  
57   bmwqemu::diag($log_ctx);
58 4 my $tx = api_call_2($method, $action, $params, $expected_codes);
59   return 0 if mmapi::handle_api_error($tx, $log_ctx, $expected_codes);
60   return $tx->res->code == 200 ? 1 : 0;
61 11 }
  11  
  11  
  11  
  11  
  11  
  11  
62 11  
63 11 bmwqemu::mydie('missing lock name') unless $name;
64 11 bmwqemu::diag("mutex lock '$name'");
65 5 while (1) {
66   my $res = _lock_action($name, $where);
67   return 1 if $res;
68 2 bmwqemu::diag("mutex lock '$name' unavailable, sleeping " . POLL_INTERVAL . ' seconds'); # uncoverable statement
  2  
  2  
  2  
69 2 sleep POLL_INTERVAL; # uncoverable statement
70 1 }
71 1 }
72 1  
73 1 bmwqemu::mydie('missing lock name') unless $name;
74 0 bmwqemu::diag("mutex try lock '$name'");
75 0 return _lock_action($name, $where);
76   }
77    
78   bmwqemu::mydie('missing lock name') unless $name;
79 6 my $param = {action => 'unlock'};
  6  
  6  
  6  
80 6 $param->{where} = $where if $where;
81 5 return _api_call_with_logging_and_error_handling("mutex unlock '$name'", post => "mutex/$name", $param);
82 5 }
83    
84   bmwqemu::mydie('missing lock name') unless $name;
85 4 return _api_call_with_logging_and_error_handling("mutex create '$name'", post => "mutex", {name => $name});
  4  
  4  
  4  
86 4 }
87 3  
88 3 # Wrapper for mutex_lock & mutex_unlock
89 3 _log $name, where => $where, info => $info;
90   my $start = time;
91   mutex_lock $name, $where;
92 4 mutex_unlock $name, $where;
  4  
  4  
93 4 _log $name, where => $where, info => $info, amend => time - $start;
94 3 }
95    
96   ## Barriers
97   bmwqemu::mydie('missing barrier name') unless $name;
98 0 bmwqemu::mydie('missing number of barrier task') unless $tasks;
  0  
  0  
  0  
  0  
99 0 return _api_call_with_logging_and_error_handling("barrier create '$name' for $tasks tasks", post => 'barrier', {name => $name, tasks => $tasks});
100 0 }
101 0  
102 0 my $param;
103 0 $param->{where} = $where if $where;
104   $param->{check_dead_job} = $check_dead_job if defined $check_dead_job;
105    
106   return _try_lock('barrier', $name, $param);
107 5 }
  5  
  5  
  5  
108 5  
109 4 # Reason to include this is to be able to unit test _wait_action without blocking
110 3 bmwqemu::mydie('missing barrier name') unless $name;
111   bmwqemu::diag("barrier try wait '$name'");
112   return _wait_action($name, $where);
113 6 }
  6  
  6  
  6  
  6  
114 6  
115 6 my ($name, $where, $check_dead_job) = ref $args[0] eq 'HASH' ? (@{$args[0]}{qw(name where check_dead_job)}) : @args;
116 6 $check_dead_job = looks_like_number($check_dead_job) && $check_dead_job ? 1 : 0;
117    
118 6 bmwqemu::mydie('missing barrier name') unless $name;
119   bmwqemu::diag("barrier wait '$name'");
120    
121   _log $name, where => $where;
122 4 my $start = time;
  4  
  4  
  4  
123 4 while (1) {
124 4 my $res = _wait_action($name, $where, $check_dead_job);
125 4 if ($res) {
126   _log $name, where => $where, amend => time - $start;
127   return 1;
128 3 }
  3  
  3  
129 3  
  1  
130 3 bmwqemu::diag("barrier '$name' not released, sleeping " . POLL_INTERVAL . ' seconds'); # uncoverable statement
131   sleep POLL_INTERVAL; # uncoverable statement
132 3 }
133 2 }
134    
135 2 bmwqemu::mydie('missing barrier name') unless $name;
136 2 return _api_call_with_logging_and_error_handling("barrier destroy '$name'",
137 2 delete => "barrier/$name", $where ? {where => $where} : undef, {200 => 1});
138 2 }
139 2  
140 2 1;