lockfile 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/rlock +125 -109
- data/bin/rlock-1.3.0 +342 -0
- data/lib/lockfile-1.3.0.rb +518 -0
- data/lib/lockfile.rb +286 -205
- metadata +16 -33
- data/BUGS +0 -3
- data/README +0 -165
- data/VERSION +0 -1
- data/doc/rlock.help +0 -88
- data/install.rb +0 -143
- data/lib/lockfile-1.1.0.rb +0 -437
- data/lockfile-1.1.0.gem +0 -0
- data/lockfile.gemspec +0 -22
- data/samples/a.rb +0 -112
- data/samples/nfsstore.rb +0 -203
- data/samples/test.db +0 -0
- data/samples/test.db~ +0 -0
data/bin/rlock
CHANGED
@@ -1,46 +1,50 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
2
|
#
|
4
|
-
#
|
3
|
+
# built-in
|
5
4
|
#
|
6
|
-
require 'rbconfig'
|
7
|
-
major, minor, teeny = %w(MAJOR MINOR TEENY).map{|k| Config::CONFIG[k].to_i}
|
8
|
-
unless major >= 1 and minor >= 8
|
9
|
-
STDERR.puts "ruby-1.8.0 or greater is required, you are running <ruby-#{ major }.#{ minor }.#{ teeny }>"
|
10
|
-
STDERR.puts "check your PATH setting or install ruby-1.8.0 or greater"
|
11
|
-
exit 1
|
12
|
-
end
|
13
5
|
require 'optparse'
|
14
6
|
require 'logger'
|
15
|
-
require 'yaml'
|
16
|
-
require 'pp'
|
17
|
-
|
18
7
|
#
|
19
|
-
#
|
8
|
+
# http://raa.ruby-lang.org/project/lockfile/
|
20
9
|
#
|
21
|
-
require 'lockfile.rb'
|
10
|
+
require 'lockfile-1.3.0.rb'
|
22
11
|
|
23
12
|
class Main
|
24
|
-
|
25
|
-
VERSION =
|
26
|
-
PROGNAM = File.basename(File.expand_path($0))
|
13
|
+
#--{{{
|
14
|
+
VERSION = Lockfile::VERSION
|
27
15
|
|
28
16
|
USAGE =
|
29
|
-
|
17
|
+
#--{{{
|
30
18
|
<<-usage
|
31
19
|
NAME
|
32
|
-
|
20
|
+
rlock v#{ VERSION }
|
33
21
|
|
34
22
|
SYNOPSIS
|
35
|
-
|
23
|
+
rlock [options]+ lockfile [program [args]+ | -- program options+ [args]+]
|
36
24
|
|
37
25
|
DESCRIPTTION
|
38
|
-
|
26
|
+
rlock creates NFS safe lockfiles. it can optionally run a program while
|
27
|
+
holding the lock, ensuring lockfile removal on program exit. if a program
|
28
|
+
is specified to be run rlock will spawn a background thread to kept the
|
29
|
+
lockfile 'fresh' by touching it at a regular interval. in this way a lease
|
30
|
+
is maintained on the lockfile and other processes attempting to obtain the
|
31
|
+
lock can determine that it is in use. see the '--refresh' option for how to
|
32
|
+
control the touch interval. any other process trying to obtain a lock will
|
33
|
+
automatically remove a stale lockfile; a stale lockfile is one that is older
|
34
|
+
than a certain age. this age be controled via the '--max_age' option.
|
39
35
|
|
40
36
|
ENVIRONMENT
|
41
|
-
LOCKFILE_DEBUG=1
|
37
|
+
LOCKFILE_DEBUG=1
|
38
|
+
causes internal actions of the library to be shown on STDERR
|
42
39
|
|
43
40
|
DIAGNOSTICS
|
41
|
+
rlock attempts to exit with the status of 'program' except where it
|
42
|
+
cannot due to exceptional conditions. in addition the message
|
43
|
+
|
44
|
+
'RLOCK SUBCOMMAND FAILURE'
|
45
|
+
|
46
|
+
will be printed on STDERR if 'program' exits with non-zero status.
|
47
|
+
|
44
48
|
success => $? == 0
|
45
49
|
failure => $? != 0
|
46
50
|
|
@@ -48,68 +52,78 @@
|
|
48
52
|
ara.t.howard@noaa.gov
|
49
53
|
|
50
54
|
BUGS
|
51
|
-
|
55
|
+
1 < bugno && bugno < 42
|
52
56
|
|
53
57
|
OPTIONS
|
54
58
|
usage
|
55
|
-
|
59
|
+
#--}}}
|
56
60
|
|
57
61
|
EXAMPLES =
|
58
|
-
|
62
|
+
#--{{{
|
59
63
|
<<-examples
|
60
64
|
EXAMPLES
|
61
65
|
|
62
|
-
0) simple usage -
|
66
|
+
0) simple usage - create lockfile in an atomic fashion (obtain a lock)
|
63
67
|
|
64
|
-
~ >
|
68
|
+
~ > rlock lockfile
|
65
69
|
|
66
|
-
1) safe usage - create a
|
70
|
+
1) safe usage - create a lockfile, execute a command, and remove lockfile
|
67
71
|
|
68
|
-
~ >
|
72
|
+
~ > rlock lockfile ls lockfile
|
69
73
|
|
70
74
|
2) same as above, but logging verbose messages
|
71
75
|
|
72
|
-
~ >
|
76
|
+
~ > rlock -v4 lockfile ls lockfile
|
73
77
|
|
74
|
-
3) same as above, but logging verbose messages and showing actions internal
|
75
|
-
|
78
|
+
3) same as above, but logging verbose messages and showing actions internal
|
79
|
+
to lockfile library
|
76
80
|
|
77
|
-
~ >
|
81
|
+
~ > rlock -v4 -d lockfile ls lockfile
|
78
82
|
|
79
83
|
4) same as above
|
80
84
|
|
81
|
-
~ > LOCKFILE_DEBUG=1
|
85
|
+
~ > LOCKFILE_DEBUG=1 rlock -v4 lockfile ls lockfile
|
82
86
|
|
83
87
|
5) same as above
|
84
88
|
|
85
89
|
~ > export LOCKFILE_DEBUG=1
|
86
|
-
~ >
|
90
|
+
~ > rlock -v4 lockfile ls lockfile
|
91
|
+
|
92
|
+
6) you need to tell the option parser to stop parsing rlock options if you
|
93
|
+
intend to pass options to 'program'
|
94
|
+
|
95
|
+
~ > rlock -v4 -d lockfile -- ls -ltar lockfile
|
96
|
+
|
97
|
+
without the '--' rlock would consume the '-ltar' option as one of
|
98
|
+
it's own.
|
87
99
|
|
88
|
-
|
89
|
-
|
100
|
+
7) lock lockfile and exec 'program' - remove the lockfile if it is older
|
101
|
+
than 4242 seconds
|
90
102
|
|
91
|
-
~ >
|
103
|
+
~ > rlock --max_age=4242 lockfile program
|
92
104
|
|
93
|
-
|
94
|
-
|
105
|
+
8) lock lockfile and exec 'program' - remove the lockfile if it is older
|
106
|
+
than 4242 seconds, set the refresh rate to be 8 seconds.
|
95
107
|
|
96
|
-
|
97
|
-
than 4242 seconds
|
108
|
+
~ > rlock --max_age=4242 --refresh=8 lockfile program
|
98
109
|
|
99
|
-
|
110
|
+
9) same as above, but fail if lockfile cannot be obtained within 1 minute
|
100
111
|
|
101
|
-
|
102
|
-
than 4242 seconds, also spawn a background thread which will refresh
|
103
|
-
file.lock every 8 seonds will 'program' is executing
|
112
|
+
~ > rlock --max_age=4242 --refresh=8 --timeout=60 lockfile program
|
104
113
|
|
105
|
-
|
114
|
+
10) lockfile creation involves making some temporary files. normally these
|
115
|
+
are cleaned up unless rlock is killed with 'kill -9'. these temp files are
|
116
|
+
normally 'sweeped' - searched for and removed - unless the '--dont_sweep'
|
117
|
+
option is given. note that sweeping can remove ONLY old temp files created
|
118
|
+
by the same host since there is otherwise no way to tell if the offending
|
119
|
+
process is still running.
|
106
120
|
|
107
|
-
|
121
|
+
lock lockfile and run program - do not do any sweeping
|
108
122
|
|
109
|
-
~ >
|
123
|
+
~ > rlock --dont_sweep lockfile program
|
110
124
|
|
111
125
|
examples
|
112
|
-
|
126
|
+
#--}}}
|
113
127
|
|
114
128
|
EXIT_SUCCESS = 0
|
115
129
|
EXIT_FAILURE = 1
|
@@ -119,16 +133,24 @@
|
|
119
133
|
attr :logger
|
120
134
|
attr :config
|
121
135
|
|
122
|
-
def initialize argv =
|
123
|
-
|
124
|
-
@argv = argv
|
136
|
+
def initialize argv = ARGV
|
137
|
+
#--{{{
|
138
|
+
@argv = mcp argv
|
125
139
|
parse_opts
|
140
|
+
if @opt_version
|
141
|
+
puts Main::VERSION
|
142
|
+
exit EXIT_SUCCESS
|
143
|
+
end
|
144
|
+
if @opt_help
|
145
|
+
usage
|
146
|
+
exit EXIT_SUCCESS
|
147
|
+
end
|
126
148
|
parse_argv
|
127
|
-
|
149
|
+
run
|
150
|
+
#--}}}
|
128
151
|
end
|
129
152
|
def run
|
130
|
-
|
131
|
-
usage and exit EXIT_SUCCESS if @opt_help
|
153
|
+
#--{{{
|
132
154
|
init_logging
|
133
155
|
|
134
156
|
debug{ "lockpath <#{ @lockpath }>" }
|
@@ -154,7 +176,7 @@
|
|
154
176
|
case @argv.size
|
155
177
|
when 0
|
156
178
|
opts['dont_clean'] = true
|
157
|
-
logger.debug{ "opts <#{
|
179
|
+
logger.debug{ "opts <#{ opts.inspect }>" }
|
158
180
|
logger.debug{ "aquiring lock <#{ @lockpath }>..." }
|
159
181
|
#
|
160
182
|
# simple usage - just create the lockfile with opts
|
@@ -164,27 +186,35 @@
|
|
164
186
|
|
165
187
|
logger.debug{ "aquired lock <#{ @lockpath }>" }
|
166
188
|
else
|
167
|
-
logger.debug{ "opts <#{
|
189
|
+
logger.debug{ "opts <#{ opts.inspect }>" }
|
168
190
|
logger.debug{ "aquiring lock <#{ @lockpath }>..." }
|
169
191
|
#
|
170
192
|
# block usage - create the lockfile with opts, run block, rm lockfile
|
171
193
|
#
|
194
|
+
status = 1
|
195
|
+
|
172
196
|
lockfile = ::Lockfile.new @lockpath, opts
|
197
|
+
|
173
198
|
lockfile.lock do
|
174
199
|
logger.debug{ "aquired lock <#{ @lockpath }>" }
|
175
|
-
cmd
|
176
|
-
logger.debug{ "cmd <#{ cmd }>" }
|
200
|
+
logger.debug{ "cmd <#{ @argv.join ' ' }>" }
|
177
201
|
v = nil
|
178
202
|
begin
|
179
203
|
v = $VERBOSE
|
180
204
|
$VERBOSE = nil
|
181
|
-
|
205
|
+
STDOUT.flush
|
206
|
+
STDERR.flush
|
207
|
+
fork{ exec(*@argv) }
|
208
|
+
pid, status = Process::wait2
|
182
209
|
ensure
|
183
210
|
$VERBOSE = v
|
184
211
|
end
|
185
212
|
logger.debug{ "status <#{ $? }>" }
|
186
213
|
end
|
187
|
-
|
214
|
+
|
215
|
+
status = status.exitstatus
|
216
|
+
STDERR.puts "RLOCK SUBCOMMAND FAILURE" unless status == 0
|
217
|
+
exit status
|
188
218
|
end
|
189
219
|
rescue => e
|
190
220
|
logger.fatal{ e }
|
@@ -192,44 +222,25 @@
|
|
192
222
|
end
|
193
223
|
|
194
224
|
exit EXIT_SUCCESS
|
195
|
-
|
225
|
+
#--}}}
|
196
226
|
end
|
197
227
|
def parse_opts
|
198
|
-
|
199
|
-
@op = OptionParser
|
228
|
+
#--{{{
|
229
|
+
@op = OptionParser::new
|
200
230
|
@op.banner = ''
|
201
231
|
define_options
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
# preverve unknown options
|
206
|
-
#e.recover(argv)
|
207
|
-
#rescue Exception => e
|
208
|
-
#STDERR.puts PROGNAM
|
209
|
-
#STDERR.puts @op
|
210
|
-
#exit 2
|
211
|
-
#end
|
212
|
-
|
213
|
-
#}}}
|
232
|
+
@op.parse! argv
|
233
|
+
|
234
|
+
#--}}}
|
214
235
|
end
|
215
236
|
def parse_argv
|
216
|
-
|
237
|
+
#--{{{
|
217
238
|
usage and exit EXIT_FAILURE if @argv.empty?
|
218
239
|
@lockpath = @argv.shift
|
219
|
-
|
220
|
-
end
|
221
|
-
def usage io = STDOUT
|
222
|
-
#{{{
|
223
|
-
io << USAGE
|
224
|
-
io << "\n"
|
225
|
-
io << @op
|
226
|
-
io << "\n"
|
227
|
-
io << EXAMPLES if defined? EXAMPLES
|
228
|
-
self
|
229
|
-
#}}}
|
240
|
+
#--}}}
|
230
241
|
end
|
231
242
|
def define_options
|
232
|
-
|
243
|
+
#--{{{
|
233
244
|
options = [
|
234
245
|
['--retries=n','-r', "default(#{ Lockfile.retries.inspect }) - (nil => forever)"],
|
235
246
|
['--max_age=n','-a', "default(#{ Lockfile.max_age.inspect })"],
|
@@ -242,7 +253,9 @@
|
|
242
253
|
['--debug','-d', "default(#{ Lockfile.debug.inspect })"],
|
243
254
|
['--poll_retries=n','-R', "default(#{ Lockfile.poll_retries.inspect })"],
|
244
255
|
['--poll_max_sleep=n','-S', "default(#{ Lockfile.poll_max_sleep.inspect })"],
|
256
|
+
['--dont_sweep','-w', "default(#{ Lockfile.dont_sweep.inspect })"],
|
245
257
|
|
258
|
+
['--version'],
|
246
259
|
['--verbosity=0-4|debug|info|warn|error|fatal','-v'],
|
247
260
|
['--log=path','-l'],
|
248
261
|
['--log_age=log_age'],
|
@@ -254,20 +267,20 @@
|
|
254
267
|
get, set = opt_attr opt
|
255
268
|
@op.def_option(*option){|v| self.send(set, (v or true))}
|
256
269
|
end
|
257
|
-
|
270
|
+
#--}}}
|
258
271
|
end
|
259
272
|
%w(debug info warn error fatal).each do |m|
|
260
273
|
eval "def #{ m }(*args,&block);@logger.#{ m }(*args,&block);end"
|
261
274
|
end
|
262
275
|
def init_logging
|
263
|
-
|
276
|
+
#--{{{
|
264
277
|
if @opt_log_age
|
265
278
|
@opt_log_age = @opt_log_age.to_i if @opt_log_age =~ /\d/
|
266
279
|
end
|
267
280
|
if @opt_log_size
|
268
281
|
@opt_log_size = @opt_log_size.to_i if @opt_log_size =~ /\d/
|
269
282
|
end
|
270
|
-
$logger = @logger = Logger
|
283
|
+
$logger = @logger = Logger::new(@opt_log || STDERR, @opt_log_age, @opt_log_size)
|
271
284
|
|
272
285
|
level = nil
|
273
286
|
@opt_verbosity ||= 'info'
|
@@ -292,11 +305,20 @@
|
|
292
305
|
abort "illegal verbosity setting <#{ @opt_verbosity }>"
|
293
306
|
end
|
294
307
|
@logger.level = 2 - ((@opt_verbosity % 5) - 2)
|
295
|
-
|
296
|
-
|
308
|
+
#--}}}
|
309
|
+
end
|
310
|
+
def usage io = STDOUT
|
311
|
+
#--{{{
|
312
|
+
io << USAGE
|
313
|
+
io << "\n"
|
314
|
+
io << @op
|
315
|
+
io << "\n"
|
316
|
+
io << EXAMPLES if defined? EXAMPLES
|
317
|
+
self
|
318
|
+
#--}}}
|
297
319
|
end
|
298
320
|
def opt_attr opt
|
299
|
-
|
321
|
+
#--{{{
|
300
322
|
get = "opt_#{ opt }"
|
301
323
|
set = "#{ get }="
|
302
324
|
code = <<-code
|
@@ -307,20 +329,14 @@
|
|
307
329
|
code
|
308
330
|
instance_eval code
|
309
331
|
[get, set]
|
310
|
-
|
332
|
+
#--}}}
|
311
333
|
end
|
312
|
-
def
|
313
|
-
|
314
|
-
Marshal
|
315
|
-
|
334
|
+
def mcp obj
|
335
|
+
#--{{{
|
336
|
+
Marshal::load(Marshal::dump(obj))
|
337
|
+
#--}}}
|
316
338
|
end
|
317
|
-
|
318
|
-
#{{{
|
319
|
-
PP::pp obj, ''
|
320
|
-
#}}}
|
321
|
-
end
|
322
|
-
#}}}
|
339
|
+
#--}}}
|
323
340
|
end
|
324
341
|
|
325
|
-
|
326
|
-
Main.new(ARGV).run if $0 == __FILE__
|
342
|
+
Main::new if $0 == __FILE__
|
data/bin/rlock-1.3.0
ADDED
@@ -0,0 +1,342 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# built-in
|
4
|
+
#
|
5
|
+
require 'optparse'
|
6
|
+
require 'logger'
|
7
|
+
#
|
8
|
+
# http://raa.ruby-lang.org/project/lockfile/
|
9
|
+
#
|
10
|
+
require 'lockfile-1.3.0.rb'
|
11
|
+
|
12
|
+
class Main
|
13
|
+
#--{{{
|
14
|
+
VERSION = Lockfile::VERSION
|
15
|
+
|
16
|
+
USAGE =
|
17
|
+
#--{{{
|
18
|
+
<<-usage
|
19
|
+
NAME
|
20
|
+
rlock v#{ VERSION }
|
21
|
+
|
22
|
+
SYNOPSIS
|
23
|
+
rlock [options]+ lockfile [program [args]+ | -- program options+ [args]+]
|
24
|
+
|
25
|
+
DESCRIPTTION
|
26
|
+
rlock creates NFS safe lockfiles. it can optionally run a program while
|
27
|
+
holding the lock, ensuring lockfile removal on program exit. if a program
|
28
|
+
is specified to be run rlock will spawn a background thread to kept the
|
29
|
+
lockfile 'fresh' by touching it at a regular interval. in this way a lease
|
30
|
+
is maintained on the lockfile and other processes attempting to obtain the
|
31
|
+
lock can determine that it is in use. see the '--refresh' option for how to
|
32
|
+
control the touch interval. any other process trying to obtain a lock will
|
33
|
+
automatically remove a stale lockfile; a stale lockfile is one that is older
|
34
|
+
than a certain age. this age be controled via the '--max_age' option.
|
35
|
+
|
36
|
+
ENVIRONMENT
|
37
|
+
LOCKFILE_DEBUG=1
|
38
|
+
causes internal actions of the library to be shown on STDERR
|
39
|
+
|
40
|
+
DIAGNOSTICS
|
41
|
+
rlock attempts to exit with the status of 'program' except where it
|
42
|
+
cannot due to exceptional conditions. in addition the message
|
43
|
+
|
44
|
+
'RLOCK SUBCOMMAND FAILURE'
|
45
|
+
|
46
|
+
will be printed on STDERR if 'program' exits with non-zero status.
|
47
|
+
|
48
|
+
success => $? == 0
|
49
|
+
failure => $? != 0
|
50
|
+
|
51
|
+
AUTHOR
|
52
|
+
ara.t.howard@noaa.gov
|
53
|
+
|
54
|
+
BUGS
|
55
|
+
1 < bugno && bugno < 42
|
56
|
+
|
57
|
+
OPTIONS
|
58
|
+
usage
|
59
|
+
#--}}}
|
60
|
+
|
61
|
+
EXAMPLES =
|
62
|
+
#--{{{
|
63
|
+
<<-examples
|
64
|
+
EXAMPLES
|
65
|
+
|
66
|
+
0) simple usage - create lockfile in an atomic fashion (obtain a lock)
|
67
|
+
|
68
|
+
~ > rlock lockfile
|
69
|
+
|
70
|
+
1) safe usage - create a lockfile, execute a command, and remove lockfile
|
71
|
+
|
72
|
+
~ > rlock lockfile ls lockfile
|
73
|
+
|
74
|
+
2) same as above, but logging verbose messages
|
75
|
+
|
76
|
+
~ > rlock -v4 lockfile ls lockfile
|
77
|
+
|
78
|
+
3) same as above, but logging verbose messages and showing actions internal
|
79
|
+
to lockfile library
|
80
|
+
|
81
|
+
~ > rlock -v4 -d lockfile ls lockfile
|
82
|
+
|
83
|
+
4) same as above
|
84
|
+
|
85
|
+
~ > LOCKFILE_DEBUG=1 rlock -v4 lockfile ls lockfile
|
86
|
+
|
87
|
+
5) same as above
|
88
|
+
|
89
|
+
~ > export LOCKFILE_DEBUG=1
|
90
|
+
~ > rlock -v4 lockfile ls lockfile
|
91
|
+
|
92
|
+
6) you need to tell the option parser to stop parsing rlock options if you
|
93
|
+
intend to pass options to 'program'
|
94
|
+
|
95
|
+
~ > rlock -v4 -d lockfile -- ls -ltar lockfile
|
96
|
+
|
97
|
+
without the '--' rlock would consume the '-ltar' option as one of
|
98
|
+
it's own.
|
99
|
+
|
100
|
+
7) lock lockfile and exec 'program' - remove the lockfile if it is older
|
101
|
+
than 4242 seconds
|
102
|
+
|
103
|
+
~ > rlock --max_age=4242 lockfile program
|
104
|
+
|
105
|
+
8) lock lockfile and exec 'program' - remove the lockfile if it is older
|
106
|
+
than 4242 seconds, set the refresh rate to be 8 seconds.
|
107
|
+
|
108
|
+
~ > rlock --max_age=4242 --refresh=8 lockfile program
|
109
|
+
|
110
|
+
9) same as above, but fail if lockfile cannot be obtained within 1 minute
|
111
|
+
|
112
|
+
~ > rlock --max_age=4242 --refresh=8 --timeout=60 lockfile program
|
113
|
+
|
114
|
+
10) lockfile creation involves making some temporary files. normally these
|
115
|
+
are cleaned up unless rlock is killed with 'kill -9'. these temp files are
|
116
|
+
normally 'sweeped' - searched for and removed - unless the '--dont_sweep'
|
117
|
+
option is given. note that sweeping can remove ONLY old temp files created
|
118
|
+
by the same host since there is otherwise no way to tell if the offending
|
119
|
+
process is still running.
|
120
|
+
|
121
|
+
lock lockfile and run program - do not do any sweeping
|
122
|
+
|
123
|
+
~ > rlock --dont_sweep lockfile program
|
124
|
+
|
125
|
+
examples
|
126
|
+
#--}}}
|
127
|
+
|
128
|
+
EXIT_SUCCESS = 0
|
129
|
+
EXIT_FAILURE = 1
|
130
|
+
|
131
|
+
attr :argv
|
132
|
+
attr :op
|
133
|
+
attr :logger
|
134
|
+
attr :config
|
135
|
+
|
136
|
+
def initialize argv = ARGV
|
137
|
+
#--{{{
|
138
|
+
@argv = mcp argv
|
139
|
+
parse_opts
|
140
|
+
if @opt_version
|
141
|
+
puts Main::VERSION
|
142
|
+
exit EXIT_SUCCESS
|
143
|
+
end
|
144
|
+
if @opt_help
|
145
|
+
usage
|
146
|
+
exit EXIT_SUCCESS
|
147
|
+
end
|
148
|
+
parse_argv
|
149
|
+
run
|
150
|
+
#--}}}
|
151
|
+
end
|
152
|
+
def run
|
153
|
+
#--{{{
|
154
|
+
init_logging
|
155
|
+
|
156
|
+
debug{ "lockpath <#{ @lockpath }>" }
|
157
|
+
|
158
|
+
opts = {}
|
159
|
+
options =
|
160
|
+
%w(retries max_age sleep_inc min_sleep max_sleep suspend timeout refresh poll_retries poll_max_sleep)
|
161
|
+
options.each do |opt|
|
162
|
+
if((val = eval("opt_#{ opt }")))
|
163
|
+
begin
|
164
|
+
opts[opt] = Integer val
|
165
|
+
logger.debug{ "<#{ opt }> <#{ val }>" }
|
166
|
+
rescue
|
167
|
+
logger.fatal{ "illegal value <#{ val.inspect }> for opt <#{ opt }>" }
|
168
|
+
exit EXIT_FAILURE
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
opts['debug'] = true if opt_debug
|
174
|
+
|
175
|
+
begin
|
176
|
+
case @argv.size
|
177
|
+
when 0
|
178
|
+
opts['dont_clean'] = true
|
179
|
+
logger.debug{ "opts <#{ opts.inspect }>" }
|
180
|
+
logger.debug{ "aquiring lock <#{ @lockpath }>..." }
|
181
|
+
#
|
182
|
+
# simple usage - just create the lockfile with opts
|
183
|
+
#
|
184
|
+
lockfile = ::Lockfile.new @lockpath, opts
|
185
|
+
lockfile.lock
|
186
|
+
|
187
|
+
logger.debug{ "aquired lock <#{ @lockpath }>" }
|
188
|
+
else
|
189
|
+
logger.debug{ "opts <#{ opts.inspect }>" }
|
190
|
+
logger.debug{ "aquiring lock <#{ @lockpath }>..." }
|
191
|
+
#
|
192
|
+
# block usage - create the lockfile with opts, run block, rm lockfile
|
193
|
+
#
|
194
|
+
status = 1
|
195
|
+
|
196
|
+
lockfile = ::Lockfile.new @lockpath, opts
|
197
|
+
|
198
|
+
lockfile.lock do
|
199
|
+
logger.debug{ "aquired lock <#{ @lockpath }>" }
|
200
|
+
logger.debug{ "cmd <#{ @argv.join ' ' }>" }
|
201
|
+
v = nil
|
202
|
+
begin
|
203
|
+
v = $VERBOSE
|
204
|
+
$VERBOSE = nil
|
205
|
+
STDOUT.flush
|
206
|
+
STDERR.flush
|
207
|
+
fork{ exec(*@argv) }
|
208
|
+
pid, status = Process::wait2
|
209
|
+
ensure
|
210
|
+
$VERBOSE = v
|
211
|
+
end
|
212
|
+
logger.debug{ "status <#{ $? }>" }
|
213
|
+
end
|
214
|
+
|
215
|
+
status = status.exitstatus
|
216
|
+
STDERR.puts "RLOCK SUBCOMMAND FAILURE" unless status == 0
|
217
|
+
exit status
|
218
|
+
end
|
219
|
+
rescue => e
|
220
|
+
logger.fatal{ e }
|
221
|
+
exit EXIT_FAILURE
|
222
|
+
end
|
223
|
+
|
224
|
+
exit EXIT_SUCCESS
|
225
|
+
#--}}}
|
226
|
+
end
|
227
|
+
def parse_opts
|
228
|
+
#--{{{
|
229
|
+
@op = OptionParser::new
|
230
|
+
@op.banner = ''
|
231
|
+
define_options
|
232
|
+
@op.parse! argv
|
233
|
+
|
234
|
+
#--}}}
|
235
|
+
end
|
236
|
+
def parse_argv
|
237
|
+
#--{{{
|
238
|
+
usage and exit EXIT_FAILURE if @argv.empty?
|
239
|
+
@lockpath = @argv.shift
|
240
|
+
#--}}}
|
241
|
+
end
|
242
|
+
def define_options
|
243
|
+
#--{{{
|
244
|
+
options = [
|
245
|
+
['--retries=n','-r', "default(#{ Lockfile.retries.inspect }) - (nil => forever)"],
|
246
|
+
['--max_age=n','-a', "default(#{ Lockfile.max_age.inspect })"],
|
247
|
+
['--sleep_inc=n','-s', "default(#{ Lockfile.sleep_inc.inspect })"],
|
248
|
+
['--max_sleep=n','-p', "default(#{ Lockfile.max_sleep.inspect })"],
|
249
|
+
['--min_sleep=n','-P', "default(#{ Lockfile.min_sleep.inspect })"],
|
250
|
+
['--suspend=n','-u', "default(#{ Lockfile.suspend.inspect })"],
|
251
|
+
['--timeout=n','-t', "default(#{ Lockfile.timeout.inspect }) - (nil => never)"],
|
252
|
+
['--refresh=n','-f', "default(#{ Lockfile.refresh.inspect })"],
|
253
|
+
['--debug','-d', "default(#{ Lockfile.debug.inspect })"],
|
254
|
+
['--poll_retries=n','-R', "default(#{ Lockfile.poll_retries.inspect })"],
|
255
|
+
['--poll_max_sleep=n','-S', "default(#{ Lockfile.poll_max_sleep.inspect })"],
|
256
|
+
['--dont_sweep','-w', "default(#{ Lockfile.dont_sweep.inspect })"],
|
257
|
+
|
258
|
+
['--version'],
|
259
|
+
['--verbosity=0-4|debug|info|warn|error|fatal','-v'],
|
260
|
+
['--log=path','-l'],
|
261
|
+
['--log_age=log_age'],
|
262
|
+
['--log_size=log_size'],
|
263
|
+
['--help','-h'],
|
264
|
+
]
|
265
|
+
options.each do |option|
|
266
|
+
opt = option.first.gsub(%r/(?:--)|(?:=.*$)/o,'').strip
|
267
|
+
get, set = opt_attr opt
|
268
|
+
@op.def_option(*option){|v| self.send(set, (v or true))}
|
269
|
+
end
|
270
|
+
#--}}}
|
271
|
+
end
|
272
|
+
%w(debug info warn error fatal).each do |m|
|
273
|
+
eval "def #{ m }(*args,&block);@logger.#{ m }(*args,&block);end"
|
274
|
+
end
|
275
|
+
def init_logging
|
276
|
+
#--{{{
|
277
|
+
if @opt_log_age
|
278
|
+
@opt_log_age = @opt_log_age.to_i if @opt_log_age =~ /\d/
|
279
|
+
end
|
280
|
+
if @opt_log_size
|
281
|
+
@opt_log_size = @opt_log_size.to_i if @opt_log_size =~ /\d/
|
282
|
+
end
|
283
|
+
$logger = @logger = Logger::new(@opt_log || STDERR, @opt_log_age, @opt_log_size)
|
284
|
+
|
285
|
+
level = nil
|
286
|
+
@opt_verbosity ||= 'info'
|
287
|
+
@opt_verbosity =
|
288
|
+
case @opt_verbosity
|
289
|
+
when /^\s*(?:4|d|debug)\s*$/io
|
290
|
+
level = 'Logging::DEBUG'
|
291
|
+
4
|
292
|
+
when /^\s*(?:3|i|info)\s*$/io
|
293
|
+
level = 'Logging::INFO'
|
294
|
+
3
|
295
|
+
when /^\s*(?:2|w|warn)\s*$/io
|
296
|
+
level = 'Logging::WARN'
|
297
|
+
2
|
298
|
+
when /^\s*(?:1|e|error)\s*$/io
|
299
|
+
level = 'Logging::ERROR'
|
300
|
+
1
|
301
|
+
when /^\s*(?:0|f|fatal)\s*$/io
|
302
|
+
level = 'Logging::FATAL'
|
303
|
+
0
|
304
|
+
else
|
305
|
+
abort "illegal verbosity setting <#{ @opt_verbosity }>"
|
306
|
+
end
|
307
|
+
@logger.level = 2 - ((@opt_verbosity % 5) - 2)
|
308
|
+
#--}}}
|
309
|
+
end
|
310
|
+
def usage io = STDOUT
|
311
|
+
#--{{{
|
312
|
+
io << USAGE
|
313
|
+
io << "\n"
|
314
|
+
io << @op
|
315
|
+
io << "\n"
|
316
|
+
io << EXAMPLES if defined? EXAMPLES
|
317
|
+
self
|
318
|
+
#--}}}
|
319
|
+
end
|
320
|
+
def opt_attr opt
|
321
|
+
#--{{{
|
322
|
+
get = "opt_#{ opt }"
|
323
|
+
set = "#{ get }="
|
324
|
+
code = <<-code
|
325
|
+
class << self
|
326
|
+
def #{ get }; defined?(@#{ get }) ? @#{ get } : nil; end
|
327
|
+
def #{ set } value; @#{ get } = value; end
|
328
|
+
end
|
329
|
+
code
|
330
|
+
instance_eval code
|
331
|
+
[get, set]
|
332
|
+
#--}}}
|
333
|
+
end
|
334
|
+
def mcp obj
|
335
|
+
#--{{{
|
336
|
+
Marshal::load(Marshal::dump(obj))
|
337
|
+
#--}}}
|
338
|
+
end
|
339
|
+
#--}}}
|
340
|
+
end
|
341
|
+
|
342
|
+
Main::new if $0 == __FILE__
|