From ff83e5caec5f3bbf5bed3cf93bdbaeec907a933b Mon Sep 17 00:00:00 2001 From: Oliver Jowett Date: Mon, 19 Oct 2026 15:33:28 +0800 Subject: [PATCH] Rate-limit the size of faup1090 (fatsv) updates Try to generate no more than ~ 10kB/s of fatsv output. If we exceed that when generating output, stop generating more and remember where we were in the aircraft list, then resume from that point on the next update. Any aircraft that get delayed like this will just have their reporting times pushed out a bit, the actual data generated should still be fine (and up to date at the point of generation) This should help with high-traffic sites, especially on restart where suddenly every visible aircraft wants to generate a report at the same time. --- net_io.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/net_io.c b/net_io.c index 8abd51086..a3d1083e4 100644 --- a/net_io.c +++ b/net_io.c @@ -2648,6 +2648,7 @@ static void writeFATSV() { struct aircraft *a; static uint64_t next_update; + static uint32_t resume_at; // if non-zero, last scan stopped at this aircraft if (!Modes.fatsv_out.service || !Modes.fatsv_out.service->connections) { return; // not enabled or no active connections @@ -2661,7 +2662,25 @@ static void writeFATSV() // scan once a second at most next_update = now + 1000; - for (a = Modes.aircrafts; a; a = a->next) { + unsigned emitted = 0; // Bytes emitted so far this update + const unsigned BYTES_PER_UPDATE = 10000; // Generate up to about this many bytes per update + + // Find our starting point + a = Modes.aircrafts; + if (resume_at) { + for (; a; a = a->next) { + if (a->addr == resume_at) + break; + } + if (!a) { + // Missed the resume point (e.g. aircraft entry expired) + // just run the whole list again + a = Modes.aircrafts; + } + } + + // Scan until we've emitted enough, or reached the end of the list + for (; a && emitted < BYTES_PER_UPDATE; a = a->next) { if (!a->reliable) continue; @@ -2755,6 +2774,7 @@ static void writeFATSV() char *p = prepareWrite(&Modes.fatsv_out, TSV_MAX_PACKET_SIZE); if (!p) return; + char *start = p; char *end = p + TSV_MAX_PACKET_SIZE; p = appendFATSV(p, end, "_v", "%s", TSV_VERSION); @@ -2845,10 +2865,12 @@ static void writeFATSV() --p; // remove last tab p = safe_snprintf(p, end, "\n"); - if (p < end) + if (p < end) { + emitted += (p - start); completeWrite(&Modes.fatsv_out, p); - else + } else { fprintf(stderr, "fatsv: output too large (max %d, overran by %d)\n", TSV_MAX_PACKET_SIZE, (int) (p - end)); + } a->fatsv_emitted_altitude_baro = a->altitude_baro; a->fatsv_emitted_altitude_geom = a->altitude_geom; @@ -2886,6 +2908,12 @@ static void writeFATSV() a->fatsv_last_force_emit = now; } } + + // If we didn't completely scan the list, resume next time + // from the point where we stopped. We use the aircraft + // address to track this, to avoid worrying about the lifetime + // of the aircraft struct. + resume_at = a ? a->addr : 0; } //