lockfile 1.4.3 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ODM0M2E0ODAyNDY5MzJhZDJhNjU1ZDc5MmMzM2JkN2I4MTA4YjMwNw==
5
+ data.tar.gz: !binary |-
6
+ NThjOTI1M2JjNzYyMjQ4YWIxOGQ4OGNmZWE0NGI0YTI1M2FlMWVlNg==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ MDU2ZGQwMzA0ZWUwMWNjY2Q4MjFiMmNhY2MxNDIwODIyMmRiOGJlZDQ1N2Fk
10
+ YTJlZWUwMTg2ZTc5OWQ3YjgwYzY5OTFmYWFiZjQwYTFkYjk5OWVjY2I2OTFk
11
+ N2M0MzRmYTY3OTlhOTQyYWNiYTUzNjY1ZGRmZGJjMmEyMTE3NDk=
12
+ data.tar.gz: !binary |-
13
+ NzAyNjFjYzk3YjgzZmE3M2YyNjZmNjhkZTliZTdhMmFjNDFlNDdhZmIwNzIw
14
+ OTM2NWI3ZWNhNzI3ZmIzOTU4NGIzNjcyOTUwNmMyNWFhNThiNTAzMTIyYTY1
15
+ ZmRhYTViMzc0Zjc3MTA1ZmYwMzBlYmFlYjlkNTA3ZTY0OGI1NjE=
data/README CHANGED
@@ -5,7 +5,7 @@ URLS
5
5
 
6
6
  SYNOPSIS
7
7
 
8
- lib/lockfile.rb : a ruby library for creating NFS safe lockfiles
8
+ lib/lockfile.rb : a ruby library for creating perfect and NFS safe lockfiles
9
9
 
10
10
  bin/rlock : ruby command line tool which uses this library to create lockfiles
11
11
  and to run arbitrary commands while holding them.
@@ -158,6 +158,8 @@ BUGS
158
158
  bugno > 1 && bugno < 42
159
159
 
160
160
  HISTORY
161
+ 2.0.0:
162
+ - lock fires up a refresher thread when called without a block
161
163
 
162
164
  1.4.3:
163
165
  - fixed a small non-critical bug in the require gaurd
data/bin/rlock CHANGED
@@ -7,7 +7,7 @@
7
7
  #
8
8
  # http://raa.ruby-lang.org/project/lockfile/
9
9
  #
10
- require 'lockfile-1.4.3'
10
+ require 'lockfile'
11
11
 
12
12
  class Main
13
13
  #--{{{
@@ -49,7 +49,7 @@
49
49
  failure => $? != 0
50
50
 
51
51
  AUTHOR
52
- ara.t.howard@noaa.gov
52
+ ara.t.howard@gmail.com
53
53
 
54
54
  BUGS
55
55
  1 < bugno && bugno < 42
@@ -5,9 +5,14 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
5
5
  require 'fileutils'
6
6
 
7
7
  class Lockfile
8
- #--{{{
9
- VERSION = '1.4.3'
10
- def version() VERSION end
8
+
9
+ VERSION = '2.0.1'
10
+ def Lockfile.version() Lockfile::VERSION end
11
+ def version() Lockfile::VERSION end
12
+
13
+ def Lockfile.description
14
+ 'a ruby library for creating perfect and NFS safe lockfiles'
15
+ end
11
16
 
12
17
  class LockError < StandardError; end
13
18
  class StolenLockError < LockError; end
@@ -19,13 +24,12 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
19
24
  class UnLockError < LockError; end
20
25
 
21
26
  class SleepCycle < Array
22
- #--{{{
23
27
  attr :min
24
28
  attr :max
25
29
  attr :range
26
30
  attr :inc
27
- def initialize min, max, inc
28
- #--{{{
31
+
32
+ def initialize(min, max, inc)
29
33
  @min, @max, @inc = Float(min), Float(max), Float(inc)
30
34
  @range = @max - @min
31
35
  raise RangeError, "max(#{ @max }) <= min(#{ @min })" if @max <= @min
@@ -36,24 +40,20 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
36
40
  push(s) and s += @inc while(s <= @max)
37
41
  self[-1] = @max if self[-1] < @max
38
42
  reset
39
- #--}}}
40
43
  end
44
+
41
45
  def next
42
- #--{{{
43
46
  ret = self[@idx]
44
47
  @idx = ((@idx + 1) % self.size)
45
48
  ret
46
- #--}}}
47
49
  end
50
+
48
51
  def reset
49
- #--{{{
50
52
  @idx = 0
51
- #--}}}
52
53
  end
53
- #--}}}
54
54
  end
55
55
 
56
- HOSTNAME = Socket::gethostname
56
+ HOSTNAME = Socket.gethostname
57
57
 
58
58
  DEFAULT_RETRIES = nil # maximum number of attempts
59
59
  DEFAULT_TIMEOUT = nil # the longest we will try
@@ -71,8 +71,7 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
71
71
 
72
72
  DEFAULT_DEBUG = ENV['LOCKFILE_DEBUG'] || false
73
73
 
74
- class << self
75
- #--{{{
74
+ class << Lockfile
76
75
  attr :retries, true
77
76
  attr :max_age, true
78
77
  attr :sleep_inc, true
@@ -89,7 +88,6 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
89
88
  attr :dont_use_lock_id, true
90
89
 
91
90
  def init
92
- #--{{{
93
91
  @retries = DEFAULT_RETRIES
94
92
  @max_age = DEFAULT_MAX_AGE
95
93
  @sleep_inc = DEFAULT_SLEEP_INC
@@ -108,17 +106,17 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
108
106
 
109
107
  STDOUT.sync = true if @debug
110
108
  STDERR.sync = true if @debug
111
- #--}}}
112
109
  end
113
- #--}}}
114
110
  end
115
- self.init
111
+
112
+ Lockfile.init
116
113
 
117
114
  attr :klass
118
115
  attr :path
119
116
  attr :opts
120
117
  attr :locked
121
118
  attr :thief
119
+ attr :refresher
122
120
  attr :dirname
123
121
  attr :basename
124
122
  attr :clean
@@ -136,14 +134,13 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
136
134
  attr :dont_sweep
137
135
  attr :dont_use_lock_id
138
136
 
139
- attr :debug, true
137
+ attr_accessor :debug
140
138
 
141
139
  alias thief? thief
142
140
  alias locked? locked
143
141
  alias debug? debug
144
142
 
145
- def self::create(path, *a, &b)
146
- #--{{{
143
+ def Lockfile.create(path, *a, &b)
147
144
  opts = {
148
145
  'retries' => 0,
149
146
  'min_sleep' => 0,
@@ -164,11 +161,9 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
164
161
  raise Errno::EEXIST, path
165
162
  end
166
163
  open(path, *a, &b)
167
- #--}}}
168
164
  end
169
165
 
170
166
  def initialize(path, opts = {}, &block)
171
- #--{{{
172
167
  @klass = self.class
173
168
  @path = path
174
169
  @opts = opts
@@ -188,19 +183,19 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
188
183
  @dont_use_lock_id = getopt 'dont_use_lock_id' , @klass.dont_use_lock_id
189
184
  @debug = getopt 'debug' , @klass.debug
190
185
 
191
- @sleep_cycle = SleepCycle::new @min_sleep, @max_sleep, @sleep_inc
186
+ @sleep_cycle = SleepCycle.new @min_sleep, @max_sleep, @sleep_inc
192
187
 
193
- @clean = @dont_clean ? nil : lambda{ File::unlink @path rescue nil }
194
- @dirname = File::dirname @path
195
- @basename = File::basename @path
188
+ @clean = @dont_clean ? nil : lambda{ File.unlink @path rescue nil }
189
+ @dirname = File.dirname @path
190
+ @basename = File.basename @path
196
191
  @thief = false
197
192
  @locked = false
193
+ @refrsher = nil
198
194
 
199
195
  lock(&block) if block
200
- #--}}}
201
196
  end
197
+
202
198
  def lock
203
- #--{{{
204
199
  raise StackingLockError, "<#{ @path }> is locked!" if @locked
205
200
 
206
201
  sweep unless @dont_sweep
@@ -212,7 +207,7 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
212
207
  @sleep_cycle.reset
213
208
  create_tmplock do |f|
214
209
  begin
215
- Timeout::timeout(@timeout) do
210
+ Timeout.timeout(@timeout) do
216
211
  tmp_path = f.path
217
212
  tmp_stat = f.lstat
218
213
  n_retries = 0
@@ -222,25 +217,25 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
222
217
  begin
223
218
  trace{ "polling attempt <#{ i }>..." }
224
219
  begin
225
- File::link tmp_path, @path
220
+ File.link tmp_path, @path
226
221
  rescue Errno::ENOENT
227
222
  try_again!
228
223
  end
229
- lock_stat = File::lstat @path
224
+ lock_stat = File.lstat @path
230
225
  raise StatLockError, "stat's do not agree" unless
231
226
  tmp_stat.rdev == lock_stat.rdev and tmp_stat.ino == lock_stat.ino
232
227
  trace{ "aquired lock <#{ @path }>" }
233
228
  @locked = true
234
- rescue => e
235
- i += 1
236
- unless i >= @poll_retries
237
- t = [rand(@poll_max_sleep), @poll_max_sleep].min
238
- trace{ "poll sleep <#{ t }>..." }
239
- sleep t
240
- retry
229
+ rescue => e
230
+ i += 1
231
+ unless i >= @poll_retries
232
+ t = [rand(@poll_max_sleep), @poll_max_sleep].min
233
+ trace{ "poll sleep <#{ t }>..." }
234
+ sleep t
235
+ retry
236
+ end
237
+ raise
241
238
  end
242
- raise
243
- end
244
239
 
245
240
  rescue => e
246
241
  n_retries += 1
@@ -256,7 +251,7 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
256
251
  when false
257
252
  trace{ "found invalid lock and removing" }
258
253
  begin
259
- File::unlink @path
254
+ File.unlink @path
260
255
  @thief = true
261
256
  warn "<#{ @path }> stolen by <#{ Process.pid }> at <#{ timestamp }>"
262
257
  trace{ "i am a thief!" }
@@ -278,7 +273,7 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
278
273
 
279
274
  if block_given?
280
275
  stolen = false
281
- refresher = (@refresh ? new_refresher : nil)
276
+ @refresher = (@refresh ? new_refresher : nil)
282
277
  begin
283
278
  begin
284
279
  ret = yield @path
@@ -288,12 +283,14 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
288
283
  end
289
284
  ensure
290
285
  begin
291
- refresher.kill if refresher and refresher.status
286
+ @refresher.kill if @refresher and @refresher.status
287
+ @refresher = nil
292
288
  ensure
293
289
  unlock unless stolen
294
290
  end
295
291
  end
296
292
  else
293
+ @refresher = (@refresh ? new_refresher : nil)
297
294
  ObjectSpace.define_finalizer self, @clean if @clean
298
295
  ret = self
299
296
  end
@@ -303,16 +300,15 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
303
300
  end
304
301
 
305
302
  return ret
306
- #--}}}
307
303
  end
304
+
308
305
  def sweep
309
- #----{{{
310
306
  begin
311
- glob = File::join(@dirname, ".*lck")
307
+ glob = File.join(@dirname, ".*lck")
312
308
  paths = Dir[glob]
313
309
  paths.each do |path|
314
310
  begin
315
- basename = File::basename path
311
+ basename = File.basename path
316
312
  pat = %r/^\s*\.([^_]+)_([^_]+)/o
317
313
  if pat.match(basename)
318
314
  host, pid = $1, $2
@@ -327,7 +323,7 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
327
323
  unless alive?(pid)
328
324
  trace{ "process <#{ pid }> on <#{ host }> is no longer alive" }
329
325
  trace{ "sweeping <#{ path }>" }
330
- FileUtils::rm_f path
326
+ FileUtils.rm_f path
331
327
  else
332
328
  trace{ "process <#{ pid }> on <#{ host }> is still alive" }
333
329
  trace{ "ignoring <#{ path }>" }
@@ -342,24 +338,26 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
342
338
  rescue => e
343
339
  warn(errmsg(e))
344
340
  end
345
- #----}}}
346
341
  end
342
+
347
343
  def alive? pid
348
- #----{{{
349
344
  pid = Integer("#{ pid }")
350
345
  begin
351
- Process::kill 0, pid
346
+ Process.kill 0, pid
352
347
  true
353
348
  rescue Errno::ESRCH
354
349
  false
355
350
  end
356
- #----}}}
357
351
  end
352
+
358
353
  def unlock
359
- #--{{{
360
354
  raise UnLockError, "<#{ @path }> is not locked!" unless @locked
355
+
356
+ @refresher.kill if @refresher and @refresher.status
357
+ @refresher = nil
358
+
361
359
  begin
362
- File::unlink @path
360
+ File.unlink @path
363
361
  rescue Errno::ENOENT
364
362
  raise StolenLockError, @path
365
363
  ensure
@@ -367,11 +365,10 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
367
365
  @locked = false
368
366
  ObjectSpace.undefine_finalizer self if @clean
369
367
  end
370
- #--}}}
371
368
  end
369
+
372
370
  def new_refresher
373
- #--{{{
374
- Thread::new(Thread::current, @path, @refresh, @dont_use_lock_id) do |thread, path, refresh, dont_use_lock_id|
371
+ Thread.new(Thread.current, @path, @refresh, @dont_use_lock_id) do |thread, path, refresh, dont_use_lock_id|
375
372
  loop do
376
373
  begin
377
374
  touch path
@@ -385,48 +382,45 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
385
382
  rescue Exception => e
386
383
  trace{errmsg e}
387
384
  thread.raise StolenLockError
388
- Thread::exit
385
+ Thread.exit
389
386
  end
390
387
  end
391
388
  end
392
- #--}}}
393
389
  end
390
+
394
391
  def validlock?
395
- #--{{{
396
392
  if @max_age
397
393
  uncache @path rescue nil
398
394
  begin
399
- return((Time.now - File::stat(@path).mtime) < @max_age)
395
+ return((Time.now - File.stat(@path).mtime) < @max_age)
400
396
  rescue Errno::ENOENT
401
397
  return nil
402
398
  end
403
399
  else
404
- exist = File::exist?(@path)
400
+ exist = File.exist?(@path)
405
401
  return(exist ? true : nil)
406
402
  end
407
- #--}}}
408
403
  end
404
+
409
405
  def uncache file
410
- #--{{{
411
406
  refresh = nil
412
407
  begin
413
408
  is_a_file = File === file
414
409
  path = (is_a_file ? file.path : file.to_s)
415
- stat = (is_a_file ? file.stat : File::stat(file.to_s))
416
- refresh = tmpnam(File::dirname(path))
417
- File::link path, refresh
418
- File::chmod stat.mode, path
419
- File::utime stat.atime, stat.mtime, path
410
+ stat = (is_a_file ? file.stat : File.stat(file.to_s))
411
+ refresh = tmpnam(File.dirname(path))
412
+ File.link path, refresh
413
+ File.chmod stat.mode, path
414
+ File.utime stat.atime, stat.mtime, path
420
415
  ensure
421
416
  begin
422
- File::unlink refresh if refresh
417
+ File.unlink refresh if refresh
423
418
  rescue Errno::ENOENT
424
419
  end
425
420
  end
426
- #--}}}
427
421
  end
422
+
428
423
  def create_tmplock
429
- #--{{{
430
424
  tmplock = tmpnam @dirname
431
425
  begin
432
426
  create(tmplock) do |f|
@@ -440,124 +434,106 @@ unless(defined?($__lockfile__) or defined?(Lockfile))
440
434
  yield f
441
435
  end
442
436
  ensure
443
- begin; File::unlink tmplock; rescue Errno::ENOENT; end if tmplock
437
+ begin; File.unlink tmplock; rescue Errno::ENOENT; end if tmplock
444
438
  end
445
- #--}}}
446
439
  end
440
+
447
441
  def gen_lock_id
448
- #--{{{
449
442
  Hash[
450
443
  'host' => "#{ HOSTNAME }",
451
444
  'pid' => "#{ Process.pid }",
452
445
  'ppid' => "#{ Process.ppid }",
453
446
  'time' => timestamp,
454
447
  ]
455
- #--}}}
456
448
  end
449
+
457
450
  def timestamp
458
- #--{{{
459
451
  time = Time.now
460
452
  usec = time.usec.to_s
461
453
  usec << '0' while usec.size < 6
462
454
  "#{ time.strftime('%Y-%m-%d %H:%M:%S') }.#{ usec }"
463
- #--}}}
464
455
  end
465
- def dump_lock_id lock_id = @lock_id
466
- #--{{{
456
+
457
+ def dump_lock_id(lock_id = @lock_id)
467
458
  "host: %s\npid: %s\nppid: %s\ntime: %s\n" %
468
459
  lock_id.values_at('host','pid','ppid','time')
469
- #--}}}
470
460
  end
471
- def load_lock_id buf
472
- #--{{{
461
+
462
+ def load_lock_id(buf)
473
463
  lock_id = {}
474
464
  kv = %r/([^:]+):(.*)/o
475
- buf.each do |line|
465
+ buf.each_line do |line|
476
466
  m = kv.match line
477
467
  k, v = m[1], m[2]
478
468
  next unless m and k and v
479
469
  lock_id[k.strip] = v.strip
480
470
  end
481
471
  lock_id
482
- #--}}}
483
472
  end
484
- def tmpnam dir, seed = File::basename($0)
485
- #--{{{
473
+
474
+ def tmpnam(dir, seed = File.basename($0))
486
475
  pid = Process.pid
487
476
  time = Time.now
488
477
  sec = time.to_i
489
478
  usec = time.usec
490
479
  "%s%s.%s_%d_%s_%d_%d_%d.lck" %
491
480
  [dir, File::SEPARATOR, HOSTNAME, pid, seed, sec, usec, rand(sec)]
492
- #--}}}
493
481
  end
494
- def create path
495
- #--{{{
482
+
483
+ def create(path)
496
484
  umask = nil
497
485
  f = nil
498
486
  begin
499
- umask = File::umask 022
487
+ umask = File.umask 022
500
488
  f = open path, File::WRONLY|File::CREAT|File::EXCL, 0644
501
489
  ensure
502
- File::umask umask if umask
490
+ File.umask umask if umask
503
491
  end
504
492
  return(block_given? ? begin; yield f; ensure; f.close; end : f)
505
- #--}}}
506
493
  end
507
- def touch path
508
- #--{{{
494
+
495
+ def touch(path)
509
496
  FileUtils.touch path
510
- #--}}}
511
497
  end
512
- def getopt key, default = nil
513
- #--{{{
498
+
499
+ def getopt(key, default = nil)
514
500
  [ key, key.to_s, key.to_s.intern ].each do |k|
515
501
  return @opts[k] if @opts.has_key?(k)
516
502
  end
517
503
  return default
518
- #--}}}
519
504
  end
505
+
520
506
  def to_str
521
- #--{{{
522
507
  @path
523
- #--}}}
524
508
  end
525
509
  alias to_s to_str
526
- def trace s = nil
527
- #--{{{
510
+
511
+ def trace(s = nil)
528
512
  STDERR.puts((s ? s : yield)) if @debug
529
- #--}}}
530
513
  end
531
- def errmsg e
532
- #--{{{
514
+
515
+ def errmsg(e)
533
516
  "%s (%s)\n%s\n" % [e.class, e.message, e.backtrace.join("\n")]
534
- #--}}}
535
517
  end
518
+
536
519
  def attempt
537
- #----{{{
538
520
  ret = nil
539
521
  loop{ break unless catch('attempt'){ ret = yield } == 'try_again' }
540
522
  ret
541
- #----}}}
542
523
  end
524
+
543
525
  def try_again!
544
- #----{{{
545
526
  throw 'attempt', 'try_again'
546
- #----}}}
547
527
  end
548
528
  alias again! try_again!
529
+
549
530
  def give_up!
550
- #----{{{
551
531
  throw 'attempt', 'give_up'
552
- #----}}}
553
532
  end
554
- #--}}}
555
533
  end
556
534
 
557
- def Lockfile path, *a, &b
558
- #--{{{
535
+ def Lockfile(path, *a, &b)
559
536
  Lockfile.new(path, *a, &b)
560
- #--}}}
561
537
  end
562
538
 
563
539
  $__lockfile__ = __FILE__