Skip to content

Commit b43c044

Browse files
authored
RUBY-1347 Do not use sessions by default in parallel scan. (#974)
* RUBY-1347 Do not use sessions by default in parallel scan. A user is able to explicitly provide a session still, but the driver will execute the parallel scan outside of a session by default. * RUBY-1347 Skip session-requiring tests on old mongods
1 parent e14cea9 commit b43c044

File tree

4 files changed

+164
-16
lines changed

4 files changed

+164
-16
lines changed

lib/mongo/collection/view/readable.rb

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -553,30 +553,34 @@ def server_selector
553553
end
554554

555555
def parallel_scan(cursor_count, options = {})
556-
session = client.send(:get_session, @options)
556+
if options[:session]
557+
session = client.send(:get_session, @options)
558+
else
559+
session = nil
560+
end
557561
server = server_selector.select_server(cluster)
558562
cmd = Operation::ParallelScan.new({
559563
:coll_name => collection.name,
560564
:db_name => database.name,
561565
:cursor_count => cursor_count,
562566
:read_concern => collection.read_concern,
563-
:session => session
567+
:session => session,
564568
}.merge!(options))
565569
cmd.execute(server).cursor_ids.map do |cursor_id|
566570
result = if server.features.find_command_enabled?
567-
Operation::GetMore.new({
568-
:selector => {:getMore => cursor_id,
569-
:collection => collection.name},
570-
:db_name => database.name,
571-
:session => session
572-
}).execute(server)
573-
else
574-
Operation::GetMore.new({
575-
:to_return => 0,
576-
:cursor_id => cursor_id,
577-
:db_name => database.name,
578-
:coll_name => collection.name
579-
}).execute(server)
571+
Operation::GetMore.new({
572+
:selector => {:getMore => cursor_id,
573+
:collection => collection.name},
574+
:db_name => database.name,
575+
:session => session,
576+
}).execute(server)
577+
else
578+
Operation::GetMore.new({
579+
:to_return => 0,
580+
:cursor_id => cursor_id,
581+
:db_name => database.name,
582+
:coll_name => collection.name
583+
}).execute(server)
580584
end
581585
Cursor.new(self, result, server, session: session)
582586
end

spec/mongo/collection_spec.rb

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2376,6 +2376,33 @@ def generate
23762376
it_behaves_like 'a failed operation using a session'
23772377
end
23782378

2379+
context 'when a session is not provided' do
2380+
let(:client) { subscribed_client }
2381+
let(:collection) { client['test'] }
2382+
2383+
let(:cursors) do
2384+
collection.parallel_scan(2)
2385+
end
2386+
2387+
let(:operation) do
2388+
cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
2389+
end
2390+
2391+
let(:failed_operation) do
2392+
collection.parallel_scan(-2)
2393+
end
2394+
2395+
let(:command) do
2396+
operation
2397+
event = EventSubscriber.started_events.find { |cmd| cmd.command_name == 'parallelCollectionScan' }
2398+
expect(event).not_to be_nil
2399+
event.command
2400+
end
2401+
2402+
it_behaves_like 'an operation not using a session'
2403+
it_behaves_like 'a failed operation not using a session'
2404+
end
2405+
23792406
context 'when a session supporting causal consistency is used' do
23802407

23812408
let(:cursors) do
@@ -2388,7 +2415,9 @@ def generate
23882415

23892416
let(:command) do
23902417
operation
2391-
EventSubscriber.started_events.find { |cmd| cmd.command_name == 'parallelCollectionScan' }.command
2418+
event = EventSubscriber.started_events.find { |cmd| cmd.command_name == 'parallelCollectionScan' }
2419+
expect(event).not_to be_nil
2420+
event.command
23922421
end
23932422

23942423
it_behaves_like 'an operation supporting causally consistent reads'

spec/support/constraints.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ def min_server_version(version)
1414
end
1515
end
1616

17+
def require_sessions
18+
before do
19+
unless sessions_enabled?
20+
skip 'Sessions are not enabled'
21+
end
22+
end
23+
end
24+
1725
def require_topology(*topologies)
1826
topologies = topologies.map { |t| t.to_s }
1927
invalid_topologies = topologies - %w(single replica_set sharded)

spec/support/shared/session.rb

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,3 +756,110 @@
756756
end
757757
end
758758
end
759+
760+
shared_examples 'an operation not using a session' do
761+
require_sessions
762+
763+
describe 'operation execution' do
764+
765+
context 'when the client has a session' do
766+
767+
let(:session) do
768+
client.start_session
769+
end
770+
771+
let(:server_session) do
772+
session.instance_variable_get(:@server_session)
773+
end
774+
775+
let!(:before_last_use) do
776+
server_session.last_use
777+
end
778+
779+
let!(:before_operation_time) do
780+
session.operation_time
781+
end
782+
783+
let!(:operation_result) do
784+
operation
785+
end
786+
787+
after do
788+
session.end_session
789+
end
790+
791+
it 'does not send session id in command' do
792+
expect(command).not_to have_key('lsid')
793+
end
794+
795+
it 'does not update the last use value' do
796+
expect(server_session.last_use).to eq(before_last_use)
797+
end
798+
799+
it 'does not update the operation time value' do
800+
expect(session.operation_time).to eq(before_operation_time)
801+
end
802+
803+
it 'does not close the session when the operation completes' do
804+
expect(session.ended?).to be(false)
805+
end
806+
end
807+
808+
context 'when the session is ended before it is used' do
809+
let(:session) do
810+
client.start_session
811+
end
812+
813+
before do
814+
session.end_session
815+
end
816+
817+
let(:operation_result) do
818+
operation
819+
end
820+
821+
it 'does not raise an exception' do
822+
expect {
823+
operation_result
824+
}.not_to raise_exception(Mongo::Error::InvalidSession)
825+
end
826+
end
827+
end
828+
end
829+
830+
shared_examples 'a failed operation not using a session' do
831+
require_sessions
832+
833+
context 'when the operation fails' do
834+
835+
let!(:before_last_use) do
836+
session.instance_variable_get(:@server_session).last_use
837+
end
838+
839+
let!(:before_operation_time) do
840+
session.operation_time
841+
end
842+
843+
let!(:operation_result) do
844+
sleep 0.2
845+
begin; failed_operation; rescue => e; e; end
846+
end
847+
848+
let(:session) do
849+
client.start_session
850+
end
851+
852+
it 'raises an error' do
853+
expect([Mongo::Error::OperationFailure,
854+
Mongo::Error::BulkWriteError]).to include(operation_result.class)
855+
end
856+
857+
it 'does not update the last use value' do
858+
expect(session.instance_variable_get(:@server_session).last_use).to eq(before_last_use)
859+
end
860+
861+
it 'does not update the operation time value' do
862+
expect(session.operation_time).to eq(before_operation_time)
863+
end
864+
end
865+
end

0 commit comments

Comments
 (0)