From 199a672dd9b3e5657f971333f5c3a885e4a8920f Mon Sep 17 00:00:00 2001 From: Robert Sedlacek Date: Thu, 19 Apr 2018 21:25:47 +0200 Subject: [PATCH 1/5] Add maxTimeMS option to IndexView's create_one, create_many, drop_one and drop_all. API Changes: * Last value of create_many is now an optional hash reference with global options. * create_one received an additional maxTimeMS option. * drop_one and drop_all now accept an options hash reference with maxTimeMS. --- lib/MongoDB/IndexView.pm | 54 ++++++- lib/MongoDB/Op/_CreateIndexes.pm | 12 +- lib/MongoDB/Op/_DropIndexes.pm | 10 ++ t/indexview.t | 268 +++++++++++++++++++++++++++++++ 4 files changed, 339 insertions(+), 5 deletions(-) diff --git a/lib/MongoDB/IndexView.pm b/lib/MongoDB/IndexView.pm index e72fe079..f6769ace 100644 --- a/lib/MongoDB/IndexView.pm +++ b/lib/MongoDB/IndexView.pm @@ -183,8 +183,15 @@ sub create_one { MongoDB::UsageError->throw("Argument to create_one must be an ordered document") unless is_OrderedDoc($keys); - my ($name) = - $self->create_many( { keys => $keys, ( $opts ? ( options => $opts ) : () ) } ); + my $global_opts = {}; + if (exists $opts->{maxTimeMS}) { + $global_opts->{maxTimeMS} = delete $opts->{maxTimeMS}; + } + + my ($name) = $self->create_many( + { keys => $keys, ( $opts ? ( options => $opts ) : () ) }, + $global_opts, + ); return $name; } @@ -195,10 +202,20 @@ sub create_one { { keys => [ z => 1 ], options => { unique => 1 } } ); + @names = $indexes->create_many( + { keys => [ x => 1, y => 1 ] }, + { keys => [ z => 1 ], options => { unique => 1 } } + \%global_options, + ); + This method takes a list of index models (given as hash references) and returns a list of index names created. It will throw an exception on error. +If the last value is a hash reference without a C entry, it will +be assumed to be a set of global options. See below for a list of +accepted global options. + Each index module is described by the following fields: =for :list @@ -242,6 +259,13 @@ Some of the more commonly used options include: * C — a name (string) for the index; one will be generated if this is omitted. +Global options specified as the last value can contain the following +keys: + +=for :list +* C — maximum time in milliseconds before the operation will + time out. + =cut my $create_many_args; @@ -249,6 +273,11 @@ my $create_many_args; sub create_many { my ( $self, @models ) = @_; + my $opts; + if (@models and ref $models[-1] eq 'HASH' and not exists $models[-1]{keys}) { + $opts = pop @models; + } + MongoDB::UsageError->throw("Argument to create_many must be a list of index models") unless is_IndexModelList(\@models); @@ -260,6 +289,7 @@ sub create_many { bson_codec => $self->_bson_codec, indexes => $indexes, write_concern => $self->_write_concern, + max_time_ms => $opts->{maxTimeMS}, ); # succeed or die; we don't care about response document @@ -271,6 +301,7 @@ sub create_many { =method drop_one $output = $indexes->drop_one( $name ); + $output = $indexes->drop_one( $name, \%options ); This method takes the name of an index and drops it. It returns the output of the dropIndexes command (a hash reference) on success or throws a @@ -278,12 +309,18 @@ exception if the command errors. However, if the index does not exist, the command output will have the C field as a false value, but no exception will e thrown. +Valid options are: + +=for :list +* C — maximum time in milliseconds before the operation will + time out. + =cut my $drop_one_args; sub drop_one { - my ( $self, $name ) = @_; + my ( $self, $name, $opts ) = @_; MongoDB::UsageError->throw("Argument to drop_one must be a string") unless is_Str($name); @@ -299,6 +336,7 @@ sub drop_one { bson_codec => $self->_bson_codec, write_concern => $self->_write_concern, index_name => $name, + max_time_ms => $opts->{maxTimeMS}, ); $self->_client->send_write_op($op)->output; @@ -307,17 +345,24 @@ sub drop_one { =method drop_all $output = $indexes->drop_all; + $output = $indexes->drop_all(\%options); This method drops all indexes (except the one on the C<_id> field). It returns the output of the dropIndexes command (a hash reference) on success or throws a exception if the command fails. +Valid options are: + +=for :list +* C — maximum time in milliseconds before the operation will + time out. + =cut my $drop_all_args; sub drop_all { - my ($self) = @_; + my ($self, $opts) = @_; my $op = MongoDB::Op::_DropIndexes->_new( db_name => $self->_db_name, @@ -326,6 +371,7 @@ sub drop_all { bson_codec => $self->_bson_codec, write_concern => $self->_write_concern, index_name => '*', + max_time_ms => $opts->{maxTimeMS}, ); $self->_client->send_write_op($op)->output; diff --git a/lib/MongoDB/Op/_CreateIndexes.pm b/lib/MongoDB/Op/_CreateIndexes.pm index 51c1051f..d832e598 100644 --- a/lib/MongoDB/Op/_CreateIndexes.pm +++ b/lib/MongoDB/Op/_CreateIndexes.pm @@ -32,6 +32,7 @@ use Types::Standard qw( ArrayRef Bool HashRef + Num ); use namespace::clean; @@ -42,6 +43,11 @@ has indexes => ( isa => ArrayRef [HashRef], ); +has max_time_ms => ( + is => 'ro', + isa => Num, +); + with $_ for qw( MongoDB::Role::_PrivateConstructor MongoDB::Role::_CollectionOp @@ -76,7 +82,11 @@ sub _command_create_indexes { query => [ createIndexes => $self->coll_name, indexes => $self->indexes, - ( $link->accepts_wire_version(5) ? ( @{ $self->write_concern->as_args } ) : () ) + ( $link->accepts_wire_version(5) ? ( @{ $self->write_concern->as_args } ) : () ), + (defined($self->max_time_ms) + ? (maxTimeMS => $self->max_time_ms) + : () + ), ], query_flags => {}, bson_codec => $self->bson_codec, diff --git a/lib/MongoDB/Op/_DropIndexes.pm b/lib/MongoDB/Op/_DropIndexes.pm index 04ad2d04..c7d6e576 100644 --- a/lib/MongoDB/Op/_DropIndexes.pm +++ b/lib/MongoDB/Op/_DropIndexes.pm @@ -30,6 +30,7 @@ use MongoDB::Op::_Command; use Safe::Isa; use Types::Standard qw( Str + Num ); use namespace::clean; @@ -40,6 +41,11 @@ has index_name => ( isa => Str, ); +has max_time_ms => ( + is => 'ro', + isa => Num, +); + with $_ for qw( MongoDB::Role::_PrivateConstructor MongoDB::Role::_CollectionOp @@ -55,6 +61,10 @@ sub execute { dropIndexes => $self->coll_name, index => $self->index_name, ( $link->accepts_wire_version(5) ? ( @{ $self->write_concern->as_args } ) : () ), + (defined($self->max_time_ms) + ? (maxTimeMS => $self->max_time_ms) + : () + ), ], query_flags => {}, bson_codec => $self->bson_codec, diff --git a/t/indexview.t b/t/indexview.t index 90a4d76f..9332a1cf 100644 --- a/t/indexview.t +++ b/t/indexview.t @@ -35,12 +35,18 @@ my $testdb = get_test_db($conn); my $server_version = server_version($conn); my $server_type = server_type($conn); my $coll = $testdb->get_collection('test_collection'); +my $admin = $conn->get_database("admin"); my $supports_collation = $server_version >= 3.3.9; my $valid_collation = { locale => "en_US", strength => 2 }; my $valid_collation_alternate = { locale => "fr_CA" }; my $invalid_collation = { locale => "en_US", blah => 5 }; +my $param = eval { + $conn->get_database('admin') + ->run_command( [ getParameter => 1, enableTestCommands => 1 ] ); +}; + my ($iv); # XXX work around SERVER-18062; create collection to initialize DB for @@ -108,6 +114,76 @@ subtest "create_many" => sub { } }; +subtest "create_many w/ maxTimeMS" => sub { + plan skip_all => "maxTimeMS not available before 3.6" + unless $server_version >= v3.6.0; + + plan skip_all => "enableTestCommands is off" + unless $param && $param->{enableTestCommands}; + + plan skip_all => "fail points not supported via mongos" + if $server_type eq 'Mongos'; + + plan skip_all => "not safe to run fail points before Test::Harness 3.31" + if version->parse($ENV{HARNESS_VERSION}) < version->parse(3.31); + + $coll->drop; + + is( + exception { + $admin->run_command([ + configureFailPoint => 'maxTimeAlwaysTimeOut', + mode => 'alwaysOn', + ]); + }, + undef, + 'max time failpoint on', + ); + + like( + exception { + $iv->create_many( + { keys => [ x => 1 ] }, { keys => [ y => -1 ] }, + { maxTimeMS => 10 }, + ); + }, + qr/exceeded time limit/, + 'timeout for index creation', + ); + + is( + exception { + $iv->create_many( + { keys => [ x => 1 ] }, { keys => [ y => -1 ] }, + ); + }, + undef, + 'no timeout without max time', + ); + + is( + exception { + $admin->run_command([ + configureFailPoint => 'maxTimeAlwaysTimeOut', + mode => 'off', + ]); + }, + undef, + 'max time failpoint off', + ); + + is( + exception { + $iv->create_many( + { keys => [ x => 1 ] }, { keys => [ y => -1 ] }, + { maxTimeMS => 5000 }, + ); + }, + undef, + 'no timeout for index creation', + ); +}; + subtest "list indexes" => sub { $coll->drop; $coll->insert_one( {} ); @@ -188,6 +264,68 @@ subtest "create_one" => sub { } }; +subtest "create_one w/ maxTimeMS" => sub { + plan skip_all => "maxTimeMS not available before 3.6" + unless $server_version >= v3.6.0; + + plan skip_all => "enableTestCommands is off" + unless $param && $param->{enableTestCommands}; + + plan skip_all => "fail points not supported via mongos" + if $server_type eq 'Mongos'; + + plan skip_all => "not safe to run fail points before Test::Harness 3.31" + if version->parse($ENV{HARNESS_VERSION}) < version->parse(3.31); + + $coll->drop; + + is( + exception { + $admin->run_command([ + configureFailPoint => 'maxTimeAlwaysTimeOut', + mode => 'alwaysOn', + ]); + }, + undef, + 'max time failpoint on', + ); + + is( + exception { + $iv->create_one([ x => 1 ]); + }, + undef, + 'no timeout without max time', + ); + + like( + exception { + $iv->create_one([ x => 1 ], { maxTimeMS => 10 }); + }, + qr/exceeded time limit/, + 'timeout for index creation', + ); + + is( + exception { + $admin->run_command([ + configureFailPoint => 'maxTimeAlwaysTimeOut', + mode => 'off', + ]); + }, + undef, + 'max time failpoint off', + ); + + is( + exception { + $iv->create_one([ x => 1 ], { maxTimeMS => 5000 }); + }, + undef, + 'no timeout for index creation', + ); +}; + subtest "drop_one" => sub { $coll->drop; ok( my $name = $iv->create_one( [ x => 1 ] ), "created index on x" ); @@ -224,6 +362,71 @@ subtest "drop_one" => sub { ); }; +subtest "drop_one w/ maxTimeMS" => sub { + plan skip_all => "maxTimeMS not available before 3.6" + unless $server_version >= v3.6.0; + + plan skip_all => "enableTestCommands is off" + unless $param && $param->{enableTestCommands}; + + plan skip_all => "fail points not supported via mongos" + if $server_type eq 'Mongos'; + + plan skip_all => "not safe to run fail points before Test::Harness 3.31" + if version->parse($ENV{HARNESS_VERSION}) < version->parse(3.31); + + $coll->drop; + + is( + exception { + $admin->run_command([ + configureFailPoint => 'maxTimeAlwaysTimeOut', + mode => 'alwaysOn', + ]); + }, + undef, + 'max time failpoint on', + ); + + is( + exception { + my $name = $iv->create_one([ x => 1 ]); + $iv->drop_one($name); + }, + undef, + 'no timeout without max time', + ); + + like( + exception { + my $name = $iv->create_one([ x => 1 ]); + $iv->drop_one($name, { maxTimeMS => 10 }); + }, + qr/exceeded time limit/, + 'timeout for index drop', + ); + + is( + exception { + $admin->run_command([ + configureFailPoint => 'maxTimeAlwaysTimeOut', + mode => 'off', + ]); + }, + undef, + 'max time failpoint off', + ); + + is( + exception { + my $name = $iv->create_one([ x => 1 ]); + $iv->drop_one($name, { maxTimeMS => 5000 }); + }, + undef, + 'no timeout for index drop', + ); +}; + subtest "drop_all" => sub { $coll->drop; $iv->create_many( map { { keys => $_ } }[ x => 1 ], [ y => 1 ], [ z => 1 ] ); @@ -240,6 +443,71 @@ subtest "drop_all" => sub { }; +subtest "drop_all w/ maxTimeMS" => sub { + plan skip_all => "maxTimeMS not available before 3.6" + unless $server_version >= v3.6.0; + + plan skip_all => "enableTestCommands is off" + unless $param && $param->{enableTestCommands}; + + plan skip_all => "fail points not supported via mongos" + if $server_type eq 'Mongos'; + + plan skip_all => "not safe to run fail points before Test::Harness 3.31" + if version->parse($ENV{HARNESS_VERSION}) < version->parse(3.31); + + $coll->drop; + + is( + exception { + $admin->run_command([ + configureFailPoint => 'maxTimeAlwaysTimeOut', + mode => 'alwaysOn', + ]); + }, + undef, + 'max time failpoint on', + ); + + is( + exception { + $iv->create_many( map { { keys => $_ } }[ x => 1 ], [ y => 1 ], [ z => 1 ] ); + $iv->drop_all(); + }, + undef, + 'no timeout without max time', + ); + + like( + exception { + $iv->create_many( map { { keys => $_ } }[ x => 1 ], [ y => 1 ], [ z => 1 ] ); + $iv->drop_all({ maxTimeMS => 10 }); + }, + qr/exceeded time limit/, + 'timeout for index drop', + ); + + is( + exception { + $admin->run_command([ + configureFailPoint => 'maxTimeAlwaysTimeOut', + mode => 'off', + ]); + }, + undef, + 'max time failpoint off', + ); + + is( + exception { + $iv->create_many( map { { keys => $_ } }[ x => 1 ], [ y => 1 ], [ z => 1 ] ); + $iv->drop_all({ maxTimeMS => 5000 }); + }, + undef, + 'no timeout for index drop', + ); +}; + subtest 'handling duplicates' => sub { $coll->drop; my $doc = { foo => 1, bar => 1, baz => 1, boo => 1 }; From 4aa39dc651ba779c9e934c637f19473c9dd11883 Mon Sep 17 00:00:00 2001 From: Robert Sedlacek Date: Tue, 24 Apr 2018 17:09:25 +0200 Subject: [PATCH 2/5] Add test guard for FAILPOINT_TESTING to maxTimeMS tests using failpoints --- t/indexview.t | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/t/indexview.t b/t/indexview.t index 9332a1cf..049e4969 100644 --- a/t/indexview.t +++ b/t/indexview.t @@ -115,6 +115,9 @@ subtest "create_many" => sub { }; subtest "create_many w/ maxTimeMS" => sub { + plan skip_all => "\$ENV{FAILPOINT_TESTING} is false" + unless $ENV{FAILPOINT_TESTING}; + plan skip_all => "maxTimeMS not available before 3.6" unless $server_version >= v3.6.0; @@ -265,6 +268,9 @@ subtest "create_one" => sub { }; subtest "create_one w/ maxTimeMS" => sub { + plan skip_all => "\$ENV{FAILPOINT_TESTING} is false" + unless $ENV{FAILPOINT_TESTING}; + plan skip_all => "maxTimeMS not available before 3.6" unless $server_version >= v3.6.0; @@ -363,6 +369,9 @@ subtest "drop_one" => sub { }; subtest "drop_one w/ maxTimeMS" => sub { + plan skip_all => "\$ENV{FAILPOINT_TESTING} is false" + unless $ENV{FAILPOINT_TESTING}; + plan skip_all => "maxTimeMS not available before 3.6" unless $server_version >= v3.6.0; @@ -444,6 +453,9 @@ subtest "drop_all" => sub { }; subtest "drop_all w/ maxTimeMS" => sub { + plan skip_all => "\$ENV{FAILPOINT_TESTING} is false" + unless $ENV{FAILPOINT_TESTING}; + plan skip_all => "maxTimeMS not available before 3.6" unless $server_version >= v3.6.0; From 658436e185a4cc76aa3289d423f17b91b2119834 Mon Sep 17 00:00:00 2001 From: Robert Sedlacek Date: Tue, 24 Apr 2018 17:33:49 +0200 Subject: [PATCH 3/5] Fix undef max_time_ms option being passed on to ops --- lib/MongoDB/IndexView.pm | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/MongoDB/IndexView.pm b/lib/MongoDB/IndexView.pm index f6769ace..de687359 100644 --- a/lib/MongoDB/IndexView.pm +++ b/lib/MongoDB/IndexView.pm @@ -289,7 +289,10 @@ sub create_many { bson_codec => $self->_bson_codec, indexes => $indexes, write_concern => $self->_write_concern, - max_time_ms => $opts->{maxTimeMS}, + (defined($opts->{maxTimeMS}) + ? (max_time_ms => $opts->{maxTimeMS}) + : () + ), ); # succeed or die; we don't care about response document @@ -336,7 +339,10 @@ sub drop_one { bson_codec => $self->_bson_codec, write_concern => $self->_write_concern, index_name => $name, - max_time_ms => $opts->{maxTimeMS}, + (defined($opts->{maxTimeMS}) + ? (max_time_ms => $opts->{maxTimeMS}) + : () + ), ); $self->_client->send_write_op($op)->output; @@ -371,7 +377,10 @@ sub drop_all { bson_codec => $self->_bson_codec, write_concern => $self->_write_concern, index_name => '*', - max_time_ms => $opts->{maxTimeMS}, + (defined($opts->{maxTimeMS}) + ? (max_time_ms => $opts->{maxTimeMS}) + : () + ), ); $self->_client->send_write_op($op)->output; From c4c735d23ba53eb9fd9b7ac9540e964650dc2065 Mon Sep 17 00:00:00 2001 From: Robert Sedlacek Date: Thu, 3 May 2018 17:35:54 +0200 Subject: [PATCH 4/5] Added documentation about additional options for create_one, currently 'maxTimeMS' --- lib/MongoDB/IndexView.pm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/MongoDB/IndexView.pm b/lib/MongoDB/IndexView.pm index de687359..a9b70172 100644 --- a/lib/MongoDB/IndexView.pm +++ b/lib/MongoDB/IndexView.pm @@ -173,6 +173,12 @@ direction/type. See L for important information about index specifications and options. +The following additional options are recognized: + +=for :list +* C — maximum time in milliseconds before the operation will + time out. + =cut my $create_one_args; From e3c3f972619548d698b65479354ee7e2ebe9b994 Mon Sep 17 00:00:00 2001 From: Robert Sedlacek Date: Thu, 3 May 2018 17:36:44 +0200 Subject: [PATCH 5/5] Move IndexView maxTimeMS tests from indexview.t to max_time_ms.t --- t/indexview.t | 279 ------------------------------------------------ t/max_time_ms.t | 252 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+), 279 deletions(-) diff --git a/t/indexview.t b/t/indexview.t index 049e4969..df61ff93 100644 --- a/t/indexview.t +++ b/t/indexview.t @@ -42,11 +42,6 @@ my $valid_collation = { locale => "en_US", strength => 2 }; my $valid_collation_alternate = { locale => "fr_CA" }; my $invalid_collation = { locale => "en_US", blah => 5 }; -my $param = eval { - $conn->get_database('admin') - ->run_command( [ getParameter => 1, enableTestCommands => 1 ] ); -}; - my ($iv); # XXX work around SERVER-18062; create collection to initialize DB for @@ -114,79 +109,6 @@ subtest "create_many" => sub { } }; -subtest "create_many w/ maxTimeMS" => sub { - plan skip_all => "\$ENV{FAILPOINT_TESTING} is false" - unless $ENV{FAILPOINT_TESTING}; - - plan skip_all => "maxTimeMS not available before 3.6" - unless $server_version >= v3.6.0; - - plan skip_all => "enableTestCommands is off" - unless $param && $param->{enableTestCommands}; - - plan skip_all => "fail points not supported via mongos" - if $server_type eq 'Mongos'; - - plan skip_all => "not safe to run fail points before Test::Harness 3.31" - if version->parse($ENV{HARNESS_VERSION}) < version->parse(3.31); - - $coll->drop; - - is( - exception { - $admin->run_command([ - configureFailPoint => 'maxTimeAlwaysTimeOut', - mode => 'alwaysOn', - ]); - }, - undef, - 'max time failpoint on', - ); - - like( - exception { - $iv->create_many( - { keys => [ x => 1 ] }, { keys => [ y => -1 ] }, - { maxTimeMS => 10 }, - ); - }, - qr/exceeded time limit/, - 'timeout for index creation', - ); - - is( - exception { - $iv->create_many( - { keys => [ x => 1 ] }, { keys => [ y => -1 ] }, - ); - }, - undef, - 'no timeout without max time', - ); - - is( - exception { - $admin->run_command([ - configureFailPoint => 'maxTimeAlwaysTimeOut', - mode => 'off', - ]); - }, - undef, - 'max time failpoint off', - ); - - is( - exception { - $iv->create_many( - { keys => [ x => 1 ] }, { keys => [ y => -1 ] }, - { maxTimeMS => 5000 }, - ); - }, - undef, - 'no timeout for index creation', - ); -}; - subtest "list indexes" => sub { $coll->drop; $coll->insert_one( {} ); @@ -267,71 +189,6 @@ subtest "create_one" => sub { } }; -subtest "create_one w/ maxTimeMS" => sub { - plan skip_all => "\$ENV{FAILPOINT_TESTING} is false" - unless $ENV{FAILPOINT_TESTING}; - - plan skip_all => "maxTimeMS not available before 3.6" - unless $server_version >= v3.6.0; - - plan skip_all => "enableTestCommands is off" - unless $param && $param->{enableTestCommands}; - - plan skip_all => "fail points not supported via mongos" - if $server_type eq 'Mongos'; - - plan skip_all => "not safe to run fail points before Test::Harness 3.31" - if version->parse($ENV{HARNESS_VERSION}) < version->parse(3.31); - - $coll->drop; - - is( - exception { - $admin->run_command([ - configureFailPoint => 'maxTimeAlwaysTimeOut', - mode => 'alwaysOn', - ]); - }, - undef, - 'max time failpoint on', - ); - - is( - exception { - $iv->create_one([ x => 1 ]); - }, - undef, - 'no timeout without max time', - ); - - like( - exception { - $iv->create_one([ x => 1 ], { maxTimeMS => 10 }); - }, - qr/exceeded time limit/, - 'timeout for index creation', - ); - - is( - exception { - $admin->run_command([ - configureFailPoint => 'maxTimeAlwaysTimeOut', - mode => 'off', - ]); - }, - undef, - 'max time failpoint off', - ); - - is( - exception { - $iv->create_one([ x => 1 ], { maxTimeMS => 5000 }); - }, - undef, - 'no timeout for index creation', - ); -}; - subtest "drop_one" => sub { $coll->drop; ok( my $name = $iv->create_one( [ x => 1 ] ), "created index on x" ); @@ -368,74 +225,6 @@ subtest "drop_one" => sub { ); }; -subtest "drop_one w/ maxTimeMS" => sub { - plan skip_all => "\$ENV{FAILPOINT_TESTING} is false" - unless $ENV{FAILPOINT_TESTING}; - - plan skip_all => "maxTimeMS not available before 3.6" - unless $server_version >= v3.6.0; - - plan skip_all => "enableTestCommands is off" - unless $param && $param->{enableTestCommands}; - - plan skip_all => "fail points not supported via mongos" - if $server_type eq 'Mongos'; - - plan skip_all => "not safe to run fail points before Test::Harness 3.31" - if version->parse($ENV{HARNESS_VERSION}) < version->parse(3.31); - - $coll->drop; - - is( - exception { - $admin->run_command([ - configureFailPoint => 'maxTimeAlwaysTimeOut', - mode => 'alwaysOn', - ]); - }, - undef, - 'max time failpoint on', - ); - - is( - exception { - my $name = $iv->create_one([ x => 1 ]); - $iv->drop_one($name); - }, - undef, - 'no timeout without max time', - ); - - like( - exception { - my $name = $iv->create_one([ x => 1 ]); - $iv->drop_one($name, { maxTimeMS => 10 }); - }, - qr/exceeded time limit/, - 'timeout for index drop', - ); - - is( - exception { - $admin->run_command([ - configureFailPoint => 'maxTimeAlwaysTimeOut', - mode => 'off', - ]); - }, - undef, - 'max time failpoint off', - ); - - is( - exception { - my $name = $iv->create_one([ x => 1 ]); - $iv->drop_one($name, { maxTimeMS => 5000 }); - }, - undef, - 'no timeout for index drop', - ); -}; - subtest "drop_all" => sub { $coll->drop; $iv->create_many( map { { keys => $_ } }[ x => 1 ], [ y => 1 ], [ z => 1 ] ); @@ -452,74 +241,6 @@ subtest "drop_all" => sub { }; -subtest "drop_all w/ maxTimeMS" => sub { - plan skip_all => "\$ENV{FAILPOINT_TESTING} is false" - unless $ENV{FAILPOINT_TESTING}; - - plan skip_all => "maxTimeMS not available before 3.6" - unless $server_version >= v3.6.0; - - plan skip_all => "enableTestCommands is off" - unless $param && $param->{enableTestCommands}; - - plan skip_all => "fail points not supported via mongos" - if $server_type eq 'Mongos'; - - plan skip_all => "not safe to run fail points before Test::Harness 3.31" - if version->parse($ENV{HARNESS_VERSION}) < version->parse(3.31); - - $coll->drop; - - is( - exception { - $admin->run_command([ - configureFailPoint => 'maxTimeAlwaysTimeOut', - mode => 'alwaysOn', - ]); - }, - undef, - 'max time failpoint on', - ); - - is( - exception { - $iv->create_many( map { { keys => $_ } }[ x => 1 ], [ y => 1 ], [ z => 1 ] ); - $iv->drop_all(); - }, - undef, - 'no timeout without max time', - ); - - like( - exception { - $iv->create_many( map { { keys => $_ } }[ x => 1 ], [ y => 1 ], [ z => 1 ] ); - $iv->drop_all({ maxTimeMS => 10 }); - }, - qr/exceeded time limit/, - 'timeout for index drop', - ); - - is( - exception { - $admin->run_command([ - configureFailPoint => 'maxTimeAlwaysTimeOut', - mode => 'off', - ]); - }, - undef, - 'max time failpoint off', - ); - - is( - exception { - $iv->create_many( map { { keys => $_ } }[ x => 1 ], [ y => 1 ], [ z => 1 ] ); - $iv->drop_all({ maxTimeMS => 5000 }); - }, - undef, - 'no timeout for index drop', - ); -}; - subtest 'handling duplicates' => sub { $coll->drop; my $doc = { foo => 1, bar => 1, baz => 1, boo => 1 }; diff --git a/t/max_time_ms.t b/t/max_time_ms.t index f387e5da..8ca77957 100644 --- a/t/max_time_ms.t +++ b/t/max_time_ms.t @@ -64,6 +64,8 @@ $bulk->insert_one( { _id => $_ } ) for 1 .. 20; my $err = exception { $bulk->execute }; is( $err, undef, "inserted 20 documents for testing" ); +my $iv = $coll->indexes; + subtest "expected behaviors" => sub { is( exception { $coll->find->max_time_ms()->next }, undef, "find->max_time_ms()" ); @@ -429,4 +431,254 @@ subtest "force maxTimeMS failures" => sub { ); }; +subtest "create_many w/ maxTimeMS" => sub { + plan skip_all => "maxTimeMS not available before 3.6" + unless $server_version >= v3.6.0; + + plan skip_all => "enableTestCommands is off" + unless $param && $param->{enableTestCommands}; + + plan skip_all => "fail points not supported via mongos" + if $server_type eq 'Mongos'; + + $coll->drop; + + is( + exception { + $admin->run_command([ + configureFailPoint => 'maxTimeAlwaysTimeOut', + mode => 'alwaysOn', + ]); + }, + undef, + 'max time failpoint on', + ); + + like( + exception { + $iv->create_many( + { keys => [ x => 1 ] }, { keys => [ y => -1 ] }, + { maxTimeMS => 10 }, + ); + }, + qr/exceeded time limit/, + 'timeout for index creation', + ); + + is( + exception { + $iv->create_many( + { keys => [ x => 1 ] }, { keys => [ y => -1 ] }, + ); + }, + undef, + 'no timeout without max time', + ); + + is( + exception { + $admin->run_command([ + configureFailPoint => 'maxTimeAlwaysTimeOut', + mode => 'off', + ]); + }, + undef, + 'max time failpoint off', + ); + + is( + exception { + $iv->create_many( + { keys => [ x => 1 ] }, { keys => [ y => -1 ] }, + { maxTimeMS => 5000 }, + ); + }, + undef, + 'no timeout for index creation', + ); +}; + +subtest "create_one w/ maxTimeMS" => sub { + plan skip_all => "maxTimeMS not available before 3.6" + unless $server_version >= v3.6.0; + + plan skip_all => "enableTestCommands is off" + unless $param && $param->{enableTestCommands}; + + plan skip_all => "fail points not supported via mongos" + if $server_type eq 'Mongos'; + + $coll->drop; + + is( + exception { + $admin->run_command([ + configureFailPoint => 'maxTimeAlwaysTimeOut', + mode => 'alwaysOn', + ]); + }, + undef, + 'max time failpoint on', + ); + + is( + exception { + $iv->create_one([ x => 1 ]); + }, + undef, + 'no timeout without max time', + ); + + like( + exception { + $iv->create_one([ x => 1 ], { maxTimeMS => 10 }); + }, + qr/exceeded time limit/, + 'timeout for index creation', + ); + + is( + exception { + $admin->run_command([ + configureFailPoint => 'maxTimeAlwaysTimeOut', + mode => 'off', + ]); + }, + undef, + 'max time failpoint off', + ); + + is( + exception { + $iv->create_one([ x => 1 ], { maxTimeMS => 5000 }); + }, + undef, + 'no timeout for index creation', + ); +}; + +subtest "drop_one w/ maxTimeMS" => sub { + plan skip_all => "maxTimeMS not available before 3.6" + unless $server_version >= v3.6.0; + + plan skip_all => "enableTestCommands is off" + unless $param && $param->{enableTestCommands}; + + plan skip_all => "fail points not supported via mongos" + if $server_type eq 'Mongos'; + + $coll->drop; + + is( + exception { + $admin->run_command([ + configureFailPoint => 'maxTimeAlwaysTimeOut', + mode => 'alwaysOn', + ]); + }, + undef, + 'max time failpoint on', + ); + + is( + exception { + my $name = $iv->create_one([ x => 1 ]); + $iv->drop_one($name); + }, + undef, + 'no timeout without max time', + ); + + like( + exception { + my $name = $iv->create_one([ x => 1 ]); + $iv->drop_one($name, { maxTimeMS => 10 }); + }, + qr/exceeded time limit/, + 'timeout for index drop', + ); + + is( + exception { + $admin->run_command([ + configureFailPoint => 'maxTimeAlwaysTimeOut', + mode => 'off', + ]); + }, + undef, + 'max time failpoint off', + ); + + is( + exception { + my $name = $iv->create_one([ x => 1 ]); + $iv->drop_one($name, { maxTimeMS => 5000 }); + }, + undef, + 'no timeout for index drop', + ); +}; + +subtest "drop_all w/ maxTimeMS" => sub { + plan skip_all => "maxTimeMS not available before 3.6" + unless $server_version >= v3.6.0; + + plan skip_all => "enableTestCommands is off" + unless $param && $param->{enableTestCommands}; + + plan skip_all => "fail points not supported via mongos" + if $server_type eq 'Mongos'; + + $coll->drop; + + is( + exception { + $admin->run_command([ + configureFailPoint => 'maxTimeAlwaysTimeOut', + mode => 'alwaysOn', + ]); + }, + undef, + 'max time failpoint on', + ); + + is( + exception { + $iv->create_many( map { { keys => $_ } }[ x => 1 ], [ y => 1 ], [ z => 1 ] ); + $iv->drop_all(); + }, + undef, + 'no timeout without max time', + ); + + like( + exception { + $iv->create_many( map { { keys => $_ } }[ x => 1 ], [ y => 1 ], [ z => 1 ] ); + $iv->drop_all({ maxTimeMS => 10 }); + }, + qr/exceeded time limit/, + 'timeout for index drop', + ); + + is( + exception { + $admin->run_command([ + configureFailPoint => 'maxTimeAlwaysTimeOut', + mode => 'off', + ]); + }, + undef, + 'max time failpoint off', + ); + + is( + exception { + $iv->create_many( map { { keys => $_ } }[ x => 1 ], [ y => 1 ], [ z => 1 ] ); + $iv->drop_all({ maxTimeMS => 5000 }); + }, + undef, + 'no timeout for index drop', + ); +}; + done_testing;