| 289 | |
| 290 | |
| 291 | std::multimap<MasterLoadTest::RequestDescriptor, Future<Response>> |
| 292 | MasterLoadTest::launchSimultaneousRequests( |
| 293 | const std::vector<RequestDescriptor>& descriptors) |
| 294 | { |
| 295 | // NOTE: On Mac, the default number of open files (and thus tcp connections) |
| 296 | // is limited to 256 by default, so this number is tweaked to stay slightly |
| 297 | // lower than that at 40*5==200 connections for the most demanding test. |
| 298 | const size_t REQUESTS_PER_DESCRIPTOR = 40; |
| 299 | const size_t totalRequests = REQUESTS_PER_DESCRIPTOR * descriptors.size(); |
| 300 | |
| 301 | std::multimap<RequestDescriptor, Future<Response>> requests; |
| 302 | |
| 303 | // Need this wrapper since `AWAIT_READY()` expects a `void` return type. |
| 304 | [&] { |
| 305 | // Send out all http requests based on the specifications |
| 306 | // found in `descriptors` and store the result in `requests`. |
| 307 | foreach (const RequestDescriptor& descriptor, descriptors) { |
| 308 | for (size_t i=0; i < REQUESTS_PER_DESCRIPTOR; ++i) { |
| 309 | Future<Response> response = process::http::get( |
| 310 | master_->pid, |
| 311 | descriptor.endpoint, |
| 312 | descriptor.query, |
| 313 | descriptor.headers); |
| 314 | |
| 315 | requests.emplace(descriptor, response); |
| 316 | } |
| 317 | } |
| 318 | |
| 319 | // Wait until all the HTTP events have reached the master and are now |
| 320 | // awaiting authorization. There might be some other requests that get |
| 321 | // mixed into the authorizer, so we must have ample requests in the |
| 322 | // test body to ensure cache hits. |
| 323 | Time whileLoopStartTime = Clock::now(); |
| 324 | Future<size_t> pendingHttpCalls; |
| 325 | do { |
| 326 | pendingHttpCalls = authorizer_->pending(); |
| 327 | AWAIT_READY(pendingHttpCalls); |
| 328 | // Protect against a potential infinite loop introduced by future bugs. |
| 329 | ASSERT_TRUE(Clock::now() - whileLoopStartTime < Seconds(20)); |
| 330 | } while (pendingHttpCalls.get() < totalRequests); |
| 331 | |
| 332 | |
| 333 | // Now block the master actor, since we don't want the master to start |
| 334 | // batching until it is queued up with all the HTTP requests. |
| 335 | // NOTE: This function might be out of scope when the dispatch is |
| 336 | // scheduled, so we need to pass `masterBlocker` by value. |
| 337 | auto masterBlocker = std::make_shared<Promise<Nothing>>(); |
| 338 | process::dispatch(master_->pid, [masterBlocker]() { |
| 339 | masterBlocker->future().await(); |
| 340 | }); |
| 341 | |
| 342 | // Unblock the BlockingAuthorizer. |
| 343 | // This should trigger all the deferrals onto the master from the |
| 344 | // Authorizer's thread. When this future completes, the master's queue |
| 345 | // should be full of batched requests. |
| 346 | AWAIT_READY(authorizer_->unleash()); |
| 347 | |
| 348 | // Unblock the master now, so it can perform the batching. |