vendor: update all dependencies to latest versions

This commit is contained in:
Nick Craig-Wood
2017-09-30 15:27:27 +01:00
parent 911d121bb9
commit b017fcfe9a
3048 changed files with 537055 additions and 189679 deletions
+190 -32
View File
@@ -201,6 +201,7 @@ func (s *session) refreshIdle() bool {
if s.valid && s.idleList != nil {
// session is in idle list, refresh its session id.
sid, s.id = s.id, sid
s.createTime = time.Now()
if s.tx != nil {
s.tx = nil
s.pool.idleWriteList.Remove(s.idleList)
@@ -351,17 +352,23 @@ type SessionPoolConfig struct {
// to be broken, it will still be evicted from session pool, therefore it is
// posssible that the number of opened sessions drops below MinOpened.
MinOpened uint64
// MaxSessionAge is the maximum duration that a session can be reused, zero
// maxSessionAge is the maximum duration that a session can be reused, zero
// means session pool will never expire sessions.
MaxSessionAge time.Duration
maxSessionAge time.Duration
// MaxIdle is the maximum number of idle sessions, pool is allowed to keep. Defaults to 0.
MaxIdle uint64
// MaxBurst is the maximum number of concurrent session creation requests. Defaults to 10.
MaxBurst uint64
// WriteSessions is the fraction of sessions we try to keep prepared for write.
WriteSessions float64
// HealthCheckWorkers is number of workers used by health checker for this pool.
HealthCheckWorkers int
// HealthCheckInterval is how often the health checker pings a session.
// HealthCheckInterval is how often the health checker pings a session. Defaults to 5 min.
HealthCheckInterval time.Duration
// healthCheckMaintainerEnabled enables the session pool maintainer.
healthCheckMaintainerEnabled bool
// healthCheckSampleInterval is how often the health checker samples live session (for use in maintaining session pool size). Defaults to 1 min.
healthCheckSampleInterval time.Duration
}
// errNoRPCGetter returns error for SessionPoolConfig missing getRPCClient method.
@@ -436,9 +443,13 @@ func newSessionPool(db string, config SessionPoolConfig, md metadata.MD) (*sessi
if config.HealthCheckInterval == 0 {
config.HealthCheckInterval = 5 * time.Minute
}
if config.healthCheckSampleInterval == 0 {
config.healthCheckSampleInterval = time.Minute
}
// On GCE VM, within the same region an healthcheck ping takes on average 10ms to finish, given a 5 minutes interval and
// 10 healthcheck workers, a healthChecker can effectively mantain 100 checks_per_worker/sec * 10 workers * 300 seconds = 300K sessions.
pool.hc = newHealthChecker(config.HealthCheckInterval, config.HealthCheckWorkers, pool)
pool.hc = newHealthChecker(config.HealthCheckInterval, config.HealthCheckWorkers, config.healthCheckSampleInterval, pool)
close(pool.hc.ready)
return pool, nil
}
@@ -666,15 +677,15 @@ func (p *sessionPool) recycle(s *session) bool {
// Reject the session if session is invalid or pool itself is invalid.
return false
}
if p.MaxSessionAge != 0 && s.createTime.Add(p.MaxSessionAge).Before(time.Now()) && p.numOpened > p.MinOpened {
// session expires and number of opened sessions exceeds MinOpened, let the session destroy itself.
if p.maxSessionAge != 0 && s.createTime.Add(p.maxSessionAge).Before(time.Now()) && p.numOpened > p.MinOpened {
// session expires and number of opened sessions exceeds MinOpened, let the session itself.
return false
}
// Hot sessions will be converging at the front of the list, cold sessions will be evicted by healthcheck workers.
// Put session at the back of the list to round robin for load balancing across channels.
if s.isWritePrepared() {
s.setIdleList(p.idleWriteList.PushFront(s))
s.setIdleList(p.idleWriteList.PushBack(s))
} else {
s.setIdleList(p.idleList.PushFront(s))
s.setIdleList(p.idleList.PushBack(s))
}
// Broadcast that a session has been returned to idle list.
close(p.mayGetSession)
@@ -762,21 +773,34 @@ type healthChecker struct {
waitWorkers sync.WaitGroup
// pool is the underlying session pool.
pool *sessionPool
// closed marks if a healthChecker has been closed.
closed bool
// sampleInterval is the interval of sampling by the maintainer.
sampleInterval time.Duration
// ready is used to signal that maintainer can start running.
ready chan struct{}
// done is used to signal that health checker should be closed.
done chan struct{}
// once is used for closing channel done only once.
once sync.Once
}
// newHealthChecker initializes new instance of healthChecker.
func newHealthChecker(interval time.Duration, workers int, pool *sessionPool) *healthChecker {
func newHealthChecker(interval time.Duration, workers int, sampleInterval time.Duration, pool *sessionPool) *healthChecker {
if workers <= 0 {
workers = 1
}
hc := &healthChecker{
interval: interval,
workers: workers,
pool: pool,
interval: interval,
workers: workers,
pool: pool,
sampleInterval: sampleInterval,
ready: make(chan struct{}),
done: make(chan struct{}),
}
for i := 0; i < hc.workers; i++ {
if hc.pool.healthCheckMaintainerEnabled {
hc.waitWorkers.Add(1)
go hc.maintainer()
}
for i := 1; i <= hc.workers; i++ {
hc.waitWorkers.Add(1)
go hc.worker(i)
}
@@ -785,17 +809,18 @@ func newHealthChecker(interval time.Duration, workers int, pool *sessionPool) *h
// close closes the healthChecker and waits for all healthcheck workers to exit.
func (hc *healthChecker) close() {
hc.mu.Lock()
hc.closed = true
hc.mu.Unlock()
hc.once.Do(func() { close(hc.done) })
hc.waitWorkers.Wait()
}
// isClosing checks if a healthChecker is already closing.
func (hc *healthChecker) isClosing() bool {
hc.mu.Lock()
defer hc.mu.Unlock()
return hc.closed
select {
case <-hc.done:
return true
default:
return false
}
}
// getInterval gets the healthcheck interval.
@@ -856,7 +881,7 @@ func (hc *healthChecker) healthCheck(s *session) {
s.destroy(false)
return
}
if s.pool.MaxSessionAge != 0 && s.createTime.Add(s.pool.MaxSessionAge).Before(time.Now()) {
if s.pool.maxSessionAge != 0 && s.createTime.Add(s.pool.maxSessionAge).Before(time.Now()) {
// Session reaches its maximum age, retire it. Failing that try to refresh it.
if s.destroy(true) || !s.refreshIdle() {
return
@@ -870,9 +895,6 @@ func (hc *healthChecker) healthCheck(s *session) {
// worker performs the healthcheck on sessions in healthChecker's priority queue.
func (hc *healthChecker) worker(i int) {
if log.V(2) {
log.Infof("Starting health check worker %v", i)
}
// Returns a session which we should ping to keep it alive.
getNextForPing := func() *session {
hc.pool.mu.Lock()
@@ -918,9 +940,6 @@ func (hc *healthChecker) worker(i int) {
for {
if hc.isClosing() {
if log.V(2) {
log.Infof("Closing health check worker %v", i)
}
// Exit when the pool has been closed and all sessions have been destroyed
// or when health checker has been closed.
hc.waitWorkers.Done()
@@ -929,8 +948,12 @@ func (hc *healthChecker) worker(i int) {
ws := getNextForTx()
if ws != nil {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
ws.prepareForWrite(contextWithOutgoingMetadata(ctx, hc.pool.md))
err := ws.prepareForWrite(contextWithOutgoingMetadata(ctx, hc.pool.md))
cancel()
if err != nil {
// TODO(dixiao): handle error properly
log.Errorf("prepareForWrite failed: %v", err)
}
hc.pool.recycle(ws)
hc.pool.mu.Lock()
hc.pool.prepareReqs--
@@ -945,7 +968,13 @@ func (hc *healthChecker) worker(i int) {
if pause > int64(hc.interval) {
pause = int64(hc.interval)
}
<-time.After(time.Duration(rand.Int63n(pause) + pause/2))
select {
case <-time.After(time.Duration(rand.Int63n(pause) + pause/2)):
break
case <-hc.done:
break
}
}
continue
}
@@ -953,6 +982,135 @@ func (hc *healthChecker) worker(i int) {
}
}
// maintainer maintains the maxSessionsInUse by a window of kWindowSize * sampleInterval.
// Based on this information, health checker will try to maintain the number of sessions by hc..
func (hc *healthChecker) maintainer() {
// Wait so that pool is ready.
<-hc.ready
var (
windowSize uint64 = 10
iteration uint64
timeout <-chan time.Time
)
// replenishPool is run if numOpened is less than sessionsToKeep, timeouts on sampleInterval.
replenishPool := func(sessionsToKeep uint64) {
ctx, _ := context.WithTimeout(context.Background(), hc.sampleInterval)
for {
select {
case <-timeout:
return
default:
break
}
p := hc.pool
p.mu.Lock()
// Take budget before the actual session creation.
if sessionsToKeep <= p.numOpened {
p.mu.Unlock()
break
}
p.numOpened++
p.createReqs++
shouldPrepareWrite := p.shouldPrepareWrite()
p.mu.Unlock()
var (
s *session
err error
)
if s, err = p.createSession(ctx); err != nil {
log.Warningf("Failed to create session, error: %v", toSpannerError(err))
continue
}
if shouldPrepareWrite {
if err = s.prepareForWrite(ctx); err != nil {
log.Warningf("Failed to prepare session, error: %v", toSpannerError(err))
continue
}
}
p.recycle(s)
}
}
// shrinkPool, scales down the session pool.
shrinkPool := func(sessionsToKeep uint64) {
for {
select {
case <-timeout:
return
default:
break
}
p := hc.pool
p.mu.Lock()
if sessionsToKeep >= p.numOpened {
p.mu.Unlock()
break
}
var s *session
if p.idleList.Len() > 0 {
s = p.idleList.Front().Value.(*session)
} else if p.idleWriteList.Len() > 0 {
s = p.idleWriteList.Front().Value.(*session)
}
p.mu.Unlock()
if s != nil {
// destroy session as expire.
s.destroy(true)
} else {
break
}
}
}
for {
if hc.isClosing() {
hc.waitWorkers.Done()
return
}
// maxSessionsInUse is the maximum number of sessions in use concurrently over a period of time.
var maxSessionsInUse uint64
// Updates metrics.
hc.pool.mu.Lock()
currSessionsInUse := hc.pool.numOpened - uint64(hc.pool.idleList.Len()) - uint64(hc.pool.idleWriteList.Len())
currSessionsOpened := hc.pool.numOpened
hc.pool.mu.Unlock()
hc.mu.Lock()
if iteration%windowSize == 0 || maxSessionsInUse < currSessionsInUse {
maxSessionsInUse = currSessionsInUse
}
sessionsToKeep := maxUint64(hc.pool.MinOpened,
minUint64(currSessionsOpened, hc.pool.MaxIdle+maxSessionsInUse))
hc.mu.Unlock()
timeout = time.After(hc.sampleInterval)
// Replenish or Shrink pool if needed.
// Note: we don't need to worry about pending create session requests, we only need to sample the current sessions in use.
// the routines will not try to create extra / delete creating sessions.
if sessionsToKeep > currSessionsOpened {
replenishPool(sessionsToKeep)
} else {
shrinkPool(sessionsToKeep)
}
select {
case <-timeout:
break
case <-hc.done:
break
}
iteration++
}
}
// shouldDropSession returns true if a particular error leads to the removal of a session
func shouldDropSession(err error) bool {
if err == nil {