proxy: rename + simplify + backpressure
- tcp_proxy/remote_proxy → tcp_proxy_client/tcp_proxy_server - Все proxy файлы перенесены в src/proxy/ - Конфиг: [tcp_proxy]→[tcp_proxy_client], [remote_proxy]→[tcp_proxy_server] - Убран subcmd CONNECTED (0x02) — клиент шлёт DATA сразу после CONNECT - Backpressure: etcp_router_waiter_register/cancel через ll_queue threshold waiter - Клиент: recv_cb send fail → tx_buf+waiter, не tcp_recved() (окно lwIP=0) - Сервер: read_cb send fail → pause_buf+waiter, пауза read_id - CLOSE/ERROR отправляется только после drain всех очередей - Fail: conn не найден/closed → send ERROR вместо CLOSE/silent drop - PROTOCOL.md: полная архитектура с диаграммами состояний и потоков
This commit is contained in:
1 parent
e7a9163011
commit
1f4fe37fe5
41 files changed
+1659
-659
No files matched your search
+158
-5
@@ -73,6 +73,15 @@ static void waiter_cb(struct ll_queue *q, void *arg) {
|
||||
(*(int*)arg)++; stats.cb_waiter++;
|
||||
}
|
||||
|
||||
static int waiter_order[10];
|
||||
static int waiter_order_idx;
|
||||
|
||||
static void waiter_cb_order(struct ll_queue *q, void *arg) {
|
||||
(void)q;
|
||||
waiter_order[waiter_order_idx++] = *(int*)arg;
|
||||
stats.cb_waiter++;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
static void test_basic(void) {
|
||||
TEST("basic creation / free");
|
||||
@@ -165,10 +174,13 @@ static void test_waiter(void) {
|
||||
TEST("wait_threshold + cancel");
|
||||
struct UASYNC *ua = uasync_create();
|
||||
struct ll_queue *q = queue_new(ua, 0, 0, 0, "q6");
|
||||
queue_set_threshold(q, 2, 0);
|
||||
|
||||
int called = 0;
|
||||
struct queue_waiter *w = queue_wait_threshold(q, 2, 0, waiter_cb, &called);
|
||||
ASSERT(w == NULL && called == 1, "immediate when condition met"); // empty queue
|
||||
struct queue_waiter_handle h;
|
||||
queue_waiter_handle_init(&h, waiter_cb, &called);
|
||||
int ret = queue_waiter_wait(q, &h);
|
||||
ASSERT(ret == 1 && called == 1, "immediate when condition met"); // empty queue
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
test_data_t *d = (test_data_t*)queue_entry_new(sizeof(*d)); d->id = i;
|
||||
@@ -176,15 +188,151 @@ static void test_waiter(void) {
|
||||
}
|
||||
|
||||
called = 0;
|
||||
w = queue_wait_threshold(q, 2, 0, waiter_cb, &called);
|
||||
ASSERT(w != NULL && called == 0, "");
|
||||
ret = queue_waiter_wait(q, &h);
|
||||
ASSERT(ret == 0 && called == 0, "");
|
||||
|
||||
for (int i = 0; i < 3; i++) queue_entry_free((struct ll_entry*)queue_data_get(q));
|
||||
|
||||
for (int i = 0; i < 15; i++) uasync_poll(ua, 1);
|
||||
ASSERT_EQ(called, 1, "");
|
||||
|
||||
queue_cancel_wait(q, w);
|
||||
queue_waiter_cancel(q, &h);
|
||||
queue_free(q); uasync_destroy(ua, 0);
|
||||
PASS();
|
||||
}
|
||||
|
||||
static void test_waiter_multiple(void) {
|
||||
TEST("waiter multiple FIFO (round-robin)");
|
||||
struct UASYNC *ua = uasync_create();
|
||||
struct ll_queue *q = queue_new(ua, 0, 0, 0, "wm");
|
||||
queue_set_threshold(q, 2, 0);
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
test_data_t *d = (test_data_t*)queue_entry_new(sizeof(*d)); d->id = i;
|
||||
queue_data_put(q, (struct ll_entry*)d);
|
||||
}
|
||||
|
||||
waiter_order_idx = 0;
|
||||
int ids[4] = {10, 20, 30, 40};
|
||||
struct queue_waiter_handle handles[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
queue_waiter_handle_init(&handles[i], waiter_cb_order, &ids[i]);
|
||||
ASSERT(queue_waiter_wait(q, &handles[i]) == 0, "should queue");
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++) queue_entry_free((struct ll_entry*)queue_data_get(q));
|
||||
ASSERT_EQ(waiter_order_idx, 3, "3 waiters fired");
|
||||
ASSERT(waiter_order[0] == 10 && waiter_order[1] == 20 && waiter_order[2] == 30, "FIFO order");
|
||||
|
||||
for (int i = 0; i < 4; i++) queue_waiter_cancel(q, &handles[i]);
|
||||
queue_free(q); uasync_destroy(ua, 0);
|
||||
PASS();
|
||||
}
|
||||
|
||||
static void test_waiter_cancel(void) {
|
||||
TEST("waiter cancel middle");
|
||||
struct UASYNC *ua = uasync_create();
|
||||
struct ll_queue *q = queue_new(ua, 0, 0, 0, "wc");
|
||||
queue_set_threshold(q, 3, 0);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
test_data_t *d = (test_data_t*)queue_entry_new(sizeof(*d)); d->id = i;
|
||||
queue_data_put(q, (struct ll_entry*)d);
|
||||
}
|
||||
|
||||
waiter_order_idx = 0;
|
||||
int ids[3] = {1, 2, 3};
|
||||
struct queue_waiter_handle handles[3];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
queue_waiter_handle_init(&handles[i], waiter_cb_order, &ids[i]);
|
||||
queue_waiter_wait(q, &handles[i]); // count=10 > 3, all queued
|
||||
}
|
||||
|
||||
queue_waiter_cancel(q, &handles[1]); // cancel middle (ID 2)
|
||||
|
||||
for (int i = 0; i < 10; i++) queue_entry_free((struct ll_entry*)queue_data_get(q));
|
||||
ASSERT_EQ(waiter_order_idx, 2, "2 fired (middle cancelled)");
|
||||
ASSERT(waiter_order[0] == 1 && waiter_order[1] == 3, "skip cancelled");
|
||||
|
||||
for (int i = 0; i < 3; i++) queue_waiter_cancel(q, &handles[i]);
|
||||
queue_free(q); uasync_destroy(ua, 0);
|
||||
PASS();
|
||||
}
|
||||
|
||||
static void test_waiter_queue_free(void) {
|
||||
TEST("queue_free clears waiters");
|
||||
struct UASYNC *ua = uasync_create();
|
||||
struct ll_queue *q = queue_new(ua, 0, 0, 0, "wf");
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
test_data_t *d = (test_data_t*)queue_entry_new(sizeof(*d)); d->id = i;
|
||||
queue_data_put(q, (struct ll_entry*)d);
|
||||
}
|
||||
|
||||
int called = 0;
|
||||
struct queue_waiter_handle h;
|
||||
queue_waiter_handle_init(&h, waiter_cb, &called);
|
||||
queue_waiter_wait(q, &h);
|
||||
ASSERT(h.internal != NULL, "waiter is queued");
|
||||
|
||||
queue_free(q);
|
||||
ASSERT(h.internal == NULL, "internal cleared by queue_free");
|
||||
uasync_destroy(ua, 0);
|
||||
PASS();
|
||||
}
|
||||
|
||||
static void test_waiter_threshold(void) {
|
||||
TEST("waiter dynamic threshold change");
|
||||
struct UASYNC *ua = uasync_create();
|
||||
struct ll_queue *q = queue_new(ua, 0, 0, 0, "wt");
|
||||
queue_set_threshold(q, 0, 0); // default, but explicit
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
test_data_t *d = (test_data_t*)queue_entry_new(sizeof(*d)); d->id = i;
|
||||
queue_data_put(q, (struct ll_entry*)d);
|
||||
}
|
||||
|
||||
int called = 0;
|
||||
struct queue_waiter_handle h;
|
||||
queue_waiter_handle_init(&h, waiter_cb, &called);
|
||||
int ret = queue_waiter_wait(q, &h);
|
||||
ASSERT(ret == 0 && called == 0, "queued (10 > 0)");
|
||||
|
||||
queue_set_threshold(q, 10, 0); // raise threshold
|
||||
queue_entry_free((struct ll_entry*)queue_data_get(q)); // count=9, check: 9 <= 10? YES
|
||||
ASSERT_EQ(called, 1, "fired after threshold raised");
|
||||
|
||||
while (queue_entry_count(q)) queue_entry_free((struct ll_entry*)queue_data_get(q));
|
||||
queue_free(q); uasync_destroy(ua, 0);
|
||||
PASS();
|
||||
}
|
||||
|
||||
static void test_waiter_reuse(void) {
|
||||
TEST("waiter handle reuse");
|
||||
struct UASYNC *ua = uasync_create();
|
||||
struct ll_queue *q = queue_new(ua, 0, 0, 0, "wr");
|
||||
|
||||
int called = 0;
|
||||
struct queue_waiter_handle h;
|
||||
queue_waiter_handle_init(&h, waiter_cb, &called);
|
||||
|
||||
int ret = queue_waiter_wait(q, &h);
|
||||
ASSERT(ret == 1 && called == 1, "immediate (empty queue)");
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
test_data_t *d = (test_data_t*)queue_entry_new(sizeof(*d)); d->id = i;
|
||||
queue_data_put(q, (struct ll_entry*)d);
|
||||
}
|
||||
|
||||
called = 0;
|
||||
ret = queue_waiter_wait(q, &h);
|
||||
ASSERT(ret == 0 && called == 0, "queued");
|
||||
|
||||
for (int i = 0; i < 3; i++) queue_entry_free((struct ll_entry*)queue_data_get(q));
|
||||
ASSERT_EQ(called, 1, "fired again on same handle");
|
||||
|
||||
queue_waiter_cancel(q, &h);
|
||||
ASSERT(h.internal == NULL, "internal cleared");
|
||||
queue_free(q); uasync_destroy(ua, 0);
|
||||
PASS();
|
||||
}
|
||||
@@ -284,6 +432,11 @@ int main(void) {
|
||||
test_lifo_priority();
|
||||
test_callback();
|
||||
test_waiter();
|
||||
test_waiter_multiple();
|
||||
test_waiter_cancel();
|
||||
test_waiter_queue_free();
|
||||
test_waiter_threshold();
|
||||
test_waiter_reuse();
|
||||
test_limits_hash();
|
||||
test_pool();
|
||||
test_stress();
|
||||
|
||||
Reference in new issue
Block a user