This file is indexed.

/usr/share/gocode/src/github.com/jacobsa/ratelimit/throttle.go is in golang-github-jacobsa-ratelimit-dev 0.0~git20150723.0.2ca5e0c-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ratelimit

import (
	"time"

	"github.com/jacobsa/syncutil"

	"golang.org/x/net/context"
)

// A simple interface for limiting the rate of some event. Unlike TokenBucket,
// does not allow the user control over what time means.
//
// Safe for concurrent access.
type Throttle interface {
	// Return the maximum number of tokens that can be requested in a call to
	// Wait.
	Capacity() (c uint64)

	// Acquire the given number of tokens from the underlying token bucket, then
	// sleep until when it says to wake. If the context is cancelled before then,
	// return early with an error.
	//
	// REQUIRES: tokens <= capacity
	Wait(ctx context.Context, tokens uint64) (err error)
}

// Create a throttle that uses time.Now to judge the time given to the
// underlying token bucket.
//
// Be aware of the monotonicity issues. In particular:
//
//  *  If the system clock jumps into the future, the throttle will let through
//     a burst of traffic.
//
//  *  If the system clock jumps into the past, it will halt all traffic for
//     a potentially very long amount of time.
//
func NewThrottle(
	rateHz float64,
	capacity uint64) (t Throttle) {
	typed := &throttle{
		startTime: time.Now(),
		bucket:    NewTokenBucket(rateHz, capacity),
	}

	typed.mu = syncutil.NewInvariantMutex(typed.checkInvariants)

	t = typed
	return
}

type throttle struct {
	/////////////////////////
	// Constant data
	/////////////////////////

	startTime time.Time

	/////////////////////////
	// Mutable state
	/////////////////////////

	mu syncutil.InvariantMutex

	// INVARIANT: bucket.CheckInvariants()
	//
	// GUARDED_BY(mu)
	bucket TokenBucket
}

// LOCKS_REQUIRED(t.mu)
func (t *throttle) checkInvariants() {
	// INVARIANT: bucket.CheckInvariants()
	t.bucket.CheckInvariants()
}

// LOCKS_EXCLUDED(t.mu)
func (t *throttle) Capacity() (c uint64) {
	t.mu.Lock()
	c = t.bucket.Capacity()
	t.mu.Unlock()

	return
}

// LOCKS_EXCLUDED(t.mu)
func (t *throttle) Wait(
	ctx context.Context,
	tokens uint64) (err error) {
	now := MonotonicTime(time.Now().Sub(t.startTime))

	t.mu.Lock()
	sleepUntil := t.bucket.Remove(now, tokens)
	t.mu.Unlock()

	select {
	case <-ctx.Done():
		err = ctx.Err()
		return

	case <-time.After(time.Duration(sleepUntil - now)):
		return
	}
}