Skip to content

Commit ea50ebf

Browse files
committed
Merge pull request #736
* phplib-522: PHPLIB-522: Loosen index equality checks for GridFS
2 parents 051f345 + 79c2993 commit ea50ebf

File tree

2 files changed

+76
-4
lines changed

2 files changed

+76
-4
lines changed

src/GridFS/CollectionWrapper.php

+42-4
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,18 @@
1717

1818
namespace MongoDB\GridFS;
1919

20+
use ArrayIterator;
2021
use MongoDB\Collection;
2122
use MongoDB\Driver\Cursor;
2223
use MongoDB\Driver\Manager;
2324
use MongoDB\Driver\ReadPreference;
2425
use MongoDB\Exception\InvalidArgumentException;
2526
use MongoDB\UpdateResult;
27+
use MultipleIterator;
2628
use stdClass;
2729
use function abs;
30+
use function count;
31+
use function is_numeric;
2832
use function sprintf;
2933

3034
/**
@@ -289,27 +293,31 @@ public function updateFilenameForId($id, $filename)
289293
*/
290294
private function ensureChunksIndex()
291295
{
296+
$expectedIndex = ['files_id' => 1, 'n' => 1];
297+
292298
foreach ($this->chunksCollection->listIndexes() as $index) {
293-
if ($index->isUnique() && $index->getKey() === ['files_id' => 1, 'n' => 1]) {
299+
if ($index->isUnique() && $this->indexKeysMatch($expectedIndex, $index->getKey())) {
294300
return;
295301
}
296302
}
297303

298-
$this->chunksCollection->createIndex(['files_id' => 1, 'n' => 1], ['unique' => true]);
304+
$this->chunksCollection->createIndex($expectedIndex, ['unique' => true]);
299305
}
300306

301307
/**
302308
* Create an index on the files collection if it does not already exist.
303309
*/
304310
private function ensureFilesIndex()
305311
{
312+
$expectedIndex = ['filename' => 1, 'uploadDate' => 1];
313+
306314
foreach ($this->filesCollection->listIndexes() as $index) {
307-
if ($index->getKey() === ['filename' => 1, 'uploadDate' => 1]) {
315+
if ($this->indexKeysMatch($expectedIndex, $index->getKey())) {
308316
return;
309317
}
310318
}
311319

312-
$this->filesCollection->createIndex(['filename' => 1, 'uploadDate' => 1]);
320+
$this->filesCollection->createIndex($expectedIndex);
313321
}
314322

315323
/**
@@ -334,6 +342,36 @@ private function ensureIndexes()
334342
$this->ensureChunksIndex();
335343
}
336344

345+
private function indexKeysMatch(array $expectedKeys, array $actualKeys) : bool
346+
{
347+
if (count($expectedKeys) !== count($actualKeys)) {
348+
return false;
349+
}
350+
351+
$iterator = new MultipleIterator(MultipleIterator::MIT_NEED_ANY);
352+
$iterator->attachIterator(new ArrayIterator($expectedKeys));
353+
$iterator->attachIterator(new ArrayIterator($actualKeys));
354+
355+
foreach ($iterator as $key => $value) {
356+
list($expectedKey, $actualKey) = $key;
357+
list($expectedValue, $actualValue) = $value;
358+
359+
if ($expectedKey !== $actualKey) {
360+
return false;
361+
}
362+
363+
/* Since we don't expect special indexes (e.g. text), we mark any
364+
* index with a non-numeric definition as unequal. All others are
365+
* compared against their int value to avoid differences due to
366+
* some drivers using float values in the key specification. */
367+
if (! is_numeric($actualValue) || (int) $expectedValue !== (int) $actualValue) {
368+
return false;
369+
}
370+
}
371+
372+
return true;
373+
}
374+
337375
/**
338376
* Returns whether the files collection is empty.
339377
*

tests/GridFS/BucketFunctionalTest.php

+34
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,17 @@ public function testUploadingFirstFileCreatesIndexes()
697697
});
698698
}
699699

700+
public function testExistingIndexIsReused()
701+
{
702+
$this->filesCollection->createIndex(['filename' => 1.0, 'uploadDate' => 1], ['name' => 'test']);
703+
$this->chunksCollection->createIndex(['files_id' => 1.0, 'n' => 1], ['name' => 'test', 'unique' => true]);
704+
705+
$this->bucket->uploadFromStream('filename', $this->createStream('foo'));
706+
707+
$this->assertIndexNotExists($this->filesCollection->getCollectionName(), 'filename_1_uploadDate_1');
708+
$this->assertIndexNotExists($this->chunksCollection->getCollectionName(), 'files_id_1_n_1');
709+
}
710+
700711
/**
701712
* Asserts that a collection with the given name does not exist on the
702713
* server.
@@ -757,6 +768,29 @@ private function assertIndexExists($collectionName, $indexName, $callback = null
757768
}
758769
}
759770

771+
/**
772+
* Asserts that an index with the given name does not exist for the collection.
773+
*
774+
* @param string $collectionName
775+
* @param string $indexName
776+
*/
777+
private function assertIndexNotExists($collectionName, $indexName)
778+
{
779+
$operation = new ListIndexes($this->getDatabaseName(), $collectionName);
780+
$indexes = $operation->execute($this->getPrimaryServer());
781+
782+
$foundIndex = false;
783+
784+
foreach ($indexes as $index) {
785+
if ($index->getName() === $indexName) {
786+
$foundIndex = true;
787+
break;
788+
}
789+
}
790+
791+
$this->assertFalse($foundIndex, sprintf('Index %s exists', $indexName));
792+
}
793+
760794
/**
761795
* Return a list of invalid stream values.
762796
*

0 commit comments

Comments
 (0)