Skip to content

Commit cb40262

Browse files
committed
PHPLIB-544: Add commitQuorum option to createIndexes
1 parent 85d29db commit cb40262

6 files changed

+113
-1
lines changed

docs/includes/apiargs-MongoDBCollection-method-createIndex-option.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,23 @@
11
arg_name: option
2+
name: commitQuorum
3+
type: string|integer
4+
description: |
5+
Specifies how many data-bearing members of a replica set, including the
6+
primary, must complete the index builds successfully before the primary marks
7+
the indexes as ready.
8+
9+
This option accepts the same values for the "w" field in a write concern plus
10+
"votingMembers", which indicates all voting data-bearing nodes.
11+
12+
This is not supported for server versions prior to 4.4 and will result in an
13+
exception at execution time if used.
14+
15+
.. versionadded:: 1.7
16+
interface: phpmethod
17+
operation: ~
18+
optional: true
19+
---
20+
arg_name: option
221
name: unique
322
type: boolean
423
description: |

docs/includes/apiargs-MongoDBCollection-method-createIndexes-option.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
arg_name: option
2+
name: commitQuorum
3+
type: string|integer
4+
description: |
5+
Specifies how many data-bearing members of a replica set, including the
6+
primary, must complete the index builds successfully before the primary marks
7+
the indexes as ready.
8+
9+
This option accepts the same values for the "w" field in a write concern plus
10+
"votingMembers", which indicates all voting data-bearing nodes.
11+
12+
This is not supported for server versions prior to 4.4 and will result in an
13+
exception at execution time if used.
14+
15+
.. versionadded:: 1.7
16+
interface: phpmethod
17+
operation: ~
18+
optional: true
19+
---
120
source:
221
file: apiargs-common-option.yaml
322
ref: maxTimeMS

src/Collection.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ public function countDocuments($filter = [], array $options = [])
356356
*/
357357
public function createIndex($key, array $options = [])
358358
{
359-
$commandOptionKeys = ['maxTimeMS' => 1, 'session' => 1, 'writeConcern' => 1];
359+
$commandOptionKeys = ['commitQuorum' => 1, 'maxTimeMS' => 1, 'session' => 1, 'writeConcern' => 1];
360360
$indexOptions = array_diff_key($options, $commandOptionKeys);
361361
$commandOptions = array_intersect_key($options, $commandOptionKeys);
362362

src/Operation/CreateIndexes.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
namespace MongoDB\Operation;
1919

2020
use MongoDB\Driver\Command;
21+
use MongoDB\Driver\Exception\CommandException;
2122
use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
2223
use MongoDB\Driver\Server;
2324
use MongoDB\Driver\Session;
@@ -28,6 +29,7 @@
2829
use function array_map;
2930
use function is_array;
3031
use function is_integer;
32+
use function is_string;
3133
use function MongoDB\server_supports_feature;
3234
use function sprintf;
3335

@@ -47,6 +49,9 @@ class CreateIndexes implements Executable
4749
/** @var integer */
4850
private static $wireVersionForWriteConcern = 5;
4951

52+
/** @var integer */
53+
private static $wireVersionForCommitQuorum = 9;
54+
5055
/** @var string */
5156
private $databaseName;
5257

@@ -67,6 +72,8 @@ class CreateIndexes implements Executable
6772
*
6873
* Supported options:
6974
*
75+
* * commitQuorum (integer|string):
76+
*
7077
* * maxTimeMS (integer): The maximum amount of time to allow the query to
7178
* run.
7279
*
@@ -115,6 +122,10 @@ public function __construct($databaseName, $collectionName, array $indexes, arra
115122
$expectedIndex += 1;
116123
}
117124

125+
if (isset($options['commitQuorum']) && ! is_string($options['commitQuorum']) && ! is_integer($options['commitQuorum'])) {
126+
throw InvalidArgumentException::invalidType('"commitQuorum" option', $options['commitQuorum'], ['integer', 'string']);
127+
}
128+
118129
if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) {
119130
throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer');
120131
}
@@ -202,6 +213,16 @@ private function executeCommand(Server $server)
202213
'indexes' => $this->indexes,
203214
];
204215

216+
if (isset($this->options['commitQuorum'])) {
217+
/* Drivers MUST manually raise an error if this option is specified
218+
* when creating an index on a pre 4.4 server. */
219+
if (! server_supports_feature($server, self::$wireVersionForCommitQuorum)) {
220+
throw new CommandException('Invalid field specified for createIndexes command: commitQuorum', 2);
221+
}
222+
223+
$cmd['commitQuorum'] = $this->options['commitQuorum'];
224+
}
225+
205226
if (isset($this->options['maxTimeMS'])) {
206227
$cmd['maxTimeMS'] = $this->options['maxTimeMS'];
207228
}

tests/Operation/CreateIndexesFunctionalTest.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
namespace MongoDB\Tests\Operation;
44

55
use InvalidArgumentException;
6+
use MongoDB\Driver\Exception\CommandException;
67
use MongoDB\Driver\Exception\RuntimeException;
8+
use MongoDB\Driver\Server;
79
use MongoDB\Model\IndexInfo;
810
use MongoDB\Operation\CreateIndexes;
911
use MongoDB\Operation\ListIndexes;
@@ -171,6 +173,52 @@ function (array $event) {
171173
);
172174
}
173175

176+
public function testCommitQuorumOption()
177+
{
178+
if (version_compare($this->getServerVersion(), '4.3.4', '<')) {
179+
$this->markTestSkipped('commitQuorum is not supported');
180+
}
181+
182+
if ($this->getPrimaryServer()->getType() !== Server::TYPE_RS_PRIMARY) {
183+
$this->markTestSkipped('commitQuorum is only supported on replica sets');
184+
}
185+
186+
(new CommandObserver())->observe(
187+
function () {
188+
$operation = new CreateIndexes(
189+
$this->getDatabaseName(),
190+
$this->getCollectionName(),
191+
[['key' => ['x' => 1]]],
192+
['commitQuorum' => 'majority']
193+
);
194+
195+
$operation->execute($this->getPrimaryServer());
196+
},
197+
function (array $event) {
198+
$this->assertObjectHasAttribute('commitQuorum', $event['started']->getCommand());
199+
}
200+
);
201+
}
202+
203+
public function testCommitQuorumUnsupported()
204+
{
205+
if (version_compare($this->getServerVersion(), '4.3.4', '>=')) {
206+
$this->markTestSkipped('commitQuorum is supported');
207+
}
208+
209+
$operation = new CreateIndexes(
210+
$this->getDatabaseName(),
211+
$this->getCollectionName(),
212+
[['key' => ['x' => 1]]],
213+
['commitQuorum' => 'majority']
214+
);
215+
216+
$this->expectException(CommandException::class);
217+
$this->expectExceptionMessage('Invalid field specified for createIndexes command: commitQuorum');
218+
219+
$operation->execute($this->getPrimaryServer());
220+
}
221+
174222
/**
175223
* Asserts that an index with the given name exists for the collection.
176224
*

tests/Operation/CreateIndexesTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use MongoDB\Exception\InvalidArgumentException;
66
use MongoDB\Operation\CreateIndexes;
7+
use stdClass;
78

89
class CreateIndexesTest extends TestCase
910
{
@@ -27,6 +28,10 @@ public function provideInvalidConstructorOptions()
2728
{
2829
$options = [];
2930

31+
foreach ([3.14, true, [], new stdClass()] as $value) {
32+
$options[][] = ['commitQuorum' => $value];
33+
}
34+
3035
foreach ($this->getInvalidIntegerValues() as $value) {
3136
$options[][] = ['maxTimeMS' => $value];
3237
}

0 commit comments

Comments
 (0)