This will make testing easier, as it's more similar to the actual prod
deployment. We don't have to rewrite anything in vite, as the host and
origin is the same.
Improve the performance of the unique function by:
1. Pre-allocating map capacity with len(s) to avoid frequent map resizing
2. Pre-allocating result slice capacity with len(s) to reduce append overhead
3. Reducing the number of traversals performs well under the condition of a large number of elements
These changes maintain the original behavior (preserving element order)
while reducing memory allocation operations, especially effective for
large slices (100k+ elements) with benchmark showing ~25% speedup.
No breaking changes, the function signature and output order remain unchanged.
We should use `(*regexp.Regexp).MatchString` instead of
`(*regexp.Regexp).Match([]byte(...))` when matching string to avoid
unnecessary `[]byte` conversions and reduce allocations.
Example benchmark:
var allowedOrigin = regexp.MustCompile(".*.example.com")
func BenchmarkMatch(b *testing.B) {
for i := 0; i < b.N; i++ {
if match := allowedOrigin.Match([]byte("www.example.com")); !match {
b.Fail()
}
}
}
func BenchmarkMatchString(b *testing.B) {
for i := 0; i < b.N; i++ {
if match := allowedOrigin.MatchString("wwww.example.com"); !match {
b.Fail()
}
}
}
goos: linux
goarch: amd64
pkg: github.com/gotify/server/v2/api/stream
cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
BenchmarkMatch-16 2076819 647.7 ns/op 16 B/op 1 allocs/op
BenchmarkMatchString-16 2536326 442.0 ns/op 0 B/op 0 allocs/op
PASS
ok github.com/gotify/server/v2/api/stream 3.552s
Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
GR = goroutine
[GR#1] http server gets closed
[GR#2] client.NotifyClose() will be executed
[GR#2] client.once.Do will be executed (lock's client.once.m)
[GR#1] stream.Close will be executed (lock's stream.lock)
[GR#1] client.Close will be executed (waits for client.once.m)
[GR#2] stream.remove will be executed (waits for stream.lock)
GR#1 holds lock stream.lock and waits for client.once.m
GR#2 holds lock client.once.m and waits for stream.lock
We prevent the deadlock with releasing the client.once.m lock earlier.