Use a real rate limiter to throttle Gitiles requests. Set the default so clients of android.googlesource.com wil not get throttled. Change-Id: Iace07b58bc5e45343071a99133b299eca16ea045
diff --git a/cmd/slothfs-expand-manifest/main.go b/cmd/slothfs-expand-manifest/main.go index a9ace1d..0e5dfb6 100644 --- a/cmd/slothfs-expand-manifest/main.go +++ b/cmd/slothfs-expand-manifest/main.go
@@ -34,7 +34,13 @@ log.Fatal("must set --gitiles") } - service, err := gitiles.NewService(*gitilesURL) + // SustainedQPS is a little high, but since this is a one-shot + // program let's try to get away with it. + service, err := gitiles.NewService(*gitilesURL, + gitiles.Options{ + BurstQPS: 10, + SustainedQPS: 5, + }) if err != nil { log.Fatal(err) }
diff --git a/cmd/slothfs-gitilesfs/main.go b/cmd/slothfs-gitilesfs/main.go index 628b7f1..85ad920 100644 --- a/cmd/slothfs-gitilesfs/main.go +++ b/cmd/slothfs-gitilesfs/main.go
@@ -48,7 +48,7 @@ log.Printf("NewCache: %v", err) } - service, err := gitiles.NewService(*url) + service, err := gitiles.NewService(*url, gitiles.Options{}) if err != nil { log.Printf("NewService: %v", err) }
diff --git a/cmd/slothfs-manifestfs/main.go b/cmd/slothfs-manifestfs/main.go index 1b3199a..c3f57d5 100644 --- a/cmd/slothfs-manifestfs/main.go +++ b/cmd/slothfs-manifestfs/main.go
@@ -57,7 +57,7 @@ log.Printf("NewCache: %v", err) } - service, err := gitiles.NewService(*gitilesURL) + service, err := gitiles.NewService(*gitilesURL, gitiles.Options{}) if err != nil { log.Printf("NewService: %v", err) }
diff --git a/cmd/slothfs-multifs/main.go b/cmd/slothfs-multifs/main.go index 31b076b..70912b8 100644 --- a/cmd/slothfs-multifs/main.go +++ b/cmd/slothfs-multifs/main.go
@@ -52,7 +52,7 @@ log.Printf("NewCache: %v", err) } - service, err := gitiles.NewService(*gitilesURL) + service, err := gitiles.NewService(*gitilesURL, gitiles.Options{}) if err != nil { log.Printf("NewService: %v", err) }
diff --git a/fs/gitilesfs_test.go b/fs/gitilesfs_test.go index bd53d25..0bbae9d 100644 --- a/fs/gitilesfs_test.go +++ b/fs/gitilesfs_test.go
@@ -576,7 +576,8 @@ } fixture.service, err = gitiles.NewService( - fmt.Sprintf("http://%s", fixture.testServer.listener.Addr().String())) + fmt.Sprintf("http://%s", fixture.testServer.listener.Addr().String()), + gitiles.Options{}) if err != nil { return nil, err }
diff --git a/gitiles/client.go b/gitiles/client.go index eb600ba..10cb86a 100644 --- a/gitiles/client.go +++ b/gitiles/client.go
@@ -25,12 +25,15 @@ "net/http" "net/url" "path" + + "golang.org/x/net/context" + "golang.org/x/time/rate" ) // Service is a client for the Gitiles JSON interface. type Service struct { - throttle chan struct{} - addr url.URL + limiter *rate.Limiter + addr url.URL } // Addr returns the address of the gitiles service. @@ -38,22 +41,39 @@ return s.addr.String() } +// Options specifies how much load we can put on remote Gitiles servers. +type Options struct { + BurstQPS int + SustainedQPS float64 +} + // NewService returns a new Gitiles JSON client. -func NewService(addr string) (*Service, error) { +func NewService(addr string, opts Options) (*Service, error) { + if opts.BurstQPS == 0 { + opts.BurstQPS = 4 + } + if opts.SustainedQPS == 0.0 { + opts.SustainedQPS = 0.5 + } + url, err := url.Parse(addr) if err != nil { return nil, err } return &Service{ - throttle: make(chan struct{}, 12), - addr: *url, + limiter: rate.NewLimiter(rate.Limit(opts.SustainedQPS), opts.BurstQPS), + addr: *url, }, nil } func (s *Service) get(u url.URL) ([]byte, error) { - s.throttle <- struct{}{} + ctx := context.Background() + + if err := s.limiter.Wait(ctx); err != nil { + return nil, err + } resp, err := http.Get(u.String()) - <-s.throttle + if err != nil { return nil, err }