Skip to content

Commit 0d4b89c

Browse files
committed
Merge pull request #741
2 parents 85d29db + 12356e2 commit 0d4b89c

7 files changed

+110
-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
10+
plus ``"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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
source:
2+
file: apiargs-MongoDBCollection-method-createIndex-option.yaml
3+
ref: commitQuorum
4+
---
15
source:
26
file: apiargs-common-option.yaml
37
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/Exception/UnsupportedException.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,17 @@ public static function collationNotSupported()
3939
return new static('Collations are not supported by the server executing this operation');
4040
}
4141

42+
/**
43+
* Thrown when the commitQuorum option for createIndexes is not supported
44+
* by a server.
45+
*
46+
* @return self
47+
*/
48+
public static function commitQuorumNotSupported()
49+
{
50+
return new static('The "commitQuorum" option is not supported by the server executing this operation');
51+
}
52+
4253
/**
4354
* Thrown when explain is not supported by a server.
4455
*

src/Operation/CreateIndexes.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use function array_map;
2929
use function is_array;
3030
use function is_integer;
31+
use function is_string;
3132
use function MongoDB\server_supports_feature;
3233
use function sprintf;
3334

@@ -47,6 +48,9 @@ class CreateIndexes implements Executable
4748
/** @var integer */
4849
private static $wireVersionForWriteConcern = 5;
4950

51+
/** @var integer */
52+
private static $wireVersionForCommitQuorum = 9;
53+
5054
/** @var string */
5155
private $databaseName;
5256

@@ -67,6 +71,10 @@ class CreateIndexes implements Executable
6771
*
6872
* Supported options:
6973
*
74+
* * commitQuorum (integer|string): Specifies how many data-bearing members
75+
* of a replica set, including the primary, must complete the index
76+
* builds successfully before the primary marks the indexes as ready.
77+
*
7078
* * maxTimeMS (integer): The maximum amount of time to allow the query to
7179
* run.
7280
*
@@ -115,6 +123,10 @@ public function __construct($databaseName, $collectionName, array $indexes, arra
115123
$expectedIndex += 1;
116124
}
117125

126+
if (isset($options['commitQuorum']) && ! is_string($options['commitQuorum']) && ! is_integer($options['commitQuorum'])) {
127+
throw InvalidArgumentException::invalidType('"commitQuorum" option', $options['commitQuorum'], ['integer', 'string']);
128+
}
129+
118130
if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) {
119131
throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer');
120132
}
@@ -202,6 +214,16 @@ private function executeCommand(Server $server)
202214
'indexes' => $this->indexes,
203215
];
204216

217+
if (isset($this->options['commitQuorum'])) {
218+
/* Drivers MUST manually raise an error if this option is specified
219+
* when creating an index on a pre 4.4 server. */
220+
if (! server_supports_feature($server, self::$wireVersionForCommitQuorum)) {
221+
throw UnsupportedException::commitQuorumNotSupported();
222+
}
223+
224+
$cmd['commitQuorum'] = $this->options['commitQuorum'];
225+
}
226+
205227
if (isset($this->options['maxTimeMS'])) {
206228
$cmd['maxTimeMS'] = $this->options['maxTimeMS'];
207229
}

tests/Operation/CreateIndexesFunctionalTest.php

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

55
use InvalidArgumentException;
66
use MongoDB\Driver\Exception\RuntimeException;
7+
use MongoDB\Driver\Server;
8+
use MongoDB\Exception\UnsupportedException;
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(UnsupportedException::class);
217+
$this->expectExceptionMessage('The "commitQuorum" option is not supported by the server executing this operation');
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)