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
}