99 "math/big"
1010 "net"
1111 "strings"
12+ "sync"
1213 "time"
1314
1415 "github.com/jmhodges/clock"
@@ -33,6 +34,11 @@ type SQLStorageAuthority struct {
3334 clk clock.Clock
3435 log blog.Logger
3536 scope metrics.Scope
37+
38+ // For RPCs that generate multiple, parallelizable SQL queries, this is the
39+ // max parallelism they will use (to avoid consuming too many MariaDB
40+ // threads).
41+ parallelismPerRPC int
3642}
3743
3844func digest256 (data []byte ) []byte {
@@ -69,14 +75,16 @@ func NewSQLStorageAuthority(
6975 clk clock.Clock ,
7076 logger blog.Logger ,
7177 scope metrics.Scope ,
78+ parallelismPerRPC int ,
7279) (* SQLStorageAuthority , error ) {
7380 SetSQLDebug (dbMap , logger )
7481
7582 ssa := & SQLStorageAuthority {
76- dbMap : dbMap ,
77- clk : clk ,
78- log : logger ,
79- scope : scope ,
83+ dbMap : dbMap ,
84+ clk : clk ,
85+ log : logger ,
86+ scope : scope ,
87+ parallelismPerRPC : parallelismPerRPC ,
8088 }
8189
8290 return ssa , nil
@@ -332,15 +340,60 @@ func (t TooManyCertificatesError) Error() string {
332340// The highest count this function can return is 10,000. If there are more
333341// certificates than that matching one of the provided domain names, it will return
334342// TooManyCertificatesError.
343+ // Queries will be run in parallel. If any of them error, only one error will
344+ // be returned.
335345func (ssa * SQLStorageAuthority ) CountCertificatesByNames (ctx context.Context , domains []string , earliest , latest time.Time ) ([]* sapb.CountByNames_MapElement , error ) {
336- var ret []* sapb.CountByNames_MapElement
346+ work := make (chan string , len (domains ))
347+ type result struct {
348+ err error
349+ count int
350+ domain string
351+ }
352+ results := make (chan result , len (domains ))
337353 for _ , domain := range domains {
338- currentCount , err := ssa .countCertificatesByName (domain , earliest , latest )
339- if err != nil {
340- return ret , err
354+ work <- domain
355+ }
356+ close (work )
357+ var wg sync.WaitGroup
358+ ctx , cancel := context .WithCancel (ctx )
359+ defer cancel ()
360+ // We may perform up to 100 queries, depending on what's in the certificate
361+ // request. Parallelize them so we don't hit our timeout, but limit the
362+ // parallelism so we don't consume too many threads on the database.
363+ for i := 0 ; i < ssa .parallelismPerRPC ; i ++ {
364+ wg .Add (1 )
365+ go func () {
366+ defer wg .Done ()
367+ for domain := range work {
368+ select {
369+ case <- ctx .Done ():
370+ results <- result {err : ctx .Err ()}
371+ return
372+ default :
373+ }
374+ currentCount , err := ssa .countCertificatesByName (domain , earliest , latest )
375+ if err != nil {
376+ results <- result {err : err }
377+ // Skip any further work
378+ cancel ()
379+ return
380+ }
381+ results <- result {
382+ count : currentCount ,
383+ domain : domain ,
384+ }
385+ }
386+ }()
387+ }
388+ wg .Wait ()
389+ close (results )
390+ var ret []* sapb.CountByNames_MapElement
391+ for r := range results {
392+ if r .err != nil {
393+ return nil , r .err
341394 }
342- name := string (domain )
343- pbCount := int64 (currentCount )
395+ name := string (r . domain )
396+ pbCount := int64 (r . count )
344397 ret = append (ret , & sapb.CountByNames_MapElement {
345398 Name : & name ,
346399 Count : & pbCount ,
0 commit comments