Skip to content

Commit aac37e3

Browse files
committed
Merge pull request #1136
2 parents 1771d5c + a449493 commit aac37e3

7 files changed

+244
-13
lines changed

src/MongoDB/ReadPreference.c

Lines changed: 128 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ zend_class_entry* php_phongo_readpreference_ce;
4040
* An exception will be thrown on error. */
4141
static bool php_phongo_readpreference_init_from_hash(php_phongo_readpreference_t* intern, HashTable* props) /* {{{ */
4242
{
43-
zval *mode, *tagSets, *maxStalenessSeconds;
43+
zval *mode, *tagSets, *maxStalenessSeconds, *hedge;
4444

4545
if ((mode = zend_hash_str_find(props, "mode", sizeof("mode") - 1)) && Z_TYPE_P(mode) == IS_STRING) {
4646
if (strcasecmp(Z_STRVAL_P(mode), PHONGO_READ_PRIMARY) == 0) {
@@ -91,22 +91,49 @@ static bool php_phongo_readpreference_init_from_hash(php_phongo_readpreference_t
9191

9292
if ((maxStalenessSeconds = zend_hash_str_find(props, "maxStalenessSeconds", sizeof("maxStalenessSeconds") - 1))) {
9393
if (Z_TYPE_P(maxStalenessSeconds) == IS_LONG) {
94-
if (Z_LVAL_P(maxStalenessSeconds) < MONGOC_SMALLEST_MAX_STALENESS_SECONDS) {
95-
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"maxStalenessSeconds\" integer field to be >= %d", ZSTR_VAL(php_phongo_readpreference_ce->name), MONGOC_SMALLEST_MAX_STALENESS_SECONDS);
96-
goto failure;
94+
if (Z_LVAL_P(maxStalenessSeconds) != MONGOC_NO_MAX_STALENESS) {
95+
if (mongoc_read_prefs_get_mode(intern->read_preference) == MONGOC_READ_PRIMARY) {
96+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"maxStalenessSeconds\" field to not be present with \"primary\" mode", ZSTR_VAL(php_phongo_readpreference_ce->name));
97+
goto failure;
98+
}
99+
if (Z_LVAL_P(maxStalenessSeconds) < MONGOC_SMALLEST_MAX_STALENESS_SECONDS) {
100+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"maxStalenessSeconds\" integer field to be >= %d", ZSTR_VAL(php_phongo_readpreference_ce->name), MONGOC_SMALLEST_MAX_STALENESS_SECONDS);
101+
goto failure;
102+
}
103+
if (Z_LVAL_P(maxStalenessSeconds) > INT32_MAX) {
104+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"maxStalenessSeconds\" integer field to be <= %" PRId32, ZSTR_VAL(php_phongo_readpreference_ce->name), INT32_MAX);
105+
goto failure;
106+
}
97107
}
98-
if (Z_LVAL_P(maxStalenessSeconds) > INT32_MAX) {
99-
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"maxStalenessSeconds\" integer field to be <= %" PRId32, ZSTR_VAL(php_phongo_readpreference_ce->name), INT32_MAX);
108+
109+
mongoc_read_prefs_set_max_staleness_seconds(intern->read_preference, Z_LVAL_P(maxStalenessSeconds));
110+
} else {
111+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"maxStalenessSeconds\" field to be integer", ZSTR_VAL(php_phongo_readpreference_ce->name));
112+
goto failure;
113+
}
114+
}
115+
116+
if ((hedge = zend_hash_str_find(props, "hedge", sizeof("hedge") - 1))) {
117+
if (Z_TYPE_P(hedge) == IS_ARRAY || Z_TYPE_P(hedge) == IS_OBJECT) {
118+
bson_t* hedge_doc = bson_new();
119+
120+
if (mongoc_read_prefs_get_mode(intern->read_preference) == MONGOC_READ_PRIMARY) {
121+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"hedge\" field to not be present with \"primary\" mode", ZSTR_VAL(php_phongo_readpreference_ce->name));
122+
bson_destroy(hedge_doc);
100123
goto failure;
101124
}
102-
if (mongoc_read_prefs_get_mode(intern->read_preference) == MONGOC_READ_PRIMARY) {
103-
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"maxStalenessSeconds\" array field to not be present with \"primary\" mode", ZSTR_VAL(php_phongo_readpreference_ce->name));
125+
126+
php_phongo_zval_to_bson(hedge, PHONGO_BSON_NONE, hedge_doc, NULL);
127+
128+
if (EG(exception)) {
129+
bson_destroy(hedge_doc);
104130
goto failure;
105131
}
106132

107-
mongoc_read_prefs_set_max_staleness_seconds(intern->read_preference, Z_LVAL_P(maxStalenessSeconds));
133+
mongoc_read_prefs_set_hedge(intern->read_preference, hedge_doc);
134+
bson_destroy(hedge_doc);
108135
} else {
109-
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"maxStalenessSeconds\" field to be integer", ZSTR_VAL(php_phongo_readpreference_ce->name));
136+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"hedge\" field to be an array or object", ZSTR_VAL(php_phongo_readpreference_ce->name));
110137
goto failure;
111138
}
112139
}
@@ -238,6 +265,33 @@ static PHP_METHOD(ReadPreference, __construct)
238265
mongoc_read_prefs_set_max_staleness_seconds(intern->read_preference, maxStalenessSeconds);
239266
}
240267

268+
if (options && php_array_exists(options, "hedge")) {
269+
zval* hedge = php_array_fetchc(options, "hedge");
270+
271+
if (Z_TYPE_P(hedge) == IS_ARRAY || Z_TYPE_P(hedge) == IS_OBJECT) {
272+
bson_t* hedge_doc = bson_new();
273+
274+
if (mongoc_read_prefs_get_mode(intern->read_preference) == MONGOC_READ_PRIMARY) {
275+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "hedge may not be used with primary mode");
276+
bson_destroy(hedge_doc);
277+
return;
278+
}
279+
280+
php_phongo_zval_to_bson(hedge, PHONGO_BSON_NONE, hedge_doc, NULL);
281+
282+
if (EG(exception)) {
283+
bson_destroy(hedge_doc);
284+
return;
285+
}
286+
287+
mongoc_read_prefs_set_hedge(intern->read_preference, hedge_doc);
288+
bson_destroy(hedge_doc);
289+
} else {
290+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s initialization requires \"hedge\" field to be an array or object", ZSTR_VAL(php_phongo_readpreference_ce->name));
291+
return;
292+
}
293+
}
294+
241295
if (!mongoc_read_prefs_is_valid(intern->read_preference)) {
242296
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Read preference is not valid");
243297
return;
@@ -264,6 +318,37 @@ static PHP_METHOD(ReadPreference, __set_state)
264318
php_phongo_readpreference_init_from_hash(intern, props);
265319
} /* }}} */
266320

321+
/* {{{ proto array|null MongoDB\Driver\ReadPreference::getHedge()
322+
Returns the ReadPreference hedge document */
323+
static PHP_METHOD(ReadPreference, getHedge)
324+
{
325+
php_phongo_readpreference_t* intern;
326+
const bson_t* hedge;
327+
328+
intern = Z_READPREFERENCE_OBJ_P(getThis());
329+
330+
if (zend_parse_parameters_none() == FAILURE) {
331+
return;
332+
}
333+
334+
hedge = mongoc_read_prefs_get_hedge(intern->read_preference);
335+
336+
if (!bson_empty0(hedge)) {
337+
php_phongo_bson_state state;
338+
339+
PHONGO_BSON_INIT_STATE(state);
340+
341+
if (!php_phongo_bson_to_zval_ex(bson_get_data(hedge), hedge->len, &state)) {
342+
zval_ptr_dtor(&state.zchild);
343+
return;
344+
}
345+
346+
RETURN_ZVAL(&state.zchild, 0, 1);
347+
} else {
348+
RETURN_NULL();
349+
}
350+
} /* }}} */
351+
267352
/* {{{ proto integer MongoDB\Driver\ReadPreference::getMaxStalenessSeconds()
268353
Returns the ReadPreference maxStalenessSeconds value */
269354
static PHP_METHOD(ReadPreference, getMaxStalenessSeconds)
@@ -353,11 +438,12 @@ static HashTable* php_phongo_readpreference_get_properties_hash(zval* object, bo
353438
HashTable* props;
354439
const char* modeString = NULL;
355440
const bson_t* tags;
441+
const bson_t* hedge;
356442
mongoc_read_mode_t mode;
357443

358444
intern = Z_READPREFERENCE_OBJ_P(object);
359445

360-
PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_debug, intern, props, 3);
446+
PHONGO_GET_PROPERTY_HASH_INIT_PROPS(is_debug, intern, props, 4);
361447

362448
if (!intern->read_preference) {
363449
return props;
@@ -366,6 +452,7 @@ static HashTable* php_phongo_readpreference_get_properties_hash(zval* object, bo
366452
tags = mongoc_read_prefs_get_tags(intern->read_preference);
367453
mode = mongoc_read_prefs_get_mode(intern->read_preference);
368454
modeString = php_phongo_readpreference_get_mode_string(mode);
455+
hedge = mongoc_read_prefs_get_hedge(intern->read_preference);
369456

370457
if (modeString) {
371458
zval z_mode;
@@ -398,6 +485,19 @@ static HashTable* php_phongo_readpreference_get_properties_hash(zval* object, bo
398485
zend_hash_str_update(props, "maxStalenessSeconds", sizeof("maxStalenessSeconds") - 1, &z_max_ss);
399486
}
400487

488+
if (!bson_empty0(hedge)) {
489+
php_phongo_bson_state state;
490+
491+
PHONGO_BSON_INIT_STATE(state);
492+
493+
if (!php_phongo_bson_to_zval_ex(bson_get_data(hedge), hedge->len, &state)) {
494+
zval_ptr_dtor(&state.zchild);
495+
goto done;
496+
}
497+
498+
zend_hash_str_update(props, "hedge", sizeof("hedge") - 1, &state.zchild);
499+
}
500+
401501
done:
402502
return props;
403503
} /* }}} */
@@ -424,6 +524,7 @@ static PHP_METHOD(ReadPreference, serialize)
424524
smart_str buf = { 0 };
425525
const char* modeString = NULL;
426526
const bson_t* tags;
527+
const bson_t* hedge;
427528
int64_t maxStalenessSeconds;
428529
mongoc_read_mode_t mode;
429530

@@ -441,8 +542,9 @@ static PHP_METHOD(ReadPreference, serialize)
441542
mode = mongoc_read_prefs_get_mode(intern->read_preference);
442543
modeString = php_phongo_readpreference_get_mode_string(mode);
443544
maxStalenessSeconds = mongoc_read_prefs_get_max_staleness_seconds(intern->read_preference);
545+
hedge = mongoc_read_prefs_get_hedge(intern->read_preference);
444546

445-
array_init_size(&retval, 3);
547+
array_init_size(&retval, 4);
446548

447549
if (modeString) {
448550
ADD_ASSOC_STRING(&retval, "mode", modeString);
@@ -465,6 +567,19 @@ static PHP_METHOD(ReadPreference, serialize)
465567
ADD_ASSOC_LONG_EX(&retval, "maxStalenessSeconds", maxStalenessSeconds);
466568
}
467569

570+
if (!bson_empty0(hedge)) {
571+
php_phongo_bson_state state;
572+
573+
PHONGO_BSON_INIT_STATE(state);
574+
575+
if (!php_phongo_bson_to_zval_ex(bson_get_data(hedge), hedge->len, &state)) {
576+
zval_ptr_dtor(&state.zchild);
577+
return;
578+
}
579+
580+
ADD_ASSOC_ZVAL_EX(&retval, "hedge", &state.zchild);
581+
}
582+
468583
PHP_VAR_SERIALIZE_INIT(var_hash);
469584
php_var_serialize(&buf, &retval, &var_hash);
470585
smart_str_0(&buf);
@@ -537,6 +652,7 @@ static zend_function_entry php_phongo_readpreference_me[] = {
537652
/* clang-format off */
538653
PHP_ME(ReadPreference, __construct, ai_ReadPreference___construct, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL)
539654
PHP_ME(ReadPreference, __set_state, ai_ReadPreference___set_state, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
655+
PHP_ME(ReadPreference, getHedge, ai_ReadPreference_void, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL)
540656
PHP_ME(ReadPreference, getMaxStalenessSeconds, ai_ReadPreference_void, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL)
541657
PHP_ME(ReadPreference, getMode, ai_ReadPreference_void, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL)
542658
PHP_ME(ReadPreference, getModeString, ai_ReadPreference_void, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL)

tests/readPreference/readpreference-ctor-001.phpt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_PRI
77
var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, [['tag' => 'one']]));
88
var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_PRIMARY, []));
99
var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, null, ['maxStalenessSeconds' => 1000]));
10+
var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, null, ['hedge' => ['enabled' => true]]));
11+
var_dump(new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, null, ['hedge' => []]));
1012

1113
?>
1214
===DONE===
@@ -38,4 +40,17 @@ object(MongoDB\Driver\ReadPreference)#%d (%d) {
3840
["maxStalenessSeconds"]=>
3941
int(1000)
4042
}
43+
object(MongoDB\Driver\ReadPreference)#%d (%d) {
44+
["mode"]=>
45+
string(9) "secondary"
46+
["hedge"]=>
47+
object(stdClass)#%d (%d) {
48+
["enabled"]=>
49+
bool(true)
50+
}
51+
}
52+
object(MongoDB\Driver\ReadPreference)#%d (%d) {
53+
["mode"]=>
54+
string(9) "secondary"
55+
}
4156
===DONE===
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
MongoDB\Driver\ReadPreference construction (combining hedge with primary read preference)
3+
--FILE--
4+
<?php
5+
6+
require_once __DIR__ . '/../utils/tools.php';
7+
8+
echo throws(function() {
9+
new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_PRIMARY, null, ['hedge' => ['enabled' => true]]);
10+
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";
11+
12+
?>
13+
===DONE===
14+
<?php exit(0); ?>
15+
--EXPECTF--
16+
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
17+
hedge may not be used with primary mode
18+
===DONE===

tests/readPreference/readpreference-debug-001.phpt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ $tests = [
1515
new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, [['dc' => 'ny']]),
1616
new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, [['dc' => 'ny'], ['dc' => 'sf', 'use' => 'reporting'], []]),
1717
new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, null, ['maxStalenessSeconds' => 1000]),
18+
new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, null, ['hedge' => ['enabled' => true]]),
1819
];
1920

2021
foreach ($tests as $test) {
@@ -89,4 +90,13 @@ object(MongoDB\Driver\ReadPreference)#%d (%d) {
8990
["maxStalenessSeconds"]=>
9091
int(1000)
9192
}
93+
object(MongoDB\Driver\ReadPreference)#%d (%d) {
94+
["mode"]=>
95+
string(9) "secondary"
96+
["hedge"]=>
97+
object(stdClass)#%d (%d) {
98+
["enabled"]=>
99+
bool(true)
100+
}
101+
}
92102
===DONE===
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
MongoDB\Driver\ReadPreference::getHedge()
3+
--FILE--
4+
<?php
5+
6+
require_once __DIR__ . '/../utils/tools.php';
7+
8+
$tests = [
9+
[],
10+
['enabled' => true],
11+
(object) ['enabled' => true],
12+
['foo' => 'bar'],
13+
];
14+
15+
foreach ($tests as $test) {
16+
$rp = new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, null, ['hedge' => $test]);
17+
var_dump($rp->getHedge());
18+
}
19+
20+
?>
21+
===DONE===
22+
<?php exit(0); ?>
23+
--EXPECTF--
24+
NULL
25+
object(stdClass)#%d (%d) {
26+
["enabled"]=>
27+
bool(true)
28+
}
29+
object(stdClass)#%d (%d) {
30+
["enabled"]=>
31+
bool(true)
32+
}
33+
object(stdClass)#%d (%d) {
34+
["foo"]=>
35+
string(3) "bar"
36+
}
37+
===DONE===

tests/readPreference/readpreference-serialization-001.phpt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ $tests = [
1515
new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, [['dc' => 'ny']]),
1616
new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, [['dc' => 'ny'], ['dc' => 'sf', 'use' => 'reporting'], []]),
1717
new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, null, ['maxStalenessSeconds' => 1000]),
18+
new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY, null, ['hedge' => ['enabled' => true]]),
1819
];
1920

2021
foreach ($tests as $test) {
@@ -184,4 +185,25 @@ object(MongoDB\Driver\ReadPreference)#%d (%d) {
184185
int(1000)
185186
}
186187

188+
object(MongoDB\Driver\ReadPreference)#%d (%d) {
189+
["mode"]=>
190+
string(9) "secondary"
191+
["hedge"]=>
192+
object(stdClass)#%d (%d) {
193+
["enabled"]=>
194+
bool(true)
195+
}
196+
}
197+
bool(true)
198+
C:29:"MongoDB\Driver\ReadPreference":82:{a:2:{s:4:"mode";s:9:"secondary";s:5:"hedge";O:8:"stdClass":1:{s:7:"enabled";b:1;}}}
199+
object(MongoDB\Driver\ReadPreference)#%d (%d) {
200+
["mode"]=>
201+
string(9) "secondary"
202+
["hedge"]=>
203+
object(stdClass)#%d (%d) {
204+
["enabled"]=>
205+
bool(true)
206+
}
207+
}
208+
187209
===DONE===

tests/readPreference/readpreference-set_state_error-001.phpt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ echo throws(function() {
3535
MongoDB\Driver\ReadPreference::__set_state(['mode' => 'primary', 'maxStalenessSeconds' => 100]);
3636
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";
3737

38+
39+
echo throws(function() {
40+
MongoDB\Driver\ReadPreference::__set_state(['mode' => 'secondary', 'hedge' => 'foo']);
41+
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";
42+
43+
echo throws(function() {
44+
MongoDB\Driver\ReadPreference::__set_state(['mode' => 'primary', 'hedge' => []]);
45+
}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n";
46+
3847
?>
3948
===DONE===
4049
<?php exit(0); ?>
@@ -52,5 +61,9 @@ MongoDB\Driver\ReadPreference initialization requires "tags" array field to not
5261
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
5362
MongoDB\Driver\ReadPreference initialization requires "maxStalenessSeconds" integer field to be >= 90
5463
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
55-
MongoDB\Driver\ReadPreference initialization requires "maxStalenessSeconds" array field to not be present with "primary" mode
64+
MongoDB\Driver\ReadPreference initialization requires "maxStalenessSeconds" field to not be present with "primary" mode
65+
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
66+
MongoDB\Driver\ReadPreference initialization requires "hedge" field to be an array or object
67+
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
68+
MongoDB\Driver\ReadPreference initialization requires "hedge" field to not be present with "primary" mode
5669
===DONE===

0 commit comments

Comments
 (0)