perf(relay): remove global lock and optimize ban list lookup

- Remove duplicate connection tracking from bps_manager.go; RelayServer's event loop (cmdCheckAndIncLimit/cmdDecLimit) already handles this - Replace O(N×M) ban list iteration with O(1) map lookup in view.go - Delete isLeaseBanned function, add buildBannedMap for single-pass conversion

cognitive-glitch committed Dec 9, 2025 at 12:55 UTC e83d08610b1adab7f9c295a2f1f6bbcdaa24cbc8
2 files changed +13 -40
cmd/relay-server/bps_manager.go
+3 -25
@@ -12,7 +12,7 @@ import (
12 // BPSManager manages per-lease bytes-per-second rate limiting
13 type BPSManager struct {
14 mu sync.Mutex
15 - bpsLimits map[string]int64 // leaseID -> bytes-per-second (0 = unlimited)
15 + bpsLimits map[string]int64 // leaseID -> bytes-per-second (0 = unlimited)
16 bpsBuckets map[string]*ratelimit.Bucket // leaseID -> rate limit bucket
17 defaultBPS int64 // default bytes-per-second for new leases
18 }
@@ -116,40 +116,18 @@ func (m *BPSManager) Copy(dst io.Writer, src io.Reader, leaseID string) (int64,
116 return ratelimit.Copy(dst, src, bucket)
117 }
118
119 -// Connection tracking for relay (package level)
120 -var (
121 - relayedPerLeaseCount = make(map[string]int)
122 - relayLimitsLock sync.Mutex
123 -)
124 -
125 -// establishRelayWithBPS sets up bidirectional relay with BPS limiting
119 +// establishRelayWithBPS sets up bidirectional relay with BPS limiting.
120 +// Connection tracking is handled by RelayServer's event loop (cmdCheckAndIncLimit/cmdDecLimit).
121 func establishRelayWithBPS(clientStream, leaseStream *yamux.Stream, leaseID string, bpsManager *BPSManager) {
127 - // Register connection
128 - relayLimitsLock.Lock()
129 - relayedPerLeaseCount[leaseID]++
130 - connectionCount := relayedPerLeaseCount[leaseID]
131 - relayLimitsLock.Unlock()
132 -
133 - // Log relay start
122 bpsLimit := bpsManager.GetBPSLimit(leaseID)
123 log.Info().
124 Str("lease_id", leaseID).
125 Int64("bps_limit", bpsLimit).
138 - Int("active_connections", connectionCount).
126 Msg("[Relay] Starting relay connection")
127
141 - // Cleanup function
128 defer func() {
143 - relayLimitsLock.Lock()
144 - if relayedPerLeaseCount[leaseID] > 0 {
145 - relayedPerLeaseCount[leaseID]--
146 - }
147 - remainingCount := relayedPerLeaseCount[leaseID]
148 - relayLimitsLock.Unlock()
149 -
129 log.Info().
130 Str("lease_id", leaseID).
152 - Int("remaining_connections", remainingCount).
131 Msg("[Relay] Relay connection closed")
132 }()
133
cmd/relay-server/view.go
+10 -15
@@ -449,6 +449,9 @@ func convertLeaseEntriesToRows(serv *portal.RelayServer) []leaseRow {
449 rows := []leaseRow{}
450 now := time.Now()
451
452 + // Build banned map once for O(1) lookup per lease
453 + bannedMap := buildBannedMap(serv.GetLeaseManager().GetBannedLeases())
454 +
455 for _, leaseEntry := range leaseEntries {
456 // Check if lease is still valid
457 if now.After(leaseEntry.Expires) {
@@ -459,7 +462,7 @@ func convertLeaseEntriesToRows(serv *portal.RelayServer) []leaseRow {
462 identityID := string(lease.Identity.Id)
463
464 // Skip banned leases for user-facing list
462 - if isLeaseBanned(serv, identityID) {
465 + if _, banned := bannedMap[identityID]; banned {
466 continue
467 }
468
@@ -574,21 +577,13 @@ func isLocalhost(r *http.Request) bool {
577 return host == "127.0.0.1" || host == "::1"
578 }
579
577 -// isLeaseBanned checks if a lease ID is in the banned list
578 -func isLeaseBanned(serv *portal.RelayServer, leaseID string) bool {
579 - bannedList := serv.GetLeaseManager().GetBannedLeases()
580 - for _, banned := range bannedList {
581 - bannedStr := string(banned)
582 - log.Debug().
583 - Str("checking_lease", leaseID).
584 - Str("banned_entry", bannedStr).
585 - Bool("match", bannedStr == leaseID).
586 - Msg("[BanCheck] Comparing lease IDs")
587 - if bannedStr == leaseID {
588 - return true
589 - }
580 +// buildBannedMap converts banned list to O(1) lookup map
581 +func buildBannedMap(bannedList [][]byte) map[string]struct{} {
582 + m := make(map[string]struct{}, len(bannedList))
583 + for _, b := range bannedList {
584 + m[string(b)] = struct{}{}
585 }
591 - return false
586 + return m
587 }
588
589 // AdminSettings stores persistent admin configuration