Commit 6676e7ef authored by Jeremy Mikola's avatar Jeremy Mikola

PHPLIB-244: Use strings instead of memory stream for GridFS upload buffering

parent 9dfb2c5f
......@@ -150,7 +150,7 @@ class StreamWrapper
}
try {
return $this->stream->insertChunks($data);
return $this->stream->writeBytes($data);
} catch (Exception $e) {
trigger_error(sprintf('%s: %s', get_class($e), $e->getMessage()), \E_USER_WARNING);
return false;
......
......@@ -6,6 +6,7 @@ use MongoDB\BSON\Binary;
use MongoDB\BSON\ObjectId;
use MongoDB\BSON\UTCDateTime;
use MongoDB\Exception\InvalidArgumentException;
use MongoDB\Exception\RuntimeException;
/**
* WritableStream abstracts the process of writing a GridFS file.
......@@ -16,8 +17,7 @@ class WritableStream
{
private static $defaultChunkSizeBytes = 261120;
private $buffer;
private $bufferLength = 0;
private $buffer = '';
private $chunkOffset = 0;
private $chunkSize;
private $collectionWrapper;
......@@ -76,7 +76,6 @@ class WritableStream
$this->chunkSize = $options['chunkSizeBytes'];
$this->collectionWrapper = $collectionWrapper;
$this->buffer = fopen('php://memory', 'w+b');
$this->ctx = hash_init('md5');
$this->file = [
......@@ -113,14 +112,10 @@ class WritableStream
return;
}
rewind($this->buffer);
$cached = stream_get_contents($this->buffer);
if (strlen($cached) > 0) {
$this->insertChunk($cached);
if (strlen($this->buffer) > 0) {
$this->insertChunkFromBuffer();
}
fclose($this->buffer);
$this->fileCollectionInsert();
$this->isClosed = true;
}
......@@ -151,36 +146,31 @@ class WritableStream
* Inserts binary data into GridFS via chunks.
*
* Data will be buffered internally until chunkSizeBytes are accumulated, at
* which point a chunk's worth of data will be inserted and the buffer
* reset.
* which point a chunk document will be inserted and the buffer reset.
*
* @param string $toWrite Binary data to write
* @param string $data Binary data to write
* @return integer
*/
public function insertChunks($toWrite)
public function writeBytes($data)
{
if ($this->isClosed) {
// TODO: Should this be an error condition? e.g. BadMethodCallException
return;
}
$readBytes = 0;
$bytesRead = 0;
while ($readBytes != strlen($toWrite)) {
$addToBuffer = substr($toWrite, $readBytes, $this->chunkSize - $this->bufferLength);
fwrite($this->buffer, $addToBuffer);
$readBytes += strlen($addToBuffer);
$this->bufferLength += strlen($addToBuffer);
while ($bytesRead != strlen($data)) {
$initialBufferLength = strlen($this->buffer);
$this->buffer .= substr($data, $bytesRead, $this->chunkSize - $initialBufferLength);
$bytesRead += strlen($this->buffer) - $initialBufferLength;
if ($this->bufferLength == $this->chunkSize) {
rewind($this->buffer);
$this->insertChunk(stream_get_contents($this->buffer));
ftruncate($this->buffer, 0);
$this->bufferLength = 0;
if (strlen($this->buffer) == $this->chunkSize) {
$this->insertChunkFromBuffer();
}
}
return $readBytes;
return $bytesRead;
}
private function abort()
......@@ -206,14 +196,21 @@ class WritableStream
return $this->file['_id'];
}
private function insertChunk($data)
private function insertChunkFromBuffer()
{
if ($this->isClosed) {
// TODO: Should this be an error condition? e.g. BadMethodCallException
return;
}
$toUpload = [
if (strlen($this->buffer) == 0) {
return;
}
$data = $this->buffer;
$this->buffer = '';
$chunk = [
'files_id' => $this->file['_id'],
'n' => $this->chunkOffset,
'data' => new Binary($data, Binary::TYPE_GENERIC),
......@@ -221,7 +218,7 @@ class WritableStream
hash_update($this->ctx, $data);
$this->collectionWrapper->insertChunk($toUpload);
$this->collectionWrapper->insertChunk($chunk);
$this->length += strlen($data);
$this->chunkOffset++;
}
......
......@@ -55,10 +55,10 @@ class WritableStreamFunctionalTest extends FunctionalTestCase
/**
* @dataProvider provideInputDataAndExpectedMD5
*/
public function testInsertChunksCalculatesMD5($input, $expectedMD5)
public function testWriteBytesCalculatesMD5($input, $expectedMD5)
{
$stream = new WritableStream($this->collectionWrapper, 'filename');
$stream->insertChunks($input);
$stream->writeBytes($input);
$stream->close();
$fileDocument = $this->filesCollection->findOne(
......
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