Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add description change events.

Further along the server implementation card, this commit introduces the
ability of a server description to update itself with the result of an
ismaster command. The result of any changes will fire corresponding
events to the server, starting with a host being added or removed in a
replica set.

This is part of RUBY-677, but does not complete it.
  • Loading branch information...
commit 4d4de9f5b64667360166a066a69134eff99e85d2 1 parent 5df6311
@durran durran authored
View
25 lib/mongo/event.rb
@@ -14,18 +14,31 @@
require 'mongo/event/publisher'
require 'mongo/event/subscriber'
+require 'mongo/event/host_added'
+require 'mongo/event/host_removed'
module Mongo
module Event
- ARBITER_ADDED = "arbiter_added".freeze
- ARBITER_REMOVED = "arbiter_removed".freeze
+ # When a server description has a new host added.
+ #
+ # @since 3.0.0
+ HOST_ADDED = "host_added".freeze
- SECONDARY_ADDED = "server_added".freeze
- SECONDARY_REMOVED = "server_removed".freeze
+ # When a server description has a host removed.
+ #
+ # @since 3.0.0
+ HOST_REMOVED = "host_removed".freeze
- SERVER_PROMOTED = "server_promoted".freeze
- SERVER_DEMOTED = "server_demoted".freeze
+ # When a server is to be added to a cluster.
+ #
+ # @since 3.0.0
+ SERVER_ADDED = "server_added".freeze
+
+ # When a server is to be removed from a cluster.
+ #
+ # @since 3.0.0
+ SERVER_REMOVED = "server_removed".freeze
end
end
View
44 lib/mongo/event/host_added.rb
@@ -0,0 +1,44 @@
+# Copyright (C) 2009-2014 MongoDB, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module Mongo
+ module Event
+
+ # This handles host added events for server descriptions.
+ #
+ # @since 3.0.0
+ class HostAdded
+
+ # @return [ Mongo::Server ] server The event publisher.
+ attr_reader :server
+
+ # Initialize the new host added event handler.
+ #
+ # @example Create the new handler.
+ # HostAdded.new(server)
+ #
+ # @param [ Mongo::Server ] server The server to publish from.
+ #
+ # @since 3.0.0
+ def initialize(server)
+ @server = server
+ end
+
+ def handle(address)
+ # @todo: Log the description change here.
+ server.publish(Event::SERVER_ADDED, address)
+ end
+ end
+ end
+end
View
44 lib/mongo/event/host_removed.rb
@@ -0,0 +1,44 @@
+# Copyright (C) 2009-2014 MongoDB, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module Mongo
+ module Event
+
+ # This handles host removed events for server descriptions.
+ #
+ # @since 3.0.0
+ class HostRemoved
+
+ # @return [ Mongo::Server ] server The event publisher.
+ attr_reader :server
+
+ # Initialize the new host removed event handler.
+ #
+ # @example Create the new handler.
+ # HostRemoved.new(server)
+ #
+ # @param [ Mongo::Server ] server The server to publish from.
+ #
+ # @since 3.0.0
+ def initialize(server)
+ @server = server
+ end
+
+ def handle(address)
+ # @todo: Log the description change here.
+ server.publish(Event::SERVER_REMOVED, address)
+ end
+ end
+ end
+end
View
32 lib/mongo/server.rb
@@ -24,6 +24,7 @@ module Mongo
# @since 3.0.0
class Server
include Event::Publisher
+ include Event::Subscriber
# The default time for a server to refresh its status is 5 seconds.
#
@@ -52,6 +53,7 @@ def initialize(address, options = {})
@address = Address.new(address)
@options = options
@mutex = Mutex.new
+ initialize_description!
@refresh = Refresh.new(self, refresh_interval)
@refresh.run
end
@@ -60,15 +62,22 @@ def operable?
true
end
+ # Refresh the configuration for this server. Is thread-safe since the
+ # periodic refresh is invoked from another thread in order not to continue
+ # blocking operations on the current thread.
+ #
+ # @example Refresh the server.
+ # server.refresh!
+ #
+ # @note Is mutable in that the underlying server description can get
+ # mutated on this call.
+ #
+ # @return [ Server::Description ] The updated server description.
+ #
+ # @since 3.0.0
def refresh!
mutex.synchronize do
- # Update the server description here. For changes in the description to
- # the previous we need to fire events.
- #
- # refreshed = Description.new(read(refresh_command))
- #
- # publish(Event::SERVER_ADDED, address)
- # publish(Event::SERVER_REMOVED, address)
+ description.update!(dispatch([ refresh_command ]))
end
end
@@ -108,16 +117,23 @@ def refresh_interval
private
+ def initialize_description!
+ # @description = Description.new(dispatch([ refresh_command ]))
+ # subscribe_to(description, Event::HOST_ADDED, Event::HostAdded.new(self))
+ # subscribe_to(description, Event::HOST_REMOVED, Event::HostRemoved.new(self))
+ end
+
def pool
@pool ||= Pool.get(self)
end
+ # @todo: Need to sort out read preference here.
def refresh_command
Protocol::Query.new(
Database::ADMIN,
Database::COMMAND,
STATUS,
- :limit => -1, :read => cluster.client.read_preference
+ :limit => -1
)
end
View
36 lib/mongo/server/description.rb
@@ -20,6 +20,7 @@ class Server
#
# @since 3.0.0
class Description
+ include Event::Publisher
# Constant for reading arbiter info from config.
#
@@ -207,6 +208,41 @@ def secondary?
def set_name
config[SET_NAME]
end
+
+ # Update this description with a new description. Will fire the
+ # necessary events depending on what has changed from the old description
+ # to the new one.
+ #
+ # @example Update the description with the new config.
+ # description.update!({ "ismaster" => false })
+ #
+ # @note This modifies the state of the description.
+ #
+ # @param [ Hash ] new_config The new configuration.
+ #
+ # @return [ Description ] The updated description.
+ #
+ # @since 3.0.0
+ def update!(new_config)
+ find_new_servers(new_config)
+ find_removed_servers(new_config)
+ @config = new_config
+ self
+ end
+
+ private
+
+ def find_new_servers(new_config)
+ new_config[HOSTS].each do |host|
+ publish(Event::HOST_ADDED, host) unless hosts.include?(host)
+ end
+ end
+
+ def find_removed_servers(new_config)
+ hosts.each do |host|
+ publish(Event::HOST_REMOVED, host) unless new_config[HOSTS].include?(host)
+ end
+ end
end
end
end
View
7 spec/mongo/client_spec.rb
@@ -194,15 +194,12 @@
describe '#inspect' do
let(:client) do
- described_class.new(
- ['1.0.0.1:2', '1.0.0.1:1'],
- :read => :primary
- )
+ described_class.new(['127.0.0.1:27017'], :read => :primary)
end
it 'returns the cluster information' do
expect(client.inspect).to eq(
- "<Mongo::Client:0x#{client.object_id} cluster=1.0.0.1:2, 1.0.0.1:1>"
+ "<Mongo::Client:0x#{client.object_id} cluster=127.0.0.1:27017>"
)
end
end
View
20 spec/mongo/event/host_added_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe Mongo::Event::HostAdded do
+
+ describe '#handle' do
+
+ let(:server) do
+ double('server')
+ end
+
+ let(:handler) do
+ described_class.new(server)
+ end
+
+ it 'publishes the event from the server' do
+ expect(server).to receive(:publish).with(Mongo::Event::SERVER_ADDED, 'test')
+ handler.handle('test')
+ end
+ end
+end
View
20 spec/mongo/event/host_removed_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe Mongo::Event::HostRemoved do
+
+ describe '#handle' do
+
+ let(:server) do
+ double('server')
+ end
+
+ let(:handler) do
+ described_class.new(server)
+ end
+
+ it 'publishes the event from the server' do
+ expect(server).to receive(:publish).with(Mongo::Event::SERVER_REMOVED, 'test')
+ handler.handle('test')
+ end
+ end
+end
View
73 spec/mongo/server/description_spec.rb
@@ -8,14 +8,14 @@
'ismaster' => true,
'secondary' => false,
'hosts' => [
- '127.0.0.1:27118',
- '127.0.0.1:27119'
+ '127.0.0.1:27018',
+ '127.0.0.1:27019'
],
'arbiters' => [
'127.0.0.1:27120'
],
- 'primary' => '127.0.0.1:27119',
- 'me' => '127.0.0.1:27119',
+ 'primary' => '127.0.0.1:27019',
+ 'me' => '127.0.0.1:27019',
'maxBsonObjectSize' => 16777216,
'maxMessageSizeBytes' => 48000000,
'ok' => 1
@@ -104,7 +104,7 @@
end
it 'returns all the hosts in the replica set' do
- expect(description.hosts).to eq([ '127.0.0.1:27118', '127.0.0.1:27119' ])
+ expect(description.hosts).to eq([ '127.0.0.1:27018', '127.0.0.1:27019' ])
end
end
@@ -229,4 +229,67 @@
end
end
end
+
+ describe 'update!' do
+
+ let(:config) do
+ {
+ 'ismaster' => true,
+ 'secondary' => false,
+ 'hosts' => [ '127.0.0.1:27018', '127.0.0.1:27019' ]
+ }
+ end
+
+ let(:listener) do
+ double('listener')
+ end
+
+ context 'when a server is added' do
+
+ let(:new) do
+ { 'hosts' => [ '127.0.0.1:27019', '127.0.0.1:27020' ] }
+ end
+
+ let(:description) do
+ described_class.new(config)
+ end
+
+ let(:updated) do
+ description.update!(new)
+ end
+
+ before do
+ description.add_listener(Mongo::Event::HOST_ADDED, listener)
+ end
+
+ it 'fires a server added event' do
+ expect(listener).to receive(:handle).with('127.0.0.1:27020')
+ expect(updated.hosts).to eq([ '127.0.0.1:27019', '127.0.0.1:27020' ])
+ end
+ end
+
+ context 'when a server is removed' do
+
+ let(:new) do
+ { 'hosts' => [ '127.0.0.1:27019', '127.0.0.1:27020' ] }
+ end
+
+ let(:description) do
+ described_class.new(config)
+ end
+
+ let(:updated) do
+ description.update!(new)
+ end
+
+ before do
+ description.add_listener(Mongo::Event::HOST_REMOVED, listener)
+ end
+
+ it 'fires a server added event' do
+ expect(listener).to receive(:handle).with('127.0.0.1:27018')
+ expect(updated.hosts).to eq([ '127.0.0.1:27019', '127.0.0.1:27020' ])
+ end
+ end
+ end
end
Please sign in to comment.
Something went wrong with that request. Please try again.