-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathshape.go
More file actions
61 lines (55 loc) · 1.41 KB
/
Copy pathshape.go
File metadata and controls
61 lines (55 loc) · 1.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package qshape
import (
"runtime"
"sync"
"sync/atomic"
)
type (
// shapedQuery is one query's share of the parse work, computed once.
shapedQuery struct {
fingerprint string
canonical string
err error
}
)
const (
// Below this many queries the goroutine setup outweighs the parse work.
parallelShapeMin = 8
)
// fingerprintAll fingerprints every query, in parallel, returning results in input
// order. Workers pull indexes off a shared counter because per-query cost varies by
// orders of magnitude within one capture. Concurrency relies on libpg_query's
// thread-local memory contexts (pg_query_go v6); re-check on a major bump.
func fingerprintAll(queries []Query) []shapedQuery {
out := make([]shapedQuery, len(queries))
workers := runtime.GOMAXPROCS(0)
if len(queries) < parallelShapeMin || workers < 2 {
for i := range queries {
out[i].fingerprint, out[i].canonical, out[i].err = fingerprintNormalized(queries[i].Raw)
}
return out
}
if workers > len(queries) {
workers = len(queries)
}
var (
next atomic.Int64
wg sync.WaitGroup
)
wg.Add(workers)
for w := 0; w < workers; w++ {
go func() {
defer wg.Done()
for {
i := int(next.Add(1)) - 1
if i >= len(queries) {
return
}
// each worker writes its own index; no shared state
out[i].fingerprint, out[i].canonical, out[i].err = fingerprintNormalized(queries[i].Raw)
}
}()
}
wg.Wait()
return out
}