Skip to content

Commit 6ca1a03

Browse files
RUBY-2869 Do not use mutexes in finalizers
1 parent 5e91bac commit 6ca1a03

File tree

3 files changed

+45
-7
lines changed

3 files changed

+45
-7
lines changed

lib/mongo/cluster/reapers/cursor_reaper.rb

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def initialize(cluster)
4444
@to_kill = {}
4545
@active_cursor_ids = Set.new
4646
@mutex = Mutex.new
47+
@pipe_read, @pipe_write = IO.pipe
4748
end
4849

4950
attr_reader :cluster
@@ -56,12 +57,14 @@ def initialize(cluster)
5657
#
5758
# @api private
5859
def schedule_kill_cursor(kill_spec, server)
59-
@mutex.synchronize do
60-
if @active_cursor_ids.include?(kill_spec.cursor_id)
61-
@to_kill[server.address.seed] ||= Set.new
62-
@to_kill[server.address.seed] << kill_spec
63-
end
64-
end
60+
msg = [
61+
server.address.seed,
62+
kill_spec.cursor_id,
63+
kill_spec.coll_name,
64+
kill_spec.db_name,
65+
kill_spec.service_id
66+
].join("\t")
67+
@pipe_write.puts(msg)
6568
end
6669

6770
# Register a cursor id as active.
@@ -110,6 +113,25 @@ def unregister_cursor(id)
110113
end
111114
end
112115

116+
def read_scheduled_kill_specs
117+
while readable_io = IO.select([@pipe_read], nil, nil, 0.1)
118+
msg = readable_io.first[0].gets.strip
119+
seed, cursor_id, coll_name, db_name, service_id = msg.split("\t")
120+
kill_spec = Cursor::KillSpec.new(
121+
cursor_id: cursor_id.to_i,
122+
coll_name: coll_name,
123+
db_name: db_name,
124+
service_id: service_id
125+
)
126+
@mutex.synchronize do
127+
if @active_cursor_ids.include?(kill_spec.cursor_id)
128+
@to_kill[seed] ||= Set.new
129+
@to_kill[seed] << kill_spec
130+
end
131+
end
132+
end
133+
end
134+
113135
# Execute all pending kill cursors operations.
114136
#
115137
# @example Execute pending kill cursors operations.

lib/mongo/cursor/kill_spec.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,18 @@ def initialize(cursor_id:, coll_name:, db_name:, service_id:)
3333
end
3434

3535
attr_reader :cursor_id, :coll_name, :db_name, :service_id
36+
37+
def ==(other)
38+
cursor_id == other.cursor_id && coll_name == other.coll_name && db_name == other.db_name && service_id == other.service_id
39+
end
40+
41+
def eql?(other)
42+
self.==(other)
43+
end
44+
45+
def hash
46+
[cursor_id, coll_name, db_name, service_id].compact.hash
47+
end
3648
end
3749
end
3850
end

spec/mongo/cluster/cursor_reaper_spec.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,22 @@
6161

6262
before do
6363
reaper.schedule_kill_cursor(cursor_kill_spec_1, server)
64+
reaper.read_scheduled_kill_specs
6465
end
6566

6667
it 'initializes the list of op specs to a set' do
6768
expect(to_kill.keys).to eq([ address.seed ])
68-
expect(to_kill[address.seed]).to eq(Set.new([cursor_kill_spec_1]))
69+
expect(to_kill[address.seed]).to contain_exactly(cursor_kill_spec_1)
6970
end
7071
end
7172

7273
context 'when there is a list of ops already for the server' do
7374

7475
before do
7576
reaper.schedule_kill_cursor(cursor_kill_spec_1, server)
77+
reaper.read_scheduled_kill_specs
7678
reaper.schedule_kill_cursor(cursor_kill_spec_2, server)
79+
reaper.read_scheduled_kill_specs
7780
end
7881

7982
it 'adds the op to the server list' do
@@ -85,6 +88,7 @@
8588

8689
before do
8790
reaper.schedule_kill_cursor(cursor_kill_spec_2, server)
91+
reaper.read_scheduled_kill_specs
8892
end
8993

9094
it 'does not allow duplicates ops for a server' do

0 commit comments

Comments
 (0)