Skip to content

Commit 33a40e7

Browse files
committed
Implemented optional definition of a batch size when creating a batch object. If a batch size is defined, then internally the object will use an SPLFixedArray for its batch-part array.
This will mostly be more performant than normal arrays, especially in larger batch sizes. Some tests have shown that a batch size of 10000 brings about 5% to 15% more performance than normal arrays, depending on data.
1 parent 6bf49e3 commit 33a40e7

File tree

3 files changed

+109
-15
lines changed

3 files changed

+109
-15
lines changed

lib/triagens/ArangoDb/Batch.php

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ class Batch
7575
*/
7676
private $_sanitize = false;
7777

78+
/**
79+
* The Batch NextId
80+
*
81+
* @var mixed $_nextId
82+
*/
83+
private $_nextId = 0;
84+
7885

7986
/**
8087
* Constructor for Batch instance. Batch instance by default starts capturing request after initiated.
@@ -85,8 +92,10 @@ class Batch
8592
*
8693
* <p>Options are :
8794
* <li>'_sanitize' - True to remove _id and _rev attributes from result documents returned from this batch. Defaults to false.</li>
88-
* <li>'$startCapture' - Start batch capturing immediately after batch instantiation. Defaults to true.
89-
* </li>
95+
* <li>'startCapture' - Start batch capturing immediately after batch instantiation. Defaults to true.</li>
96+
* <li>'batchSize' - Defines a fixed array size for holding the batch parts. The id's of the batch parts can only be integers.
97+
* When this option is defined, the batch mechanism will use an SplFixedArray instead of the normal PHP arrays.
98+
* In most cases, this will result in increased performance of about 5% to 15%, depending on batch size and data.</li>
9099
* </p>
91100
*
92101
* @return Batch
@@ -95,9 +104,15 @@ public function __construct(Connection $connection, $options = array())
95104
{
96105
$startCapture = true;
97106
$sanitize = false;
107+
$batchSize = 0;
98108
$options = array_merge($options, $this->getCursorOptions($sanitize));
99109
extract($options, EXTR_IF_EXISTS);
100110
$this->_sanitize = $sanitize;
111+
$this->batchSize = $batchSize;
112+
113+
if ($this->batchSize > 0) {
114+
$this->_batchParts = new \SplFixedArray($this->batchSize);
115+
}
101116

102117
$this->setConnection($connection);
103118

@@ -335,7 +350,13 @@ public function append($method, $request)
335350
$response = new HttpResponse($result);
336351
$batchPart = new BatchPart($this, $this->_nextBatchPartId, $type, $request, $response, array('cursorOptions' => $this->_batchPartCursorOptions));
337352
if (null === $this->_nextBatchPartId) {
338-
$nextNumeric = count($this->_batchParts);
353+
if (is_a($this->_batchParts, 'SplFixedArray')) {
354+
$nextNumeric = $this->_nextId;
355+
$this->_nextId++;
356+
}
357+
else {
358+
$nextNumeric = count($this->_batchParts);
359+
}
339360
$this->_batchParts[$nextNumeric] = $batchPart;
340361
}
341362
else {
@@ -394,17 +415,19 @@ public function process()
394415

395416
/** @var $partValue BatchPart */
396417
foreach ($batchParts as $partValue) {
397-
$data .= '--' . HttpHelper::MIME_BOUNDARY . HttpHelper::EOL;
398-
$data .= 'Content-Type: application/x-arango-batchpart' . HttpHelper::EOL;
399-
400-
if (null !== $partValue->getId()) {
401-
$data .= 'Content-Id: ' . (string) $partValue->getId() . HttpHelper::EOL . HttpHelper::EOL;
418+
if (isset($partValue)) {
419+
$data .= '--' . HttpHelper::MIME_BOUNDARY . HttpHelper::EOL;
420+
$data .= 'Content-Type: application/x-arango-batchpart' . HttpHelper::EOL;
421+
422+
if (null !== $partValue->getId()) {
423+
$data .= 'Content-Id: ' . (string) $partValue->getId() . HttpHelper::EOL . HttpHelper::EOL;
424+
}
425+
else {
426+
$data .= HttpHelper::EOL;
427+
}
428+
429+
$data .= (string) $partValue->getRequest() . HttpHelper::EOL;
402430
}
403-
else {
404-
$data .= HttpHelper::EOL;
405-
}
406-
407-
$data .= (string) $partValue->getRequest() . HttpHelper::EOL;
408431
}
409432
$data .= '--' . HttpHelper::MIME_BOUNDARY . '--' . HttpHelper::EOL . HttpHelper::EOL;
410433

lib/triagens/ArangoDb/BatchPart.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,6 @@ class BatchPart
7676
/**
7777
* Constructor
7878
*
79-
* @internal
80-
*
8179
* @param Batch $batch the batch object, that this part belongs to
8280
* @param mixed $id The id of the batch part. TMust be unique and wil be passed to the server in the content-id header
8381
* @param mixed $type The type of the request. This is to distinguish the different request type in order to return correct results.

tests/BatchTest.php

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,79 @@ public function testCreateDocumentBatch()
174174
$batch->getProcessedPartResponse(1);
175175
}
176176

177+
/**
178+
* This tests the batch class when used with an SplFixedArray as its Array for the BatchParts
179+
*/
180+
public function testCreateDocumentBatchWithDefinedBatchSize()
181+
{
182+
$batch = new Batch($this->connection, ['batchSize' => 2]);
183+
184+
// not needed, but just here to test if anything goes wrong if it's called again...
185+
$batch->startCapture();
186+
187+
static::assertInstanceOf('\triagens\ArangoDb\Batch', $batch);
188+
$documentHandler = $this->documentHandler;
189+
190+
$document = Document::createFromArray(
191+
array('someAttribute' => 'someValue', 'someOtherAttribute' => 'someOtherValue')
192+
);
193+
$documentId = $documentHandler->add($this->collection->getId(), $document);
194+
195+
static::assertTrue(is_numeric($documentId), 'Did not return an id!');
196+
197+
$document = Document::createFromArray(
198+
array('someAttribute' => 'someValue2', 'someOtherAttribute' => 'someOtherValue2')
199+
);
200+
$documentId = $documentHandler->add($this->collection->getId(), $document);
201+
202+
static::assertTrue(is_numeric($documentId), 'Did not return an id!');
203+
204+
$batch->process();
205+
206+
$batch->getPart(0)->getProcessedResponse();
207+
208+
// try getting it from batch
209+
$batch->getProcessedPartResponse(1);
210+
}
211+
212+
213+
/**
214+
* This tests the batch class when used with an SplFixedArray as its Array for the BatchParts
215+
* It simulates an invalid index access, in order to check that we are really using SplFixedArray
216+
*/
217+
public function testFailureWhenCreatingMoreDocumentsInBatchThanDefinedBatchSize()
218+
{
219+
$batch = new Batch($this->connection, ['batchSize' => 1]);
220+
221+
// not needed, but just here to test if anything goes wrong if it's called again...
222+
$batch->startCapture();
223+
224+
static::assertInstanceOf('\triagens\ArangoDb\Batch', $batch);
225+
$documentHandler = $this->documentHandler;
226+
227+
$document = Document::createFromArray(
228+
array('someAttribute' => 'someValue', 'someOtherAttribute' => 'someOtherValue')
229+
);
230+
$documentId = $documentHandler->add($this->collection->getId(), $document);
231+
232+
static::assertTrue(is_numeric($documentId), 'Did not return an id!');
233+
234+
$document = Document::createFromArray(
235+
array('someAttribute' => 'someValue2', 'someOtherAttribute' => 'someOtherValue2')
236+
);
237+
try {
238+
$documentId = $documentHandler->add($this->collection->getId(), $document);
239+
} catch (\Exception $e) {
240+
// don't bother us, just give us the $e
241+
}
242+
static::assertInstanceOf(
243+
'RuntimeException',
244+
$e,
245+
'Exception thrown was not a RuntimeException!'
246+
);
247+
static::assertEquals('Index invalid or out of range', $e->getMessage(), 'Error code was not "Index invalid or out of range"');
248+
249+
}
177250

178251
public function testCreateMixedBatchWithPartIds()
179252
{

0 commit comments

Comments
 (0)