Skip to content

Commit 0118731

Browse files
committed
Add draft for LocalCluster
1 parent 1401f59 commit 0118731

4 files changed

Lines changed: 120 additions & 1 deletion

File tree

build.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ int main(int argc, char **argv) {
99
char *CXX = strcpy(calloc(1024, 1), or_else(getenv("CXX"), "g++"));
1010
char *EXEC_SUFFIX = strcpy(calloc(1024, 1), maybe(getenv("EXEC_SUFFIX")));
1111

12-
char *EXAMPLE_FILES[] = {"Http3Server", "Broadcast", "HelloWorld", "Crc32", "ServerName",
12+
char *EXAMPLE_FILES[] = {"LoadBalancer", "Http3Server", "Broadcast", "HelloWorld", "Crc32", "ServerName",
1313
"EchoServer", "BroadcastingEchoServer", "UpgradeSync", "UpgradeAsync", "ParameterRoutes"};
1414

1515
strcat(CXXFLAGS, " -march=native -O3 -Wpedantic -Wall -Wextra -Wsign-conversion -Wconversion -std=c++20 -Isrc -IuSockets/src");

examples/LoadBalancer.cpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#include "App.h"
2+
#include <thread>
3+
#include <algorithm>
4+
#include <mutex>
5+
6+
/* Note that SSL is disabled unless you build with WITH_OPENSSL=1 */
7+
const int SSL = 1;
8+
9+
unsigned int roundRobin = 0;
10+
unsigned int hardwareConcurrency = std::thread::hardware_concurrency();
11+
std::vector<std::thread *> threads(hardwareConcurrency);
12+
std::vector<uWS::SSLApp *> apps;
13+
std::mutex m;
14+
15+
namespace uWS {
16+
struct LocalCluster {
17+
18+
//std::vector<std::thread *> threads = std::thread::hardware_concurrency();
19+
std::vector<uWS::SSLApp *> apps;
20+
std::mutex m;
21+
22+
23+
static void loadBalancer() {
24+
static std::atomic<unsigned int> roundRobin = 0; // atomic fetch_add
25+
}
26+
27+
LocalCluster(SocketContextOptions options = {}, std::function<void(uWS::SSLApp &)> cb = nullptr) {
28+
29+
}
30+
};
31+
}
32+
33+
int main() {
34+
35+
// can be strictly round robin or not
36+
37+
// uWS::LocalCluster({
38+
// .key_file_name = "misc/key.pem",
39+
// .cert_file_name = "misc/cert.pem",
40+
// .passphrase = "1234"
41+
// },
42+
// [](uWS::SSLApp &app) {
43+
// /* Here this App instance is defined */
44+
// app.get("/*", [](auto *res, auto * /*req*/) {
45+
// res->end("Hello world!");
46+
// }).listen(3000, [](auto *listen_socket) {
47+
// if (listen_socket) {
48+
// /* Note that us_listen_socket_t is castable to us_socket_t */
49+
// std::cout << "Thread " << std::this_thread::get_id() << " listening on port " << us_socket_local_port(SSL, (struct us_socket_t *) listen_socket) << std::endl;
50+
// } else {
51+
// std::cout << "Thread " << std::this_thread::get_id() << " failed to listen on port 3000" << std::endl;
52+
// }
53+
// });
54+
// });
55+
56+
std::transform(threads.begin(), threads.end(), threads.begin(), [](std::thread *) {
57+
58+
return new std::thread([]() {
59+
60+
// lock this
61+
m.lock();
62+
apps.emplace_back(new uWS::SSLApp({
63+
.key_file_name = "misc/key.pem",
64+
.cert_file_name = "misc/cert.pem",
65+
.passphrase = "1234"
66+
}));
67+
uWS::SSLApp *app = apps.back();
68+
69+
app->get("/*", [](auto *res, auto * /*req*/) {
70+
res->end("Hello world!");
71+
}).listen(3000, [](auto *listen_socket) {
72+
if (listen_socket) {
73+
/* Note that us_listen_socket_t is castable to us_socket_t */
74+
std::cout << "Thread " << std::this_thread::get_id() << " listening on port " << us_socket_local_port(SSL, (struct us_socket_t *) listen_socket) << std::endl;
75+
} else {
76+
std::cout << "Thread " << std::this_thread::get_id() << " failed to listen on port 3000" << std::endl;
77+
}
78+
}).preOpen([](LIBUS_SOCKET_DESCRIPTOR fd) {
79+
80+
/* Distribute this socket in round robin fashion */
81+
std::cout << "About to load balance " << fd << " to " << roundRobin << std::endl;
82+
83+
auto receivingApp = apps[roundRobin];
84+
apps[roundRobin]->getLoop()->defer([fd, receivingApp]() {
85+
receivingApp->adoptSocket(fd);
86+
});
87+
88+
roundRobin = (roundRobin + 1) % hardwareConcurrency;
89+
return -1;
90+
});
91+
m.unlock();
92+
app->run();
93+
std::cout << "Fallthrough!" << std::endl;
94+
delete app;
95+
});
96+
});
97+
98+
std::for_each(threads.begin(), threads.end(), [](std::thread *t) {
99+
t->join();
100+
});
101+
}

src/App.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,12 @@ struct TemplatedApp {
575575
return std::move(*this);
576576
}
577577

578+
/* Register event handler for accepted FD. Can be used together with adoptSocket. */
579+
TemplatedApp &&preOpen(LIBUS_SOCKET_DESCRIPTOR (*handler)(LIBUS_SOCKET_DESCRIPTOR)) {
580+
httpContext->onPreOpen(handler);
581+
return std::move(*this);
582+
}
583+
578584
/* adopt an externally accepted socket */
579585
TemplatedApp &&adoptSocket(LIBUS_SOCKET_DESCRIPTOR accepted_fd) {
580586
httpContext->adoptAcceptedSocket(accepted_fd);
@@ -586,6 +592,10 @@ struct TemplatedApp {
586592
return std::move(*this);
587593
}
588594

595+
Loop *getLoop() {
596+
return (Loop *) httpContext->getLoop();
597+
}
598+
589599
};
590600

591601
typedef TemplatedApp<false> App;

src/HttpContext.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ struct HttpContext {
4646
/* Minimum allowed receive throughput per second (clients uploading less than 16kB/sec get dropped) */
4747
static const int HTTP_RECEIVE_THROUGHPUT_BYTES = 16 * 1024;
4848

49+
us_loop_t *getLoop() {
50+
return us_socket_context_loop(SSL, getSocketContext());
51+
}
52+
4953
us_socket_context_t *getSocketContext() {
5054
return (us_socket_context_t *) this;
5155
}
@@ -483,6 +487,10 @@ struct HttpContext {
483487
return us_socket_context_listen_unix(SSL, getSocketContext(), path, options, sizeof(HttpResponseData<SSL>));
484488
}
485489

490+
void onPreOpen(LIBUS_SOCKET_DESCRIPTOR (*handler)(LIBUS_SOCKET_DESCRIPTOR)) {
491+
us_socket_context_on_pre_open(SSL, getSocketContext(), handler);
492+
}
493+
486494
/* Adopt an externally accepted socket into this HttpContext */
487495
us_socket_t *adoptAcceptedSocket(LIBUS_SOCKET_DESCRIPTOR accepted_fd) {
488496
return us_adopt_accepted_socket(SSL, getSocketContext(), accepted_fd, sizeof(HttpResponseData<SSL>), 0, 0);

0 commit comments

Comments
 (0)