Skip to content

Commit 326a7c6

Browse files
committed
CDRIVER-424 Fix node selection with read preference tags
1 parent 3baf761 commit 326a7c6

File tree

2 files changed

+62
-7
lines changed

2 files changed

+62
-7
lines changed

src/mongoc/mongoc-cluster.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,14 +743,22 @@ _mongoc_cluster_select (mongoc_cluster_t *cluster,
743743

744744
count = 0;
745745

746+
int scores[MONGOC_CLUSTER_MAX_NODES];
747+
int max_score = 0;
748+
746749
for (i = 0; i < MONGOC_CLUSTER_MAX_NODES; i++) {
747750
if (nodes[i]) {
748751
if (read_prefs) {
749752
int score = _mongoc_read_prefs_score(read_prefs, nodes[i]);
753+
scores[i] = score;
754+
750755
if (score < 0) {
751756
nodes[i] = NULL;
752757
continue;
758+
} else if (score > max_score) {
759+
max_score = score;
753760
}
761+
754762
}
755763
if (IS_NEARER_THAN(nodes[i], nearest)) {
756764
nearest = nodes[i]->ping_avg_msec;
@@ -776,6 +784,19 @@ _mongoc_cluster_select (mongoc_cluster_t *cluster,
776784
}
777785
}
778786

787+
/*
788+
* Filter nodes with score less than highest score.
789+
*/
790+
if (max_score) {
791+
for (i = 0; i < MONGOC_CLUSTER_MAX_NODES; i++) {
792+
if (nodes[i] && scores[i] < max_score) {
793+
nodes[i] = NULL;
794+
count--;
795+
}
796+
}
797+
}
798+
799+
779800
/*
780801
* Mark the error as unable to locate a target node.
781802
*/
@@ -1091,6 +1112,18 @@ _mongoc_cluster_ismaster (mongoc_cluster_t *cluster,
10911112
BSON_ITER_HOLDS_UTF8(&iter)) {
10921113
node->replSet = bson_iter_dup_utf8(&iter, NULL);
10931114
}
1115+
if (bson_iter_init_find(&iter, &reply, "tags") &&
1116+
BSON_ITER_HOLDS_DOCUMENT(&iter)) {
1117+
bson_t tags;
1118+
uint32_t len;
1119+
const uint8_t *data;
1120+
1121+
bson_iter_document(&iter, &len, &data);
1122+
1123+
if (bson_init_static(&tags, data, len)) {
1124+
bson_copy_to(&tags, &(node->tags));
1125+
}
1126+
}
10941127
}
10951128

10961129
ret = true;

src/mongoc/mongoc-read-prefs.c

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,24 +144,46 @@ _score_tags (const bson_t *read_tags,
144144
{
145145
uint32_t len;
146146
bson_iter_t iter;
147+
bson_iter_t sub_iter;
147148
const char *key;
148149
const char *str;
149150
int count;
150-
int i;
151+
bool node_matches_set;
151152

152153
bson_return_val_if_fail(read_tags, -1);
153154
bson_return_val_if_fail(node_tags, -1);
154155

155156
count = bson_count_keys(read_tags);
156157

158+
// Execute this block if read tags were provided, else bail and return 0 (all nodes equal)
157159
if (!bson_empty(read_tags) && bson_iter_init(&iter, read_tags)) {
158-
for (i = count; bson_iter_next(&iter); i--) {
159-
if (BSON_ITER_HOLDS_UTF8(&iter)) {
160-
key = bson_iter_key(&iter);
161-
str = bson_iter_utf8(&iter, &len);
162-
if (_contains_tag(node_tags, key, str, len)) {
163-
return count;
160+
161+
// Iterate over array of read tag sets provided (each element is a tag set)
162+
// Tag sets are provided in order of preference so return the count of the
163+
// first set that matches the node or -1 if no set matched the node.
164+
while (count && bson_iter_next(&iter)) {
165+
if (BSON_ITER_HOLDS_DOCUMENT(&iter) && bson_iter_recurse(&iter, &sub_iter)) {
166+
node_matches_set = true;
167+
168+
// Iterate over the key/value pairs (tags) in the current set
169+
while (bson_iter_next(&sub_iter) && BSON_ITER_HOLDS_UTF8(&sub_iter)) {
170+
key = bson_iter_key(&sub_iter);
171+
str = bson_iter_utf8(&sub_iter, &len);
172+
173+
// If any of the tags do not match, this node cannot satisfy this tag set.
174+
if (!_contains_tag(node_tags, key, str, len)) {
175+
node_matches_set = false;
176+
break;
177+
}
178+
}
179+
180+
// This set matched, return the count as the score
181+
if (node_matches_set) {
182+
return count;
164183
}
184+
185+
// Decrement the score and try to match the next set.
186+
count--;
165187
}
166188
}
167189
return -1;

0 commit comments

Comments
 (0)