mega_mutex 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -19,6 +19,16 @@ rescue LoadError
19
19
  puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
20
20
  end
21
21
 
22
+ namespace :github do
23
+ task :push do
24
+ remotes = `git remote`.split("\n")
25
+ unless remotes.include?('github')
26
+ sh('git remote add github git@github.com:songkick/mega_mutex.git')
27
+ end
28
+ sh('git push github master')
29
+ end
30
+ end
31
+
22
32
  require 'spec/rake/spectask'
23
33
  Spec::Rake::SpecTask.new(:spec) do |spec|
24
34
  spec.libs << 'lib' << 'spec'
@@ -33,7 +43,7 @@ end
33
43
 
34
44
  task :spec => :check_dependencies
35
45
 
36
- task :default => :spec
46
+ task :default => [:spec, 'github:push', 'gemcutter:release']
37
47
 
38
48
  require 'rake/rdoctask'
39
49
  Rake::RDocTask.new do |rdoc|
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
@@ -6,24 +6,6 @@ module MegaMutex
6
6
 
7
7
  class CrossProcessMutex
8
8
 
9
- class Configuration
10
- attr_accessor :memcache_servers
11
-
12
- def initialize
13
- @memcache_servers = 'localhost'
14
- end
15
- end
16
-
17
- class << self
18
- def configure
19
- yield configuration
20
- end
21
-
22
- def configuration
23
- @configuration ||= Configuration.new
24
- end
25
- end
26
-
27
9
  def initialize(key, timeout = nil)
28
10
  @key = key
29
11
  @timeout = timeout
@@ -45,6 +27,10 @@ module MegaMutex
45
27
  log "Unlocking Mutex."
46
28
  end
47
29
 
30
+ def current_lock
31
+ cache.get(@key)
32
+ end
33
+
48
34
  private
49
35
 
50
36
  def timeout?
@@ -81,10 +67,6 @@ module MegaMutex
81
67
  current_lock == my_lock_id
82
68
  end
83
69
 
84
- def current_lock
85
- cache.get(@key)
86
- end
87
-
88
70
  def set_current_lock(new_lock)
89
71
  cache.add(@key, my_lock_id)
90
72
  end
@@ -94,7 +76,7 @@ module MegaMutex
94
76
  end
95
77
 
96
78
  def cache
97
- @cache ||= MemCache.new self.class.configuration.memcache_servers, :namespace => 'mega_mutex'
79
+ @cache ||= MemCache.new MegaMutex.configuration.memcache_servers, :namespace => MegaMutex.configuration.namespace
98
80
  end
99
81
  end
100
82
  end
data/lib/mega_mutex.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require 'rubygems'
2
- $:.push File.expand_path(File.dirname(__FILE__))
3
-
2
+ $:.push File.expand_path(File.dirname(__FILE__)) unless $:.include?(File.expand_path(File.dirname(__FILE__)))
4
3
  require 'mega_mutex/cross_process_mutex'
5
4
 
6
5
  # == Why
@@ -41,6 +40,10 @@ require 'mega_mutex/cross_process_mutex'
41
40
  # config.memcache_servers = ['mc1', 'mc2']
42
41
  # end
43
42
  module MegaMutex
43
+
44
+ def self.get_current_lock(mutex_id)
45
+ CrossProcessMutex.new(mutex_id).current_lock
46
+ end
44
47
 
45
48
  ##
46
49
  # Wraps code that should only be run when the mutex has been obtained.
@@ -55,7 +58,49 @@ module MegaMutex
55
58
  # end
56
59
  def with_cross_process_mutex(mutex_id, options = {}, &block)
57
60
  mutex = CrossProcessMutex.new(mutex_id, options[:timeout])
58
- mutex.run(&block)
61
+ begin
62
+ mutex.run(&block)
63
+ rescue Object => e
64
+ mega_mutex_insert_into_backtrace(
65
+ e,
66
+ /mega_mutex\.rb.*with_cross_process_mutex/,
67
+ "MegaMutex lock #{mutex_id}"
68
+ )
69
+ raise e
70
+ end
59
71
  end
60
72
 
73
+ # inserts a line into a backtrace at the correct location
74
+ def mega_mutex_insert_into_backtrace(exception, re, newline)
75
+ loc = nil
76
+ exception.backtrace.each_with_index do |line, index|
77
+ if line =~ re
78
+ loc = index
79
+ break
80
+ end
81
+ end
82
+ if loc
83
+ exception.backtrace.insert(loc, newline)
84
+ end
85
+ end
86
+
87
+ class Configuration
88
+ attr_accessor :memcache_servers, :namespace
89
+
90
+ def initialize
91
+ @memcache_servers = 'localhost'
92
+ @namespace = 'mega_mutex'
93
+ end
94
+ end
95
+
96
+ class << self
97
+ def configure
98
+ yield configuration
99
+ end
100
+
101
+ def configuration
102
+ @configuration ||= Configuration.new
103
+ end
104
+ end
61
105
  end
106
+
data/mega_mutex.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mega_mutex}
8
- s.version = "0.1.0"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Matt Johnson", "Matt Wynne"]
12
- s.date = %q{2009-08-18}
12
+ s.date = %q{2009-10-26}
13
13
  s.description = %q{Cross-process mutex using MemCache}
14
14
  s.email = %q{developers@songkick.com}
15
15
  s.extra_rdoc_files = [
@@ -26,15 +26,17 @@ Gem::Specification.new do |s|
26
26
  "lib/mega_mutex.rb",
27
27
  "lib/mega_mutex/cross_process_mutex.rb",
28
28
  "mega_mutex.gemspec",
29
- "spec/lib/mega_mutex_spec.rb"
29
+ "spec/lib/mega_mutex_spec.rb",
30
+ "spec/spec_helper.rb"
30
31
  ]
31
32
  s.homepage = %q{http://github.com/songkick/mega_mutex}
32
33
  s.rdoc_options = ["--charset=UTF-8"]
33
34
  s.require_paths = ["lib"]
34
- s.rubygems_version = %q{1.3.4}
35
+ s.rubygems_version = %q{1.3.5}
35
36
  s.summary = %q{Cross-process mutex using MemCache}
36
37
  s.test_files = [
37
- "spec/lib/mega_mutex_spec.rb"
38
+ "spec/spec_helper.rb",
39
+ "spec/lib/mega_mutex_spec.rb"
38
40
  ]
39
41
 
40
42
  if s.respond_to? :specification_version then
@@ -1,20 +1,12 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../../lib/mega_mutex')
2
-
3
- # Logging::Logger[:root].add_appenders(Logging::Appenders.stdout)
1
+ require File.dirname(__FILE__) + '/../spec_helper'
4
2
 
5
3
  module MegaMutex
6
4
  describe MegaMutex do
7
5
  def logger
8
6
  Logging::Logger['Specs']
9
7
  end
10
-
11
- before(:all) do
12
- @old_abort_on_exception_value = Thread.abort_on_exception
13
- Thread.abort_on_exception = true
14
- end
15
- after(:all) do
16
- Thread.abort_on_exception = @old_abort_on_exception_value
17
- end
8
+
9
+ abort_on_thread_exceptions
18
10
 
19
11
  describe "two blocks, one fast, one slow" do
20
12
  before(:each) do
@@ -29,10 +21,9 @@ module MegaMutex
29
21
 
30
22
  describe "with no lock" do
31
23
  it "trying to run the block twice should raise an error" do
32
- threads = []
33
24
  threads << Thread.new(&@mutually_exclusive_block)
34
25
  threads << Thread.new(&@mutually_exclusive_block)
35
- threads.each{ |t| t.join }
26
+ wait_for_threads_to_finish
36
27
  @errors.should_not be_empty
37
28
  end
38
29
  end
@@ -51,11 +42,10 @@ module MegaMutex
51
42
  [2, 20].each do |n|
52
43
  describe "when #{n} blocks try to run at the same instant in the same process" do
53
44
  it "should run each in turn" do
54
- threads = []
55
45
  n.times do
56
46
  threads << Thread.new{ with_cross_process_mutex(mutex_id, &@mutually_exclusive_block) }
57
47
  end
58
- threads.each{ |t| t.join }
48
+ wait_for_threads_to_finish
59
49
  @errors.should be_empty
60
50
  end
61
51
  end
@@ -110,19 +100,27 @@ module MegaMutex
110
100
 
111
101
  describe "with a timeout" do
112
102
  include MegaMutex
103
+
113
104
  it "should raise an error if the code blocks for longer than the timeout" do
114
- @success = false
115
- threads = []
116
- threads << Thread.new{ with_cross_process_mutex('foo'){ sleep 2 } }
105
+ @exception = nil
106
+ @first_thread_has_started = false
117
107
  threads << Thread.new do
108
+ with_cross_process_mutex('foo') do
109
+ @first_thread_has_started = true
110
+ sleep 0.2
111
+ end
112
+ end
113
+ threads << Thread.new do
114
+ sleep 0.1 until @first_thread_has_started
118
115
  begin
119
- with_cross_process_mutex('foo', :timeout => 1 ){ puts 'nobody will ever hear me scream' }
120
- rescue MegaMutex::TimeoutError
121
- @success = true
116
+ with_cross_process_mutex('foo', :timeout => 0.1 ) do
117
+ raise 'this code should never run'
118
+ end
119
+ rescue Exception => @exception
122
120
  end
123
121
  end
124
- threads.each{ |t| t.join }
125
- @success.should be_true
122
+ wait_for_threads_to_finish
123
+ assert @exception.is_a?(MegaMutex::TimeoutError), "Expected TimeoutError to be raised, but wasn't"
126
124
  end
127
125
  end
128
126
  end
@@ -0,0 +1,32 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/mega_mutex')
2
+ require 'test/unit/assertions'
3
+
4
+ # Logging::Logger[:root].add_appenders(Logging::Appenders.stdout)
5
+
6
+ module ThreadHelper
7
+ def abort_on_thread_exceptions
8
+ before(:all) do
9
+ @old_abort_on_exception_value = Thread.abort_on_exception
10
+ Thread.abort_on_exception = true
11
+ end
12
+ after(:all) do
13
+ Thread.abort_on_exception = @old_abort_on_exception_value
14
+ end
15
+ end
16
+ end
17
+
18
+ module ThreadExampleHelper
19
+ def threads
20
+ @threads ||= []
21
+ end
22
+
23
+ def wait_for_threads_to_finish
24
+ threads.each{ |t| t.join }
25
+ end
26
+ end
27
+
28
+ Spec::Runner.configure do |config|
29
+ config.extend ThreadHelper
30
+ config.include ThreadExampleHelper
31
+ config.include Test::Unit::Assertions
32
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mega_mutex
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Johnson
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-08-18 00:00:00 +01:00
13
+ date: 2009-10-26 00:00:00 +00:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -53,6 +53,7 @@ files:
53
53
  - lib/mega_mutex/cross_process_mutex.rb
54
54
  - mega_mutex.gemspec
55
55
  - spec/lib/mega_mutex_spec.rb
56
+ - spec/spec_helper.rb
56
57
  has_rdoc: true
57
58
  homepage: http://github.com/songkick/mega_mutex
58
59
  licenses: []
@@ -77,9 +78,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
77
78
  requirements: []
78
79
 
79
80
  rubyforge_project:
80
- rubygems_version: 1.3.4
81
+ rubygems_version: 1.3.5
81
82
  signing_key:
82
83
  specification_version: 3
83
84
  summary: Cross-process mutex using MemCache
84
85
  test_files:
86
+ - spec/spec_helper.rb
85
87
  - spec/lib/mega_mutex_spec.rb