lockfile 1.4.3 → 2.0.1

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.
@@ -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__