Commit 966511c8 authored by Katherine Walker's avatar Katherine Walker

Merge pull request #491

parents 0d3496dd 010751c7
......@@ -186,9 +186,32 @@ class ReadableStream
$this->chunkOffset = (integer) floor($offset / $this->chunkSize);
$this->bufferOffset = $offset % $this->chunkSize;
if ($lastChunkOffset !== $this->chunkOffset) {
$this->buffer = null;
if ($lastChunkOffset === $this->chunkOffset) {
return;
}
if ($this->chunksIterator === null) {
return;
}
// Clear the buffer since the current chunk will be changed
$this->buffer = null;
/* If we are seeking to a previous chunk, we need to reinitialize the
* chunk iterator.
*/
if ($lastChunkOffset > $this->chunkOffset) {
$this->chunksIterator = null;
return;
}
/* If we are seeking to a subsequent chunk, we do not need to
* reinitalize the chunk iterator. Instead, we can simply move forward
* to $this->chunkOffset.
*/
$numChunks = $this->chunkOffset - $lastChunkOffset;
for ($i = 0; $i < $numChunks; $i++) {
$this->chunksIterator->next();
}
}
......
......@@ -5,6 +5,8 @@ namespace MongoDB\Tests\GridFS;
use MongoDB\BSON\Binary;
use MongoDB\GridFS\CollectionWrapper;
use MongoDB\GridFS\ReadableStream;
use MongoDB\Tests\CommandObserver;
use stdClass;
/**
* Functional tests for the internal ReadableStream class.
......@@ -188,6 +190,15 @@ class ReadableStreamFunctionalTest extends FunctionalTestCase
$stream->readBytes(-1);
}
public function testSeekBeforeReading()
{
$fileDocument = $this->collectionWrapper->findFileById('length-10');
$stream = new ReadableStream($this->collectionWrapper, $fileDocument);
$stream->seek(8);
$this->assertSame('ij', $stream->readBytes(2));
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentException
* @expectedExceptionMessage $offset must be >= 0 and <= 10; given: 11
......@@ -199,4 +210,109 @@ class ReadableStreamFunctionalTest extends FunctionalTestCase
$stream->seek(11);
}
/**
* @dataProvider providePreviousChunkSeekOffsetAndBytes
*/
public function testSeekPreviousChunk($offset, $length, $expectedBytes)
{
$fileDocument = $this->collectionWrapper->findFileById('length-10');
$stream = new ReadableStream($this->collectionWrapper, $fileDocument);
// Read to initialize and advance the chunk iterator to the last chunk
$this->assertSame('abcdefghij', $stream->readBytes(10));
$commands = [];
(new CommandObserver)->observe(
function() use ($stream, $offset, $length, $expectedBytes) {
$stream->seek($offset);
$this->assertSame($expectedBytes, $stream->readBytes($length));
},
function(stdClass $command) use (&$commands) {
$commands[] = key((array) $command);
}
);
$this->assertSame(['find'], $commands);
}
public function providePreviousChunkSeekOffsetAndBytes()
{
return [
[0, 4, 'abcd'],
[2, 4, 'cdef'],
[4, 4, 'efgh'],
[6, 4, 'ghij'],
];
}
/**
* @dataProvider provideSameChunkSeekOffsetAndBytes
*/
public function testSeekSameChunk($offset, $length, $expectedBytes)
{
$fileDocument = $this->collectionWrapper->findFileById('length-10');
$stream = new ReadableStream($this->collectionWrapper, $fileDocument);
// Read to initialize and advance the chunk iterator to the middle chunk
$this->assertSame('abcdef', $stream->readBytes(6));
$commands = [];
(new CommandObserver)->observe(
function() use ($stream, $offset, $length, $expectedBytes) {
$stream->seek($offset);
$this->assertSame($expectedBytes, $stream->readBytes($length));
},
function(stdClass $command) use (&$commands) {
$commands[] = key((array) $command);
}
);
$this->assertSame([], $commands);
}
public function provideSameChunkSeekOffsetAndBytes()
{
return [
[4, 4, 'efgh'],
[6, 4, 'ghij'],
];
}
/**
* @dataProvider provideSubsequentChunkSeekOffsetAndBytes
*/
public function testSeekSubsequentChunk($offset, $length, $expectedBytes)
{
$fileDocument = $this->collectionWrapper->findFileById('length-10');
$stream = new ReadableStream($this->collectionWrapper, $fileDocument);
// Read to initialize the chunk iterator to the first chunk
$this->assertSame('a', $stream->readBytes(1));
$commands = [];
(new CommandObserver)->observe(
function() use ($stream, $offset, $length, $expectedBytes) {
$stream->seek($offset);
$this->assertSame($expectedBytes, $stream->readBytes($length));
},
function(stdClass $command) use (&$commands) {
$commands[] = key((array) $command);
}
);
$this->assertSame([], $commands);
}
public function provideSubsequentChunkSeekOffsetAndBytes()
{
return [
[4, 4, 'efgh'],
[6, 4, 'ghij'],
[8, 2, 'ij'],
];
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment