You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: update all documentation and landing page for preload performance
- README: new end-to-end benchmarks (137k req/sec), preload/gc_percent
config and env vars, updated architecture diagram with path cache
- CLI.md: add --preload and --gc-percent to flag reference
- USER_GUIDE.md: new 'Preloading for Maximum Performance' section,
GC tuning guide, Docker preload example, updated SIGHUP docs
- Landing page: hero stats show 137k req/sec, benchmark table replaces
old Docker numbers with localhost results (beats Bun), updated feature
cards, config tabs, structured data, and meta tags
-**`--verbose`**: calls `logConfig(cfg)` after all overrides are applied, so you see the final resolved values.
390
397
-**Version injection**: `internal/version.Version`, `Commit`, `Date` are set via `-ldflags` at build time. Default to `"dev"`, `"none"`, `"unknown"` for `go run`.
│ YES → serveFromCache (direct w.Write, no syscall) → done
129
126
│
130
127
└─ NO → resolveIndexPath → cache.Get(canonicalURL) hit?
131
128
YES → serveFromCache → done
132
129
NO → os.Stat → os.ReadFile → cache.Put → serveFromCache
133
130
```
134
131
132
+
When `preload = true`, every eligible file is loaded into cache at startup. The path-safety cache (`sync.Map`) is also pre-warmed, so the very first request for any preloaded file skips both filesystem I/O and `EvalSymlinks`.
133
+
135
134
---
136
135
137
136
## Performance
138
137
139
-
Benchmark numbers on Apple M2 Pro (`go test -bench=. -benchtime=5s`):
138
+
### End-to-end HTTP benchmarks
139
+
140
+
Measured on Apple M2 Pro, localhost (no Docker), serving 3 small static files via `bombardier -c 50 -n 100000`:
-**GC tuning**: `gc_percent = 400` reduces garbage collection frequency — the hot path is allocation-free, but `net/http` internals allocate per-request.
150
165
-**Cache-before-stat**: `os.Stat` is never called on a cache hit — the hot path is pure memory.
151
166
-**Zero-alloc `AcceptsEncoding`**: walks the `Accept-Encoding` header byte-by-byte without `strings.Split`.
152
167
-**Pooled `sync.Pool`**: both `gzip.Writer` and `statusResponseWriter` are pooled.
153
-
-**`filepath.Abs` at startup**: computed once during construction, never per-request.
154
168
-**Pre-computed `ETagFull`**: the `W/"..."` string is built when the file is cached.
155
169
156
170
---
@@ -211,6 +225,7 @@ Copy `config.toml.example` to `config.toml` and edit as needed. The server start
@@ -307,12 +327,13 @@ Set `tls_cert` and `tls_key` to enable HTTPS:
307
327
[server]
308
328
addr = ":80"
309
329
tls_addr = ":443"
330
+
redirect_host = "static.example.com"
310
331
tls_cert = "/etc/ssl/certs/server.pem"
311
332
tls_key = "/etc/ssl/private/server.key"
312
333
```
313
334
314
335
When TLS is configured:
315
-
- HTTP requests on `addr` are automatically **redirected** to `tls_addr`with `301 Moved Permanently`.
336
+
- HTTP requests on `addr` are automatically **redirected** to HTTPS. Set `redirect_host` when `tls_addr`listens on all interfaces (for example `:443`) so redirects use a canonical host instead of the incoming `Host` header.
316
337
-**HTTP/2** is enabled automatically via ALPN negotiation.
317
338
-**HSTS** (`Strict-Transport-Security`) is added to all HTTPS responses (configurable max-age).
318
339
- Minimum TLS version is **1.2**; preferred cipher suites are ECDHE+AES-256-GCM and ChaCha20-Poly1305.
@@ -348,9 +369,9 @@ make precompress # runs gzip and brotli on all .js/.css/.html/.json/.svg
348
369
|--------|--------|
349
370
|`SIGTERM`| Graceful shutdown (drains in-flight requests up to `shutdown_timeout`) |
350
371
|`SIGINT`| Graceful shutdown |
351
-
|`SIGHUP`| Flush in-memory cache; re-reads config pointer in `main`|
372
+
|`SIGHUP`| Flush in-memory file cache and path-safety cache; re-reads config pointer in `main`|
352
373
353
-
> **Note**: SIGHUP reloads the config pointer in `main` but the live middleware chain holds references to the old config. A full restart is required for config changes to take effect. SIGHUP is useful for flushing the cache without downtime.
374
+
> **Note**: SIGHUP reloads the config pointer in `main` but the live middleware chain holds references to the old config. A full restart is required for config changes to take effect. SIGHUP is useful for flushing both the file cache and the path-safety cache without downtime.
354
375
355
376
---
356
377
@@ -400,5 +421,4 @@ go test -race ./... # all tests, race-free
400
421
| Limitation | Detail |
401
422
|------------|--------|
402
423
|**Brotli on-the-fly**| Not implemented. Only pre-compressed `.br` sidecar files are served. |
403
-
|**Cache TTL not enforced**|`cache.ttl` is parsed but the expiry logic is not yet implemented. Use SIGHUP to flush manually. |
404
424
|**SIGHUP config reload**| Reloads the config struct pointer in `main` only. Live middleware chains hold old references — full restart required for config changes to propagate. |
0 commit comments