jmongo 1.1.4 → 1.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'jmongo'
3
- s.version = '1.1.4'
4
- s.date = '2011-10-19'
3
+ s.version = '1.1.5'
4
+ s.date = '2011-10-22'
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.authors = ["Chuck Remes","Guy Boertje", "Lee Henson"]
7
7
  s.email = ["cremes@mac.com", "guyboertje@gmail.com", "lee.m.henson@gmail.com"]
@@ -12,7 +12,6 @@ Gem::Specification.new do |s|
12
12
  # = MANIFEST =
13
13
  s.files = %w[
14
14
  Gemfile
15
- Gemfile.lock
16
15
  History.txt
17
16
  LICENSE.txt
18
17
  README.txt
@@ -87,6 +86,7 @@ Gem::Specification.new do |s|
87
86
  test/replica_sets/replication_ack_test.rb
88
87
  test/replica_sets/rs_test_helper.rb
89
88
  test/safe_test.rb
89
+ test/subscribe_test.rb
90
90
  test/support/hash_with_indifferent_access.rb
91
91
  test/support/keys.rb
92
92
  test/support_test.rb
@@ -48,20 +48,37 @@ module Mongo
48
48
  if args.size < 2
49
49
  raise ArgumentError.new("Must supply at least name and db parameters")
50
50
  end
51
- if args.first.respond_to?('collection_names')
52
- db, name = args
53
- else
51
+ if args.first.is_a?(String)
54
52
  name, db = args
53
+ else
54
+ db, name = args
55
55
  end
56
-
57
56
  @name = validate_name(name)
58
57
  @db, @j_db = db, db.j_db
59
58
  @connection = @db.connection
60
59
  @pk_factory = @opts.delete(:pk)|| BSON::ObjectId
61
60
  @hint = nil
61
+
62
+ @monitor = @opts.delete(:monitor)
63
+ if @monitor
64
+ setup_monitor
65
+ elsif @opts.has_key?(:monitor_source)
66
+ @monitor_source = @opts.delete(:monitor_source)
67
+ end
68
+
62
69
  @j_collection = j_collection || @j_db.create_collection(@name, to_dbobject(@opts))
63
70
  end
64
71
 
72
+ def setup_monitor
73
+ mon_opts = @monitor.is_a?(Hash)? @monitor : {}
74
+ size = mon_opts.fetch(:size, 8000)
75
+ @monitor_max = mon_opts.fetch(:max, 100)
76
+ opts = {:capped => true, :max => @monitor_max, :size => size, :monitor_source => self}
77
+ @mon_collection = @db.create_collection("#{@name}-monitor", opts)
78
+ @j_mon_collection = @mon_collection.j_collection
79
+ @monitorable = true
80
+ end
81
+
65
82
  def safe
66
83
  !!@opts.fetch(:safe, false)
67
84
  end
@@ -648,5 +665,46 @@ module Mongo
648
665
  end
649
666
 
650
667
  alias :size :count
651
- end
652
- end
668
+
669
+ def monitor_collection
670
+ raise InvalidOperation, "Monitoring has not been setup, add :monitor - true or Hash" unless @monitorable
671
+ @mon_collection
672
+ end
673
+
674
+ def monitored_collection
675
+ @monitor_source
676
+ end
677
+
678
+ def monitor_subscribe(opts, &callback_doc)
679
+ raise MongoArgumentError, "Not a monitorable collection" if @monitor_source.nil?
680
+ raise MongoArgumentError, "Must supply a block" unless block_given?
681
+ raise MongoArgumentError, "opts needs to be a Hash" unless opts.is_a?(Hash)
682
+ callback_exit = opts[:callback_exit]
683
+ raise MongoArgumentError, "Need a callable for exit callback" unless callback_doc.respond_to?('call')
684
+ exit_check_timeout = opts[:exit_check_timeout]
685
+ raise MongoArgumentError, "Need a positive float for timeout" unless exit_check_timeout.to_f > 0.0
686
+
687
+ tail = Mongo::Cursor.new(self, :timeout => false, :tailable => true, :await_data => 0.5, :order => [['$natural', 1]])
688
+
689
+ loop_th = Thread.new(tail, callback_doc) do |cur, cb|
690
+ while !Thread.current[:stop]
691
+ doc = cur.next
692
+ cb.call(doc) if doc
693
+ end
694
+ end
695
+ loop_th[:stop] = false
696
+
697
+ exit_th = Thread.new(exit_check_timeout.to_f, callback_exit) do |to, cb|
698
+ while true
699
+ sleep to
700
+ must_exit = cb.call
701
+ break if must_exit
702
+ end
703
+ loop_th[:stop] = true
704
+ end
705
+ #
706
+ end
707
+
708
+
709
+ end #class
710
+ end #module
@@ -337,15 +337,6 @@ module Mongo
337
337
  self
338
338
  end
339
339
 
340
- def mask_option(bitfield, bit, set = true)
341
- if set
342
- bitfield |= bit
343
- else
344
- bitfield &= ~bit
345
- end
346
- bitfield
347
- end
348
-
349
340
  def wrap_invalid_op
350
341
  begin
351
342
  yield
@@ -106,6 +106,10 @@ module Mongo
106
106
  else
107
107
  begin
108
108
  @j_collection.insert( to_dbobject(to_do), concern )
109
+ if @monitorable
110
+ mon_do = to_do.map{ |doc| {'_id'=>doc['_id'], 'action'=>1} }
111
+ @j_mon_collection.insert( to_dbobject(mon_do), concern )
112
+ end
109
113
  rescue => ex
110
114
  if ex.message =~ /E11000/
111
115
  msg = "Failed to insert document #{obj.inspect}, duplicate key, E11000"
@@ -125,6 +129,10 @@ module Mongo
125
129
  begin
126
130
  jres = @j_collection.insert( dbo, concern )
127
131
  result = from_dbobject(jres.get_last_error(concern))
132
+ if @monitorable
133
+ mon_obj = one_obj.map{ |doc| {'_id'=>doc['_id'], 'action'=>1} }
134
+ @j_mon_collection.( to_dbobject(mon_obj), concern )
135
+ end
128
136
  rescue => ex
129
137
  if ex.message =~ /E11000/ #noop duplicate key
130
138
  result = {'err'=>ex.message}
@@ -1,3 +1,3 @@
1
1
  module Mongo
2
- VERSION = '1.1.4'
2
+ VERSION = '1.1.5'
3
3
  end
@@ -0,0 +1,84 @@
1
+ require 'minitest/spec'
2
+ require './test/test_helper'
3
+
4
+ Cfg.connection :op_timeout => 10
5
+ Cfg.db
6
+
7
+ describe "Monitorable Pair Collection" do
8
+ before do
9
+ Cfg.clear_all
10
+ end
11
+
12
+ describe "monitoring a collection with defaults" do
13
+
14
+ before do
15
+ opts = {:monitor => true}
16
+ @collection = Cfg.db.create_collection('buffer', opts)
17
+ end
18
+
19
+ it "should have a monitor_collection" do
20
+ assert @collection.monitor_collection
21
+ assert_equal "buffer-monitor", @collection.monitor_collection.name
22
+ end
23
+
24
+ it "should insert into the monitorable collection as well" do
25
+ @collection.insert({'field1' => 'some value', 'field2' => 99})
26
+ assert_equal 1, @collection.size
27
+ rec = @collection.find().to_a.first
28
+ assert_equal 1, @collection.monitor_collection.size
29
+ mon_rec = @collection.monitor_collection.find().to_a.first
30
+ assert_equal rec['_id'], mon_rec['_id']
31
+ assert_equal 1, mon_rec['action']
32
+ end
33
+
34
+ it "should raise when the subscribe method is called on a normal collection" do
35
+ normal = Cfg.db.create_collection('normal')
36
+ assert normal.respond_to?('monitor_subscribe')
37
+ assert_raises Mongo::MongoArgumentError do
38
+ normal.monitor_subscribe(2)
39
+ end
40
+ end
41
+
42
+ it "should raise for invalid options" do
43
+ @stop_callback = lambda{ true }
44
+ @monitored = @collection.monitor_collection
45
+ assert_raises Mongo::MongoArgumentError do
46
+ @monitored.monitor_subscribe({}) #no block
47
+ end
48
+ assert_raises Mongo::MongoArgumentError do
49
+ @monitored.monitor_subscribe({:callback_exit => ''}) {|doc| apr(doc,'doc')} #not callable
50
+ end
51
+ assert_raises Mongo::MongoArgumentError do
52
+ @monitored.monitor_subscribe({ :callback_exit => @stop_callback }) {|doc| apr(doc,'doc')} #no timeout
53
+ end
54
+ assert_raises Mongo::MongoArgumentError do
55
+ @monitored.monitor_subscribe({:callback_exit => @stop_callback, :exit_check_timeout => 0}) {|doc| apr(doc,'doc')} #timeout not positive float
56
+ end
57
+ end
58
+
59
+ it "the monitored collection should have a subscribe method" do
60
+ @stop = 0
61
+ @count = 0
62
+ @values = []
63
+ @stop_callback = lambda{ @stop += 1; true }
64
+ @monitored = @collection.monitor_collection
65
+ assert_equal @collection, @monitored.monitored_collection
66
+
67
+ @monitored.monitor_subscribe({:callback_exit => @stop_callback, :exit_check_timeout => 1.0}) do |doc|
68
+ if doc
69
+ id, act = doc.values_at('_id','action')
70
+ @count += (act || 0)
71
+ orig = @monitored.monitored_collection.find_one('_id'=>id)
72
+ @values << orig['field2'] if orig
73
+ end
74
+ end
75
+ @collection.insert({'field1' => 'some value', 'field2' => 99})
76
+ @collection.insert({'field1' => 'some value', 'field2' => 98})
77
+
78
+ sleep 1.2
79
+ assert_equal 1, @stop
80
+ assert_equal 2, @count
81
+ assert_equal [99,98], @values
82
+ end
83
+ end
84
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jmongo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.4
4
+ version: 1.1.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,11 +11,11 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2011-10-19 00:00:00.000000000 Z
14
+ date: 2011-10-22 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: require_all
18
- requirement: &15446080 !ruby/object:Gem::Requirement
18
+ requirement: &9275500 !ruby/object:Gem::Requirement
19
19
  none: false
20
20
  requirements:
21
21
  - - ~>
@@ -23,10 +23,10 @@ dependencies:
23
23
  version: '1.2'
24
24
  type: :runtime
25
25
  prerelease: false
26
- version_requirements: *15446080
26
+ version_requirements: *9275500
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: awesome_print
29
- requirement: &15445600 !ruby/object:Gem::Requirement
29
+ requirement: &9275020 !ruby/object:Gem::Requirement
30
30
  none: false
31
31
  requirements:
32
32
  - - ~>
@@ -34,10 +34,10 @@ dependencies:
34
34
  version: '0.4'
35
35
  type: :development
36
36
  prerelease: false
37
- version_requirements: *15445600
37
+ version_requirements: *9275020
38
38
  - !ruby/object:Gem::Dependency
39
39
  name: fuubar
40
- requirement: &15444720 !ruby/object:Gem::Requirement
40
+ requirement: &9274520 !ruby/object:Gem::Requirement
41
41
  none: false
42
42
  requirements:
43
43
  - - ~>
@@ -45,10 +45,10 @@ dependencies:
45
45
  version: '0.0'
46
46
  type: :development
47
47
  prerelease: false
48
- version_requirements: *15444720
48
+ version_requirements: *9274520
49
49
  - !ruby/object:Gem::Dependency
50
50
  name: rspec
51
- requirement: &15444260 !ruby/object:Gem::Requirement
51
+ requirement: &9273680 !ruby/object:Gem::Requirement
52
52
  none: false
53
53
  requirements:
54
54
  - - ~>
@@ -56,7 +56,7 @@ dependencies:
56
56
  version: '2.6'
57
57
  type: :development
58
58
  prerelease: false
59
- version_requirements: *15444260
59
+ version_requirements: *9273680
60
60
  description: Thin jruby wrapper around Mongo Java Driver
61
61
  email:
62
62
  - cremes@mac.com
@@ -68,7 +68,6 @@ extensions: []
68
68
  extra_rdoc_files: []
69
69
  files:
70
70
  - Gemfile
71
- - Gemfile.lock
72
71
  - History.txt
73
72
  - LICENSE.txt
74
73
  - README.txt
@@ -143,6 +142,7 @@ files:
143
142
  - test/replica_sets/replication_ack_test.rb
144
143
  - test/replica_sets/rs_test_helper.rb
145
144
  - test/safe_test.rb
145
+ - test/subscribe_test.rb
146
146
  - test/support/hash_with_indifferent_access.rb
147
147
  - test/support/keys.rb
148
148
  - test/support_test.rb
@@ -1,44 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- jmongo (1.1.1)
5
- require_all (~> 1.2)
6
-
7
- GEM
8
- remote: http://rubygems.org/
9
- specs:
10
- awesome_print (0.4.0)
11
- diff-lcs (1.1.3)
12
- fuubar (0.0.6)
13
- rspec (~> 2.0)
14
- rspec-instafail (~> 0.1.8)
15
- ruby-progressbar (~> 0.0.10)
16
- metaclass (0.0.1)
17
- mocha (0.10.0)
18
- metaclass (~> 0.0.1)
19
- rake (0.9.2)
20
- require_all (1.2.0)
21
- rspec (2.6.0)
22
- rspec-core (~> 2.6.0)
23
- rspec-expectations (~> 2.6.0)
24
- rspec-mocks (~> 2.6.0)
25
- rspec-core (2.6.4)
26
- rspec-expectations (2.6.0)
27
- diff-lcs (~> 1.1.2)
28
- rspec-instafail (0.1.8)
29
- rspec-mocks (2.6.0)
30
- ruby-progressbar (0.0.10)
31
- shoulda (2.11.3)
32
-
33
- PLATFORMS
34
- java
35
- ruby
36
-
37
- DEPENDENCIES
38
- awesome_print (~> 0.4)
39
- fuubar (~> 0.0)
40
- jmongo!
41
- mocha
42
- rake
43
- rspec (~> 2.6)
44
- shoulda