src/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
188 / 210
89.5%
Branches:
337 / 606
55.6%
Functions:
7 / 8
87.5%

ps/rdma/rdma_deployment.cc
Line Branch Exec Source
1 #include "ps/rdma/rdma_deployment.h"
2
3 #include <algorithm>
4 #include <iomanip>
5 #include <sstream>
6 #include <stdexcept>
7
8 namespace recstore {
9
10 namespace {
11
12 12 std::string StableDigest(const json& value) {
13 12 std::uint64_t hash = 14695981039346656037ULL;
14
3/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 7 taken 5356 times.
✓ Branch 8 taken 12 times.
5368 for (unsigned char byte : value.dump()) {
15 5356 hash ^= byte;
16 5356 hash *= 1099511628211ULL;
17 12 }
18
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 std::ostringstream output;
19
4/8
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 12 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 12 times.
✗ Branch 13 not taken.
12 output << std::hex << std::setfill('0') << std::setw(16) << hash;
20
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
24 return output.str();
21 12 }
22
23 6 json CanonicalDeploymentConfig(const json& distributed_client,
24 const json& rdma_deployment) {
25
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 json canonical_client = distributed_client;
26
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 auto& servers = canonical_client["servers"];
27
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 std::sort(
28 6 servers.begin(), servers.end(), [](const json& lhs, const json& rhs) {
29 8 return lhs.at("shard").get<int>() < rhs.at("shard").get<int>();
30 });
31
32
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 json canonical_rdma = rdma_deployment;
33
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 auto& nodes = canonical_rdma["nodes"];
34
1/2
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
6 std::sort(nodes.begin(), nodes.end(), [](const json& lhs, const json& rhs) {
35 20 return lhs.at("node_id").get<int>() < rhs.at("node_id").get<int>();
36 });
37 return {
38 6 {"distributed_client", std::move(canonical_client)},
39 6 {"rdma_deployment", std::move(canonical_rdma)},
40
11/22
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 6 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 12 times.
✓ Branch 18 taken 6 times.
✓ Branch 20 taken 12 times.
✓ Branch 21 taken 6 times.
✓ Branch 23 taken 12 times.
✓ Branch 24 taken 6 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
60 };
41 6 }
42
43 } // namespace
44
45 ResolvedRdmaDeployment
46 72 ParseResolvedRdmaDeployment(const json& distributed_client) {
47
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
72 if (!distributed_client.is_object()) {
48
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw std::invalid_argument("RDMA distributed_client must be an object");
49 }
50
5/6
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 70 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 70 times.
142 if (!distributed_client.contains("num_shards") ||
51
2/4
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 70 times.
70 !distributed_client["num_shards"].is_number_integer()) {
52
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 throw std::invalid_argument("RDMA distributed_client.num_shards must be an "
53 4 "explicit positive integer");
54 }
55
2/4
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 70 times.
✗ Branch 5 not taken.
70 const int num_shards = distributed_client["num_shards"].get<int>();
56
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 66 times.
70 if (num_shards <= 0) {
57
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 throw std::invalid_argument("RDMA distributed_client.num_shards must be an "
58 8 "explicit positive integer");
59 }
60
5/6
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 64 times.
130 if (!distributed_client.contains("hash_method") ||
61
2/4
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 64 times.
64 !distributed_client["hash_method"].is_string()) {
62
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 throw std::invalid_argument(
63 4 "RDMA distributed_client.hash_method must be explicit");
64 }
65 const std::string hash_method =
66
2/4
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 64 times.
✗ Branch 5 not taken.
64 distributed_client["hash_method"].get<std::string>();
67
8/10
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 60 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 62 times.
64 if (hash_method != "city_hash" && hash_method != "simple_mod") {
68
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
2 throw std::invalid_argument("unsupported RDMA hash method: " + hash_method);
69 }
70
1/2
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
62 if (!distributed_client.contains("max_keys_per_request") ||
71
6/8
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 60 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 60 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 56 times.
122 !distributed_client["max_keys_per_request"].is_number_integer() ||
72
4/6
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 60 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 56 times.
60 distributed_client["max_keys_per_request"].get<int>() <= 0) {
73
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 throw std::invalid_argument("RDMA distributed_client.max_keys_per_request "
74 12 "must be explicit and positive");
75 }
76
1/2
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
56 if (!distributed_client.contains("servers") ||
77
6/8
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 54 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 54 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 50 times.
110 !distributed_client["servers"].is_array() ||
78
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 distributed_client["servers"].size() !=
79
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 50 times.
54 static_cast<std::size_t>(num_shards)) {
80
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 throw std::invalid_argument("RDMA distributed_client.servers must be an "
81 12 "array with one entry per shard");
82 }
83
84 50 ResolvedRdmaDeployment deployment;
85 50 deployment.num_shards = num_shards;
86
1/2
✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
50 deployment.hash_method = hash_method;
87 50 deployment.max_keys_per_request =
88
2/4
✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 50 times.
✗ Branch 5 not taken.
50 distributed_client["max_keys_per_request"].get<int>();
89
2/4
✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 50 times.
✗ Branch 6 not taken.
50 deployment.endpoints.reserve(distributed_client["servers"].size());
90
1/2
✓ Branch 2 taken 50 times.
✗ Branch 3 not taken.
50 std::vector<bool> seen_shards(static_cast<std::size_t>(num_shards), false);
91
6/10
✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 90 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 76 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 126 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 90 times.
✓ Branch 15 taken 36 times.
126 for (const auto& server : distributed_client["servers"]) {
92
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 88 times.
90 if (!server.is_object()) {
93
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 throw std::invalid_argument(
94 4 "RDMA distributed_client.servers entries must be objects");
95 }
96
6/10
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 88 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 88 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 88 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 86 times.
176 if (!server.contains("host") || !server["host"].is_string() ||
97
5/10
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 88 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 88 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 86 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
176 server["host"].get<std::string>().empty()) {
98
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 throw std::invalid_argument(
99 4 "RDMA distributed_client.servers[].host must be a non-empty string");
100 }
101
5/10
✓ Branch 1 taken 86 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 86 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 86 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 86 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 86 times.
86 if (!server.contains("port") || !server["port"].is_number_integer()) {
102
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ throw std::invalid_argument(
103 ✗ "RDMA distributed_client.servers[].port must be explicit");
104 }
105
2/4
✓ Branch 1 taken 86 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 86 times.
✗ Branch 5 not taken.
86 const int port = server["port"].get<int>();
106
4/4
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 82 times.
86 if (port < 1 || port > 65535) {
107
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 throw std::invalid_argument(
108 8 "RDMA distributed_client.servers[].port must be in [1, 65535]");
109 }
110
7/10
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 80 times.
✓ Branch 4 taken 2 times.
✓ Branch 6 taken 80 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 80 times.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 80 times.
82 if (!server.contains("shard") || !server["shard"].is_number_integer()) {
111
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 throw std::invalid_argument(
112 4 "RDMA distributed_client.servers[].shard must be explicit");
113 }
114
2/4
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 80 times.
✗ Branch 5 not taken.
80 const int shard = server["shard"].get<int>();
115
3/4
✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 78 times.
80 if (shard < 0 || shard >= num_shards) {
116
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 throw std::invalid_argument(
117 4 "RDMA distributed_client.servers[].shard is out of range");
118 }
119
3/4
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 76 times.
78 if (seen_shards[static_cast<std::size_t>(shard)]) {
120
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 throw std::invalid_argument(
121 4 "RDMA distributed_client.servers contains duplicate shard");
122 }
123
2/4
✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 76 times.
✗ Branch 5 not taken.
76 const std::string host = server["host"].get<std::string>();
124 76 const int endpoint_index = static_cast<int>(deployment.endpoints.size());
125
2/4
✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 76 times.
✗ Branch 5 not taken.
76 deployment.endpoints.push_back({host, port, shard});
126
1/2
✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
76 deployment.shard_to_endpoint_index.emplace(shard, endpoint_index);
127
1/2
✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
76 seen_shards[static_cast<std::size_t>(shard)] = true;
128 76 }
129
2/2
✓ Branch 6 taken 70 times.
✓ Branch 7 taken 36 times.
106 for (bool seen : seen_shards) {
130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if (!seen) {
131
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ throw std::invalid_argument(
132 ✗ "RDMA distributed_client.servers must cover every shard");
133 }
134 }
135 72 return deployment;
136 92 }
137
138 namespace {
139 36 RdmaFabricMode ParseMode(const json& node) {
140
1/2
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
36 const auto mode = node.value("mode", std::string());
141
2/2
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 8 times.
36 if (mode == "ib")
142 28 return RdmaFabricMode::kIb;
143
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if (mode == "rocev1")
144 ✗ return RdmaFabricMode::kRocEv1;
145
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 if (mode == "rocev2")
146 8 return RdmaFabricMode::kRocEv2;
147
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw std::invalid_argument("RDMA fabric mode must be ib, rocev1, or rocev2");
148 36 }
149 } // namespace
150
151 30 ResolvedRdmaDeployment ParseResolvedRdmaDeploymentConfig(const json& config) {
152
3/6
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 30 times.
60 if (!config.contains("distributed_client") ||
153
2/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 30 times.
30 !config.contains("rdma_deployment")) {
154
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw std::invalid_argument("RDMA config requires rdma_deployment");
155 }
156 auto deployment =
157
2/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
30 ParseResolvedRdmaDeployment(config.at("distributed_client"));
158
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 const auto& rdma = config.at("rdma_deployment");
159 118 if (!rdma.contains("deployment_id") ||
160
6/10
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 2 times.
✓ Branch 6 taken 28 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 28 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 28 times.
58 !rdma.at("deployment_id").is_string() ||
161
6/10
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 28 times.
✓ Branch 8 taken 2 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 28 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
58 rdma.at("deployment_id").get<std::string>().empty()) {
162
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 throw std::invalid_argument(
163 4 "rdma_deployment.deployment_id must be explicit and non-empty");
164 }
165
7/10
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 2 times.
✓ Branch 6 taken 26 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 26 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 26 times.
54 if (!rdma.contains("epoch") || !rdma.at("epoch").is_number_integer() ||
166
3/6
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 26 times.
26 rdma.at("epoch").get<std::int64_t>() <= 0) {
167
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 throw std::invalid_argument(
168 4 "rdma_deployment.epoch must be explicit and positive");
169 }
170
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 if (!rdma.contains("protocol_version") ||
171
6/8
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 24 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 24 times.
50 !rdma.at("protocol_version").is_number_integer() ||
172
3/6
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 24 times.
24 rdma.at("protocol_version").get<std::int64_t>() <= 0) {
173
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 throw std::invalid_argument(
174 4 "rdma_deployment.protocol_version must be explicit and positive");
175 }
176
2/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
24 deployment.deployment_id = rdma.at("deployment_id").get<std::string>();
177
2/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
24 deployment.epoch = rdma.at("epoch").get<std::uint64_t>();
178 24 deployment.protocol_version =
179
2/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
24 rdma.at("protocol_version").get<std::uint32_t>();
180
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 22 times.
24 if (deployment.protocol_version != kRdmaDeploymentProtocolVersion) {
181
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 throw std::invalid_argument("unsupported RDMA deployment protocol_version");
182 }
183
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 if (!rdma.contains("num_clients") ||
184
4/8
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 22 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 22 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 22 times.
44 !rdma.at("num_clients").is_number_integer() ||
185
3/6
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 22 times.
22 rdma.at("num_clients").get<int>() <= 0)
186
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ throw std::invalid_argument(
187 ✗ "rdma_deployment.num_clients must be explicit and positive");
188
2/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
22 deployment.num_clients = rdma.at("num_clients").get<int>();
189
9/12
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 22 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 20 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 18 times.
✓ Branch 13 taken 4 times.
✓ Branch 14 taken 18 times.
42 if (!rdma.contains("nodes") || !rdma.at("nodes").is_array() ||
190
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 rdma.at("nodes").empty()) {
191
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 throw std::invalid_argument(
192 8 "rdma_deployment.nodes must be a non-empty array");
193 }
194
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 const auto& nodes = rdma.at("nodes");
195
5/8
✓ Branch 3 taken 42 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 34 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 52 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 42 times.
✓ Branch 12 taken 10 times.
52 for (const auto& node : nodes) {
196
2/4
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
84 if (!node.is_object() || !node.contains("node_id") ||
197
4/8
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 42 times.
✗ Branch 9 not taken.
42 !node.contains("role") || !node.contains("device") ||
198
6/12
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 42 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 42 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 42 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 42 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 42 times.
84 !node.contains("port") || !node.contains("gid_index")) {
199
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ throw std::invalid_argument(
200 ✗ "fabric node requires node_id, role, device, port, gid_index");
201 }
202
1/2
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
42 if (!node.at("node_id").is_number_integer() ||
203
4/8
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 42 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 42 times.
✗ Branch 11 not taken.
42 !node.at("role").is_string() || !node.at("device").is_string() ||
204
4/8
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 42 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 42 times.
126 !node.at("port").is_number_integer() ||
205
2/4
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 42 times.
42 !node.at("gid_index").is_number_integer()) {
206
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw std::invalid_argument("RDMA fabric node fields have invalid types");
207 }
208
2/4
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
42 const int id = node.at("node_id").get<int>();
209
3/4
✓ Branch 5 taken 42 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 40 times.
42 if (!deployment.fabrics.emplace(id, ResolvedRdmaFabric{}).second) {
210
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 throw std::invalid_argument("duplicate RDMA fabric node_id");
211 }
212
1/2
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
40 auto& fabric = deployment.fabrics.at(id);
213
1/2
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
40 fabric.deployment_id = deployment.deployment_id;
214 40 fabric.deployment_epoch = deployment.epoch;
215 40 fabric.protocol_version = deployment.protocol_version;
216
2/4
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 40 times.
✗ Branch 5 not taken.
40 const auto role = node.at("role").get<std::string>();
217
6/10
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 30 times.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 10 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 40 times.
40 if (role != "server" && role != "client") {
218
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw std::invalid_argument("RDMA fabric role must be server or client");
219 }
220 40 const bool server = role == "server";
221
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 10 times.
40 fabric.role = server ? RdmaNodeRole::kServer : RdmaNodeRole::kClient;
222
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 10 times.
40 fabric.logical_id = server ? id : id - deployment.num_shards;
223
5/6
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
40 if ((server && (id >= deployment.num_shards || fabric.logical_id < 0)) ||
224
5/6
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
38 (!server && (id < deployment.num_shards || fabric.logical_id < 0 ||
225
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 fabric.logical_id >= deployment.num_clients)))
226
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 throw std::invalid_argument("RDMA fabric node_id/role is inconsistent");
227
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 fabric.mode = ParseMode(node);
228
2/4
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
36 fabric.device = node.at("device").get<std::string>();
229
2/4
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
36 fabric.port = node.at("port").get<int>();
230
2/4
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
36 fabric.gid_index = node.at("gid_index").get<int>();
231
2/4
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
✗ Branch 4 not taken.
72 if (fabric.device.empty() || fabric.port < 1 || fabric.port > 255 ||
232
4/8
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 36 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 36 times.
72 fabric.gid_index < 0 || id < 0) {
233
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw std::invalid_argument("RDMA fabric device/port/gid_index invalid");
234 }
235
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 28 times.
36 if (fabric.mode == RdmaFabricMode::kRocEv2) {
236
7/10
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 2 times.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 6 times.
14 if (!node.contains("hop_limit") || !node.contains("traffic_class") ||
237
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
6 !node.contains("flow_label")) {
238
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 throw std::invalid_argument(
239 4 "RoCE v2 requires hop_limit, traffic_class, flow_label");
240 }
241
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 fabric.hop_limit = node.at("hop_limit").get<int>();
242
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 fabric.traffic_class = node.at("traffic_class").get<int>();
243
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 fabric.flow_label = node.at("flow_label").get<std::uint32_t>();
244
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 if (fabric.hop_limit < 1 || fabric.hop_limit > 255 ||
245
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 fabric.traffic_class < 0 || fabric.traffic_class > 255 ||
246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 fabric.flow_label > 0xfffff) {
247
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ throw std::invalid_argument("RoCE v2 network fields are out of range");
248 }
249 }
250 40 }
251 10 if (deployment.fabrics.size() !=
252
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
10 static_cast<std::size_t>(deployment.num_shards + deployment.num_clients))
253
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 throw std::invalid_argument(
254 8 "RDMA fabric nodes must cover every server and client");
255 const json canonical =
256
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 CanonicalDeploymentConfig(config.at("distributed_client"), rdma);
257
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 deployment.configuration_digest = StableDigest(canonical);
258 deployment.fabric_digest =
259
3/6
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 6 times.
✗ Branch 8 not taken.
6 StableDigest(canonical.at("rdma_deployment").at("nodes"));
260
2/2
✓ Branch 7 taken 18 times.
✓ Branch 8 taken 6 times.
24 for (auto& [node_id, fabric] : deployment.fabrics) {
261 (void)node_id;
262
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 fabric.configuration_digest = deployment.configuration_digest;
263
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 fabric.fabric_digest = deployment.fabric_digest;
264 }
265 12 return deployment;
266 30 }
267
268 const ResolvedRdmaFabric&
269 ✗ LocalRdmaFabric(const ResolvedRdmaDeployment& deployment, int node_id) {
270
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ const auto it = deployment.fabrics.find(node_id);
271
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ if (it == deployment.fabrics.end()) {
272
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ throw std::invalid_argument(
273
0/4
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ "missing RDMA fabric for local node_id=" + std::to_string(node_id));
274 }
275 ✗ return it->second;
276 }
277
278 } // namespace recstore
279