@@ -30,13 +30,6 @@ class ConnectionOptions implements \ArrayAccess
30
30
*/
31
31
private $ _values = [];
32
32
33
- /**
34
- * The connection endpoint object
35
- *
36
- * @var Endpoint
37
- */
38
- private $ _endpoint ;
39
-
40
33
/**
41
34
* The index into the endpoints array that we will connect to (or are currently
42
35
* connected to). This index will be increased in case the currently connected
@@ -49,6 +42,13 @@ class ConnectionOptions implements \ArrayAccess
49
42
*/
50
43
private $ _currentEndpointIndex = 0 ;
51
44
45
+ /**
46
+ * Optional Memcached instance for endpoints caching
47
+ *
48
+ * @var Memcached
49
+ */
50
+ private $ _cache = null ;
51
+
52
52
/**
53
53
* Endpoint string index constant
54
54
*/
@@ -208,18 +208,43 @@ class ConnectionOptions implements \ArrayAccess
208
208
* UTF-8 CHeck Flag
209
209
*/
210
210
const OPTION_CHECK_UTF8_CONFORM = 'CheckUtf8Conform ' ;
211
+
212
+ /**
213
+ * Entry for memcached servers array
214
+ */
215
+ const OPTION_MEMCACHED_SERVERS = 'memcachedServers ' ;
216
+
217
+ /**
218
+ * Entry for memcached options array
219
+ */
220
+ const OPTION_MEMCACHED_OPTIONS = 'memcachedOptions ' ;
221
+
222
+ /**
223
+ * Entry for memcached endpoints key
224
+ */
225
+ const OPTION_MEMCACHED_ENDPOINTS_KEY = 'memcachedEndpointsKey ' ;
226
+
227
+ /**
228
+ * Entry for memcached persistend id
229
+ */
230
+ const OPTION_MEMCACHED_PERSISTENT_ID = 'memcachedPersistentId ' ;
231
+
232
+ /**
233
+ * Entry for memcached cache ttl
234
+ */
235
+ const OPTION_MEMCACHED_TTL = 'memcachedTtl ' ;
211
236
212
237
/**
213
238
* Set defaults, use options provided by client and validate them
214
239
*
215
- *
216
240
* @param array $options - initial options
217
241
*
218
242
* @throws \ArangoDBClient\ClientException
219
243
*/
220
244
public function __construct (array $ options )
221
245
{
222
246
$ this ->_values = array_merge (self ::getDefaults (), $ options );
247
+ $ this ->loadOptionsFromCache ();
223
248
$ this ->validate ();
224
249
}
225
250
@@ -294,22 +319,6 @@ public function offsetGet($offset)
294
319
return $ this ->_values [$ offset ];
295
320
}
296
321
297
- /**
298
- * Get the endpoint object for the connection
299
- *
300
- * @throws ClientException
301
- * @return Endpoint - endpoint object
302
- */
303
- public function getEndpoint ()
304
- {
305
- if ($ this ->_endpoint === null ) {
306
- // will also validate the endpoint
307
- $ this ->_endpoint = new Endpoint ($ this ->getCurrentEndpoint ());
308
- }
309
-
310
- return $ this ->_endpoint ;
311
- }
312
-
313
322
/**
314
323
* Get the current endpoint to use
315
324
*
@@ -344,6 +353,10 @@ public function haveMultipleEndpoints()
344
353
*/
345
354
public function addEndpoint ($ endpoint )
346
355
{
356
+ if (!is_string ($ endpoint ) || !Endpoint::isValid ($ endpoint )) {
357
+ throw new ClientException (sprintf ("invalid endpoint specification '%s' " , $ endpoint ));
358
+ }
359
+
347
360
// can only add an endpoint here if the list of endpoints is already an array
348
361
if (!is_array ($ this ->_values [self ::OPTION_ENDPOINT ])) {
349
362
// make it an array now
@@ -358,26 +371,37 @@ public function addEndpoint($endpoint)
358
371
// we have already got this endpoint
359
372
$ this ->_currentEndpointIndex = $ found ;
360
373
}
374
+
375
+ $ this ->storeOptionsInCache ();
361
376
}
362
377
363
378
/**
364
379
* Return the next endpoint from the list of endpoints
380
+ * As a side-effect this function switches to a new endpoint
365
381
*
366
382
* @return string - the next endpoint
367
383
*/
368
384
public function nextEndpoint ()
369
385
{
370
- if (!is_array ($ this ->_values [self ::OPTION_ENDPOINT ])) {
371
- return $ this ->_values [self ::OPTION_ENDPOINT ];
386
+ $ endpoints = $ this ->_values [self ::OPTION_ENDPOINT ];
387
+ if (!is_array ($ endpoints )) {
388
+ return $ endpoints ;
372
389
}
373
390
374
- $ numberOfEndpoints = count ($ this ->_values [self ::OPTION_ENDPOINT ]);
391
+ $ numberOfEndpoints = count ($ endpoints );
392
+
375
393
$ this ->_currentEndpointIndex ++;
376
394
if ($ this ->_currentEndpointIndex >= $ numberOfEndpoints ) {
377
395
$ this ->_currentEndpointIndex = 0 ;
378
396
}
379
397
380
- return $ this ->_values [self ::OPTION_ENDPOINT ][$ this ->_currentEndpointIndex ];
398
+ $ endpoint = $ endpoints [$ this ->_currentEndpointIndex ];
399
+
400
+ if ($ numberOfEndpoints > 1 ) {
401
+ $ this ->storeOptionsInCache ();
402
+ }
403
+
404
+ return $ endpoint ;
381
405
}
382
406
383
407
/**
@@ -388,35 +412,39 @@ public function nextEndpoint()
388
412
private static function getDefaults ()
389
413
{
390
414
return [
391
- self ::OPTION_ENDPOINT => null ,
392
- self ::OPTION_HOST => null ,
393
- self ::OPTION_PORT => DefaultValues::DEFAULT_PORT ,
394
- self ::OPTION_FAILOVER_TRIES => DefaultValues::DEFAULT_FAILOVER_TRIES ,
395
- self ::OPTION_TIMEOUT => DefaultValues::DEFAULT_TIMEOUT ,
396
- self ::OPTION_CREATE => DefaultValues::DEFAULT_CREATE ,
397
- self ::OPTION_UPDATE_POLICY => DefaultValues::DEFAULT_UPDATE_POLICY ,
398
- self ::OPTION_REPLACE_POLICY => DefaultValues::DEFAULT_REPLACE_POLICY ,
399
- self ::OPTION_DELETE_POLICY => DefaultValues::DEFAULT_DELETE_POLICY ,
400
- self ::OPTION_REVISION => null ,
401
- self ::OPTION_WAIT_SYNC => DefaultValues::DEFAULT_WAIT_SYNC ,
402
- self ::OPTION_BATCHSIZE => null ,
403
- self ::OPTION_JOURNAL_SIZE => DefaultValues::DEFAULT_JOURNAL_SIZE ,
404
- self ::OPTION_IS_SYSTEM => false ,
405
- self ::OPTION_IS_VOLATILE => DefaultValues::DEFAULT_IS_VOLATILE ,
406
- self ::OPTION_CONNECTION => DefaultValues::DEFAULT_CONNECTION ,
407
- self ::OPTION_TRACE => null ,
408
- self ::OPTION_ENHANCED_TRACE => false ,
409
- self ::OPTION_VERIFY_CERT => DefaultValues::DEFAULT_VERIFY_CERT ,
410
- self ::OPTION_ALLOW_SELF_SIGNED => DefaultValues::DEFAULT_ALLOW_SELF_SIGNED ,
411
- self ::OPTION_CIPHERS => DefaultValues::DEFAULT_CIPHERS ,
412
- self ::OPTION_AUTH_USER => null ,
413
- self ::OPTION_AUTH_PASSWD => null ,
414
- self ::OPTION_AUTH_TYPE => DefaultValues::DEFAULT_AUTH_TYPE ,
415
- self ::OPTION_RECONNECT => false ,
416
- self ::OPTION_BATCH => false ,
417
- self ::OPTION_BATCHPART => false ,
418
- self ::OPTION_DATABASE => '_system ' ,
419
- self ::OPTION_CHECK_UTF8_CONFORM => DefaultValues::DEFAULT_CHECK_UTF8_CONFORM
415
+ self ::OPTION_ENDPOINT => null ,
416
+ self ::OPTION_HOST => null ,
417
+ self ::OPTION_PORT => DefaultValues::DEFAULT_PORT ,
418
+ self ::OPTION_FAILOVER_TRIES => DefaultValues::DEFAULT_FAILOVER_TRIES ,
419
+ self ::OPTION_TIMEOUT => DefaultValues::DEFAULT_TIMEOUT ,
420
+ self ::OPTION_MEMCACHED_PERSISTENT_ID => 'arangodb-php-pool ' ,
421
+ self ::OPTION_MEMCACHED_OPTIONS => [ ],
422
+ self ::OPTION_MEMCACHED_ENDPOINTS_KEY => 'arangodb-php-endpoints ' ,
423
+ self ::OPTION_MEMCACHED_TTL => 600 ,
424
+ self ::OPTION_CREATE => DefaultValues::DEFAULT_CREATE ,
425
+ self ::OPTION_UPDATE_POLICY => DefaultValues::DEFAULT_UPDATE_POLICY ,
426
+ self ::OPTION_REPLACE_POLICY => DefaultValues::DEFAULT_REPLACE_POLICY ,
427
+ self ::OPTION_DELETE_POLICY => DefaultValues::DEFAULT_DELETE_POLICY ,
428
+ self ::OPTION_REVISION => null ,
429
+ self ::OPTION_WAIT_SYNC => DefaultValues::DEFAULT_WAIT_SYNC ,
430
+ self ::OPTION_BATCHSIZE => null ,
431
+ self ::OPTION_JOURNAL_SIZE => DefaultValues::DEFAULT_JOURNAL_SIZE ,
432
+ self ::OPTION_IS_SYSTEM => false ,
433
+ self ::OPTION_IS_VOLATILE => DefaultValues::DEFAULT_IS_VOLATILE ,
434
+ self ::OPTION_CONNECTION => DefaultValues::DEFAULT_CONNECTION ,
435
+ self ::OPTION_TRACE => null ,
436
+ self ::OPTION_ENHANCED_TRACE => false ,
437
+ self ::OPTION_VERIFY_CERT => DefaultValues::DEFAULT_VERIFY_CERT ,
438
+ self ::OPTION_ALLOW_SELF_SIGNED => DefaultValues::DEFAULT_ALLOW_SELF_SIGNED ,
439
+ self ::OPTION_CIPHERS => DefaultValues::DEFAULT_CIPHERS ,
440
+ self ::OPTION_AUTH_USER => null ,
441
+ self ::OPTION_AUTH_PASSWD => null ,
442
+ self ::OPTION_AUTH_TYPE => DefaultValues::DEFAULT_AUTH_TYPE ,
443
+ self ::OPTION_RECONNECT => false ,
444
+ self ::OPTION_BATCH => false ,
445
+ self ::OPTION_BATCHPART => false ,
446
+ self ::OPTION_DATABASE => '_system ' ,
447
+ self ::OPTION_CHECK_UTF8_CONFORM => DefaultValues::DEFAULT_CHECK_UTF8_CONFORM
420
448
];
421
449
}
422
450
@@ -467,10 +495,12 @@ private function validate()
467
495
unset($ this ->_values [self ::OPTION_HOST ]);
468
496
}
469
497
470
- // set up a new endpoint, this will also validate it
471
- $ this ->getEndpoint ();
472
-
498
+ // validate endpoint
473
499
$ ep = $ this ->getCurrentEndpoint ();
500
+ if (!Endpoint::isValid ($ ep )) {
501
+ throw new ClientException (sprintf ("invalid endpoint specification '%s' " , $ ep ));
502
+ }
503
+
474
504
$ type = Endpoint::getType ($ ep );
475
505
if ($ type === Endpoint::TYPE_UNIX ) {
476
506
// must set port to 0 for UNIX domain sockets
@@ -516,6 +546,98 @@ private function validate()
516
546
UpdatePolicy::validate ($ this ->_values [self ::OPTION_REPLACE_POLICY ]);
517
547
UpdatePolicy::validate ($ this ->_values [self ::OPTION_DELETE_POLICY ]);
518
548
}
549
+
550
+
551
+ /**
552
+ * load and merge connection options from optional Memcached cache into
553
+ * ihe current settings
554
+ *
555
+ * @return void
556
+ */
557
+ private function loadOptionsFromCache ()
558
+ {
559
+ $ cache = $ this ->getEndpointsCache ();
560
+
561
+ if ($ cache === null ) {
562
+ return ;
563
+ }
564
+
565
+ $ endpoints = $ cache ->get ($ this ->_values [self ::OPTION_MEMCACHED_ENDPOINTS_KEY ]);
566
+ if ($ endpoints ) {
567
+ $ this ->_values [self ::OPTION_ENDPOINT ] = $ endpoints ;
568
+ }
569
+ }
570
+
571
+ /**
572
+ * store the updated options in the optional Memcached cache
573
+ *
574
+ * @return void
575
+ */
576
+ private function storeOptionsInCache ()
577
+ {
578
+ $ endpoints = $ this ->_values [self ::OPTION_ENDPOINT ];
579
+ $ numberOfEndpoints = count ($ endpoints );
580
+
581
+ if ($ numberOfEndpoints <= 1 ) {
582
+ return ;
583
+ }
584
+
585
+ // now try to store the updated values in the cache
586
+ $ cache = $ this ->getEndpointsCache ();
587
+ if ($ cache === null ) {
588
+ return ;
589
+ }
590
+
591
+ $ update = [ $ endpoints [$ this ->_currentEndpointIndex ] ];
592
+ for ($ i = 0 ; $ i < $ numberOfEndpoints ; ++$ i ) {
593
+ if ($ i !== $ this ->_currentEndpointIndex ) {
594
+ $ update [] = $ endpoints [$ i ];
595
+ }
596
+ }
597
+
598
+ $ ttl = (int ) $ this ->_values [self ::OPTION_MEMCACHED_TTL ];
599
+ $ cache ->set ($ this ->_values [self ::OPTION_MEMCACHED_ENDPOINTS_KEY ], $ update , $ ttl );
600
+ }
601
+
602
+ /**
603
+ * Initialize and return a memcached cache instance,
604
+ * if option "memcachedServers" is set
605
+ *
606
+ * @return Memcached - memcached server instance if configured or null if not
607
+ */
608
+ private function getEndpointsCache ()
609
+ {
610
+ if ($ this ->_cache === null ) {
611
+ if (!isset ($ this ->_values [self ::OPTION_MEMCACHED_SERVERS ])) {
612
+ return null ;
613
+ }
614
+ if (!class_exists ('Memcached ' , false )) {
615
+ return null ;
616
+ }
617
+
618
+ $ servers = $ this ->_values [self ::OPTION_MEMCACHED_SERVERS ];
619
+ if (!is_array ($ servers )) {
620
+ throw new ClientException ('Invalid memcached servers list. should be an array of servers ' );
621
+ }
622
+
623
+ $ cache = new \Memcached (self ::OPTION_MEMCACHED_PERSISTENT_ID );
624
+ if (empty ($ cache ->getServerList ())) {
625
+ $ cache ->addServers ($ servers );
626
+ }
627
+
628
+ if (isset ($ this ->_values [self ::OPTION_MEMCACHED_OPTIONS ])) {
629
+ $ options = $ this ->_values [self ::OPTION_MEMCACHED_OPTIONS ];
630
+ if (!is_array ($ options )) {
631
+ throw new ClientException ('Invalid memcached options list. should be an array of options ' );
632
+ }
633
+ $ cache ->setOptions ($ options );
634
+ }
635
+
636
+ $ this ->_cache = $ cache ;
637
+
638
+ }
639
+ return $ this ->_cache ;
640
+ }
519
641
}
520
642
521
643
class_alias (ConnectionOptions::class, '\triagens\ArangoDb\ConnectionOptions ' );
0 commit comments