bosh_common 0.4.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/README ADDED
@@ -0,0 +1 @@
1
+ BOSH common / shared classes
data/Rakefile ADDED
@@ -0,0 +1,51 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ $:.unshift(File.expand_path("../../rake", __FILE__))
4
+
5
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __FILE__)
6
+
7
+ require "rubygems"
8
+ require "bundler"
9
+ Bundler.setup(:default, :test)
10
+
11
+ require "rake"
12
+ begin
13
+ require "rspec/core/rake_task"
14
+ rescue LoadError
15
+ end
16
+
17
+ require "bundler_task"
18
+ require "ci_task"
19
+
20
+ gem_helper = Bundler::GemHelper.new(Dir.pwd)
21
+
22
+ desc "Build Blobstore Client gem into the pkg directory"
23
+ task "build" do
24
+ gem_helper.build_gem
25
+ end
26
+
27
+ desc "Build and install Blobstore Client into system gems"
28
+ task "install" do
29
+ sh("bundle install --local --without test development")
30
+ gem_helper.install_gem
31
+ end
32
+
33
+ BundlerTask.new
34
+
35
+ if defined?(RSpec)
36
+ namespace :spec do
37
+ desc "Run Unit Tests"
38
+ rspec_task = RSpec::Core::RakeTask.new(:unit) do |t|
39
+ t.gemfile = "Gemfile"
40
+ t.pattern = "spec/unit/**/*_spec.rb"
41
+ t.rspec_opts = %w(--format progress --colour)
42
+ end
43
+
44
+ CiTask.new do |task|
45
+ task.rspec_task = rspec_task
46
+ end
47
+ end
48
+
49
+ desc "Install dependencies and run tests"
50
+ task :spec => %w(bundler:install:test spec:unit)
51
+ end
@@ -0,0 +1,51 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ class ThreadFormatter
4
+ FORMAT = "%s, [%s#%d] [%s] %5s -- %s: %s\n"
5
+
6
+ attr_accessor :datetime_format
7
+
8
+ def initialize
9
+ @datetime_format = nil
10
+ end
11
+
12
+ def call(severity, time, progname, msg)
13
+ thread_name = Thread.current[:name] || "0x#{Thread.current.object_id.to_s(16)}"
14
+ FORMAT % [severity[0..0], format_datetime(time), $$, thread_name, severity, progname,
15
+ msg2str(msg)]
16
+ end
17
+
18
+ private
19
+
20
+ def format_datetime(time)
21
+ if @datetime_format.nil?
22
+ time.strftime("%Y-%m-%dT%H:%M:%S.") << "%06d " % time.usec
23
+ else
24
+ time.strftime(@datetime_format)
25
+ end
26
+ end
27
+
28
+ def msg2str(msg)
29
+ case msg
30
+ when ::String
31
+ msg
32
+ when ::Exception
33
+ "#{ msg.message } (#{ msg.class })\n" <<
34
+ (msg.backtrace || []).join("\n")
35
+ else
36
+ msg.inspect
37
+ end
38
+ end
39
+ end
40
+
41
+ module Kernel
42
+
43
+ def with_thread_name(name)
44
+ old_name = Thread.current[:name]
45
+ Thread.current[:name] = name
46
+ yield
47
+ ensure
48
+ Thread.current[:name] = old_name
49
+ end
50
+
51
+ end
@@ -0,0 +1,130 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require "logger"
4
+
5
+ module Bosh
6
+
7
+ class ThreadPool
8
+
9
+ def initialize(options = {})
10
+ @actions = []
11
+ @lock = Mutex.new
12
+ @cv = ConditionVariable.new
13
+ @max_threads = options[:max_threads] || 1
14
+ @available_threads = @max_threads
15
+ @logger = options[:logger]
16
+ @boom = nil
17
+ @original_thread = Thread.current
18
+ @threads = []
19
+ @state = :open
20
+ end
21
+
22
+ def wrap
23
+ begin
24
+ yield self
25
+ wait
26
+ ensure
27
+ shutdown
28
+ end
29
+ end
30
+
31
+ def pause
32
+ @lock.synchronize do
33
+ @state = :paused
34
+ end
35
+ end
36
+
37
+ def resume
38
+ @lock.synchronize do
39
+ @state = :open
40
+ [@available_threads, @actions.size].min.times do
41
+ @available_threads -= 1
42
+ create_thread
43
+ end
44
+ end
45
+ end
46
+
47
+ def process(&block)
48
+ @lock.synchronize do
49
+ @actions << block
50
+ if @state == :open
51
+ if @available_threads > 0
52
+ @logger.debug("Creating new thread")
53
+ @available_threads -= 1
54
+ create_thread
55
+ else
56
+ @logger.debug("All threads are currently busy, queuing action")
57
+ end
58
+ elsif @state == :paused
59
+ @logger.debug("Pool is paused, queueing action.")
60
+ end
61
+ end
62
+ end
63
+
64
+ def create_thread
65
+ thread = Thread.new do
66
+ begin
67
+ loop do
68
+ action = nil
69
+ @lock.synchronize do
70
+ action = @actions.shift unless @boom
71
+ if action
72
+ @logger.debug("Found an action that needs to be processed")
73
+ else
74
+ @logger.debug("Thread is no longer needed, cleaning up")
75
+ @available_threads += 1
76
+ @threads.delete(thread) if @state == :open
77
+ end
78
+ end
79
+
80
+ break unless action
81
+
82
+ begin
83
+ action.call
84
+ rescue Exception => e
85
+ raise_worker_exception(e)
86
+ end
87
+ end
88
+ end
89
+ @lock.synchronize { @cv.signal unless working? }
90
+ end
91
+ @threads << thread
92
+ end
93
+
94
+ def raise_worker_exception(exception)
95
+ if exception.respond_to?(:backtrace)
96
+ @logger.debug("Worker thread raised exception: #{exception} - #{exception.backtrace.join("\n")}")
97
+ else
98
+ @logger.debug("Worker thread raised exception: #{exception}")
99
+ end
100
+ @lock.synchronize do
101
+ @boom = exception if @boom.nil?
102
+ end
103
+ end
104
+
105
+ def working?
106
+ @boom.nil? && (@available_threads != @max_threads || !@actions.empty?)
107
+ end
108
+
109
+ def wait
110
+ @logger.debug("Waiting for tasks to complete")
111
+ @lock.synchronize do
112
+ @cv.wait(@lock) while working?
113
+ raise @boom if @boom
114
+ end
115
+ end
116
+
117
+ def shutdown
118
+ return if @state == :closed
119
+ @logger.debug("Shutting down pool")
120
+ @lock.synchronize do
121
+ return if @state == :closed
122
+ @state = :closed
123
+ @actions.clear
124
+ end
125
+ @threads.each { |t| t.join }
126
+ end
127
+
128
+ end
129
+
130
+ end
@@ -0,0 +1,7 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh
4
+ module Common
5
+ VERSION = "0.4.0"
6
+ end
7
+ end
data/spec/Rakefile ADDED
@@ -0,0 +1,87 @@
1
+ require "tempfile"
2
+ require "rake"
3
+
4
+ APP_DIR = File.expand_path(File.join("..", ".."), __FILE__)
5
+ ENV["BUNDLE_GEMFILE"] ||= File.join(APP_DIR, "Gemfile")
6
+ require "rubygems"
7
+ require "bundler"
8
+ Bundler.setup(:default, :test)
9
+
10
+ require "rspec/core/rake_task"
11
+ require "ci/reporter/rake/rspec"
12
+
13
+ desc "Run all examples"
14
+ RSpec::Core::RakeTask.new(:spec) do |t|
15
+ t.pattern = "**/*_spec.rb"
16
+ t.rspec_opts = %w[--color]
17
+ end
18
+
19
+ task :default => [:spec]
20
+
21
+ coverage_dir = File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_coverage"))
22
+ reports_dir = File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_reports"))
23
+ dump_file = File.join(Dir.tmpdir, "bosh-common.rcov")
24
+
25
+ ENV["CI_REPORTS"] = reports_dir
26
+
27
+ namespace "spec" do
28
+ gemfile = "../Gemfile"
29
+ spec_opts = ["--format", "documentation", "--colour"]
30
+
31
+ if RUBY_VERSION < "1.9"
32
+ desc "Run specs for ci"
33
+ task "ci" => [ "ci:setup:rspec", "spec:rcov", "convert_rcov_to_clover" ]
34
+
35
+ desc "Run spec with coverage"
36
+ RSpec::Core::RakeTask.new("rcov") do |t|
37
+ FileUtils.rm_rf(dump_file)
38
+ t.gemfile = gemfile
39
+ t.pattern = "**/*_spec.rb"
40
+ t.rspec_opts = ["--format", "progress", "--colour"]
41
+ t.rcov = true
42
+ t.rcov_opts = %W{--aggregate #{dump_file} --exclude osx\/objc,gems\/,spec\/,unit\/,features\/ -o "#{coverage_dir}"}
43
+ end
44
+
45
+ task "convert_rcov_to_clover" do |t|
46
+ ignore_pattern = "spec,[.]bundle,[/]gems[/]"
47
+ clover_output = File.join(coverage_dir, "clover.xml")
48
+
49
+ sh("bundle exec rcov_analyzer #{dump_file} #{ignore_pattern} > #{clover_output}")
50
+ FileUtils.rm_rf(dump_file)
51
+ end
52
+
53
+ else
54
+ desc "Run specs for ci"
55
+ task "ci" => [ "ci:setup:rspec", "spec:rcov" ]
56
+
57
+ desc "Run spec with coverage"
58
+ task :rcov => :cleanup_coverage do
59
+ require "simplecov"
60
+ require "simplecov-rcov"
61
+ require "simplecov-clover"
62
+
63
+ class SimpleCov::Formatter::CombinedFormatter
64
+ def format(result)
65
+ SimpleCov::Formatter::CloverFormatter.new.format(result)
66
+ SimpleCov::Formatter::RcovFormatter.new.format(result)
67
+ end
68
+ end
69
+
70
+ SimpleCov.formatter = SimpleCov::Formatter::CombinedFormatter
71
+ SimpleCov.root('..')
72
+ SimpleCov.coverage_dir('cov')
73
+ SimpleCov.start do
74
+ require "rspec/core"
75
+ add_filter "/spec/"
76
+ spec_dir = File.expand_path("..", __FILE__)
77
+ RSpec::Core::Runner.disable_autorun!
78
+ RSpec::Core::Runner.run([spec_dir], STDERR, STDOUT)
79
+ end
80
+ end
81
+ end
82
+
83
+ task "cleanup_coverage" do
84
+ rm_rf "cov"
85
+ end
86
+
87
+ end
@@ -0,0 +1,8 @@
1
+ module Bosh
2
+ module Clouds
3
+ class Spec
4
+ def initialize(options)
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ require 'rspec/core'
2
+
3
+ $:.unshift(File.expand_path("../../lib", __FILE__))
4
+
5
+ RSpec.configure do |c|
6
+ c.color_enabled = true
7
+ end
@@ -0,0 +1,69 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require File.expand_path("../../spec_helper", __FILE__)
4
+
5
+ require "common/thread_pool"
6
+
7
+ describe Bosh::ThreadPool do
8
+
9
+ before(:all) do
10
+ @logger = Logger.new(STDOUT)
11
+ @logger.level = Logger::INFO
12
+ end
13
+
14
+ it "should respect max threads" do
15
+ max = 0
16
+ current = 0
17
+ lock = Mutex.new
18
+
19
+ Bosh::ThreadPool.new(:max_threads => 2, :logger => @logger).wrap do |pool|
20
+ 4.times do
21
+ pool.process do
22
+ lock.synchronize do
23
+ current += 1
24
+ max = current if current > max
25
+ end
26
+ sleep(0.050)
27
+ lock.synchronize do
28
+ max = current if current > max
29
+ current -= 1
30
+ end
31
+ end
32
+ end
33
+ end
34
+ max.should be <= 2
35
+ end
36
+
37
+ it "should raise exceptions" do
38
+ lambda {
39
+ Bosh::ThreadPool.new(:max_threads => 2, :logger => @logger).wrap do |pool|
40
+ 5.times do |index|
41
+ pool.process do
42
+ sleep(0.050)
43
+ raise "bad" if index == 4
44
+ end
45
+ end
46
+ end
47
+ }.should raise_exception("bad")
48
+ end
49
+
50
+ it "should stop processing new work when there was an exception" do
51
+ max = 0
52
+ lock = Mutex.new
53
+
54
+ lambda {
55
+ Bosh::ThreadPool.new(:max_threads => 1, :logger => @logger).wrap do |pool|
56
+ 10.times do |index|
57
+ pool.process do
58
+ lock.synchronize { max = index if index > max }
59
+ sleep(0.050)
60
+ raise "bad" if index == 4
61
+ end
62
+ end
63
+ end
64
+ }.should raise_exception("bad")
65
+
66
+ max.should be == 4
67
+ end
68
+
69
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bosh_common
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - VMware
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-22 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &2156296060 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *2156296060
25
+ description: Bosh common
26
+ email: support@vmware.com
27
+ executables: []
28
+ extensions: []
29
+ extra_rdoc_files: []
30
+ files:
31
+ - README
32
+ - Rakefile
33
+ - lib/common/thread_formatter.rb
34
+ - lib/common/thread_pool.rb
35
+ - lib/common/version.rb
36
+ - spec/Rakefile
37
+ - spec/lib/cloud/spec.rb
38
+ - spec/spec_helper.rb
39
+ - spec/unit/thread_pool_spec.rb
40
+ homepage: http://www.vmware.com
41
+ licenses: []
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ segments:
53
+ - 0
54
+ hash: -472840810854006979
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ segments:
62
+ - 0
63
+ hash: -472840810854006979
64
+ requirements: []
65
+ rubyforge_project:
66
+ rubygems_version: 1.8.10
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: Bosh common
70
+ test_files:
71
+ - spec/Rakefile
72
+ - spec/lib/cloud/spec.rb
73
+ - spec/spec_helper.rb
74
+ - spec/unit/thread_pool_spec.rb