implement Scylla database
This commit is contained in:
22
vendor/github.com/hailocab/go-hostpool/.gitignore
generated
vendored
Normal file
22
vendor/github.com/hailocab/go-hostpool/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
0
vendor/github.com/hailocab/go-hostpool/.travis.yml
generated
vendored
Normal file
0
vendor/github.com/hailocab/go-hostpool/.travis.yml
generated
vendored
Normal file
21
vendor/github.com/hailocab/go-hostpool/LICENSE
generated
vendored
Normal file
21
vendor/github.com/hailocab/go-hostpool/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Bitly
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
17
vendor/github.com/hailocab/go-hostpool/README.md
generated
vendored
Normal file
17
vendor/github.com/hailocab/go-hostpool/README.md
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
go-hostpool
|
||||
===========
|
||||
|
||||
A Go package to intelligently and flexibly pool among multiple hosts from your Go application.
|
||||
Host selection can operate in round robin or epsilon greedy mode, and unresponsive hosts are
|
||||
avoided.
|
||||
Usage example:
|
||||
|
||||
```go
|
||||
hp := hostpool.NewEpsilonGreedy([]string{"a", "b"}, 0, &hostpool.LinearEpsilonValueCalculator{})
|
||||
hostResponse := hp.Get()
|
||||
hostname := hostResponse.Host()
|
||||
err := _ // (make a request with hostname)
|
||||
hostResponse.Mark(err)
|
||||
```
|
||||
|
||||
View more detailed documentation on [godoc.org](http://godoc.org/github.com/bitly/go-hostpool)
|
220
vendor/github.com/hailocab/go-hostpool/epsilon_greedy.go
generated
vendored
Normal file
220
vendor/github.com/hailocab/go-hostpool/epsilon_greedy.go
generated
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
package hostpool
|
||||
|
||||
import (
|
||||
"log"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
type epsilonHostPoolResponse struct {
|
||||
standardHostPoolResponse
|
||||
started time.Time
|
||||
ended time.Time
|
||||
}
|
||||
|
||||
func (r *epsilonHostPoolResponse) Mark(err error) {
|
||||
r.Do(func() {
|
||||
r.ended = time.Now()
|
||||
doMark(err, r)
|
||||
})
|
||||
}
|
||||
|
||||
type epsilonGreedyHostPool struct {
|
||||
standardHostPool // TODO - would be nifty if we could embed HostPool and Locker interfaces
|
||||
epsilon float32 // this is our exploration factor
|
||||
decayDuration time.Duration
|
||||
EpsilonValueCalculator // embed the epsilonValueCalculator
|
||||
timer
|
||||
quit chan bool
|
||||
}
|
||||
|
||||
// Construct an Epsilon Greedy HostPool
|
||||
//
|
||||
// Epsilon Greedy is an algorithm that allows HostPool not only to track failure state,
|
||||
// but also to learn about "better" options in terms of speed, and to pick from available hosts
|
||||
// based on how well they perform. This gives a weighted request rate to better
|
||||
// performing hosts, while still distributing requests to all hosts (proportionate to their performance).
|
||||
// The interface is the same as the standard HostPool, but be sure to mark the HostResponse immediately
|
||||
// after executing the request to the host, as that will stop the implicitly running request timer.
|
||||
//
|
||||
// A good overview of Epsilon Greedy is here http://stevehanov.ca/blog/index.php?id=132
|
||||
//
|
||||
// To compute the weighting scores, we perform a weighted average of recent response times, over the course of
|
||||
// `decayDuration`. decayDuration may be set to 0 to use the default value of 5 minutes
|
||||
// We then use the supplied EpsilonValueCalculator to calculate a score from that weighted average response time.
|
||||
func NewEpsilonGreedy(hosts []string, decayDuration time.Duration, calc EpsilonValueCalculator) HostPool {
|
||||
|
||||
if decayDuration <= 0 {
|
||||
decayDuration = defaultDecayDuration
|
||||
}
|
||||
stdHP := New(hosts).(*standardHostPool)
|
||||
p := &epsilonGreedyHostPool{
|
||||
standardHostPool: *stdHP,
|
||||
epsilon: float32(initialEpsilon),
|
||||
decayDuration: decayDuration,
|
||||
EpsilonValueCalculator: calc,
|
||||
timer: &realTimer{},
|
||||
quit: make(chan bool),
|
||||
}
|
||||
|
||||
// allocate structures
|
||||
for _, h := range p.hostList {
|
||||
h.epsilonCounts = make([]int64, epsilonBuckets)
|
||||
h.epsilonValues = make([]int64, epsilonBuckets)
|
||||
}
|
||||
go p.epsilonGreedyDecay()
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *epsilonGreedyHostPool) Close() {
|
||||
// No need to do p.quit <- true as close(p.quit) does the trick.
|
||||
close(p.quit)
|
||||
}
|
||||
|
||||
func (p *epsilonGreedyHostPool) SetEpsilon(newEpsilon float32) {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
p.epsilon = newEpsilon
|
||||
}
|
||||
|
||||
func (p *epsilonGreedyHostPool) SetHosts(hosts []string) {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
p.standardHostPool.setHosts(hosts)
|
||||
for _, h := range p.hostList {
|
||||
h.epsilonCounts = make([]int64, epsilonBuckets)
|
||||
h.epsilonValues = make([]int64, epsilonBuckets)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *epsilonGreedyHostPool) epsilonGreedyDecay() {
|
||||
durationPerBucket := p.decayDuration / epsilonBuckets
|
||||
ticker := time.NewTicker(durationPerBucket)
|
||||
for {
|
||||
select {
|
||||
case <-p.quit:
|
||||
ticker.Stop()
|
||||
return
|
||||
case <-ticker.C:
|
||||
p.performEpsilonGreedyDecay()
|
||||
}
|
||||
}
|
||||
}
|
||||
func (p *epsilonGreedyHostPool) performEpsilonGreedyDecay() {
|
||||
p.Lock()
|
||||
for _, h := range p.hostList {
|
||||
h.epsilonIndex += 1
|
||||
h.epsilonIndex = h.epsilonIndex % epsilonBuckets
|
||||
h.epsilonCounts[h.epsilonIndex] = 0
|
||||
h.epsilonValues[h.epsilonIndex] = 0
|
||||
}
|
||||
p.Unlock()
|
||||
}
|
||||
|
||||
func (p *epsilonGreedyHostPool) Get() HostPoolResponse {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
host := p.getEpsilonGreedy()
|
||||
if host == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
started := time.Now()
|
||||
return &epsilonHostPoolResponse{
|
||||
standardHostPoolResponse: standardHostPoolResponse{host: host, pool: p},
|
||||
started: started,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *epsilonGreedyHostPool) getEpsilonGreedy() string {
|
||||
var hostToUse *hostEntry
|
||||
|
||||
// this is our exploration phase
|
||||
if rand.Float32() < p.epsilon {
|
||||
p.epsilon = p.epsilon * epsilonDecay
|
||||
if p.epsilon < minEpsilon {
|
||||
p.epsilon = minEpsilon
|
||||
}
|
||||
return p.getRoundRobin()
|
||||
}
|
||||
|
||||
// calculate values for each host in the 0..1 range (but not ormalized)
|
||||
var possibleHosts []*hostEntry
|
||||
now := time.Now()
|
||||
var sumValues float64
|
||||
for _, h := range p.hostList {
|
||||
if h.canTryHost(now) {
|
||||
v := h.getWeightedAverageResponseTime()
|
||||
if v > 0 {
|
||||
ev := p.CalcValueFromAvgResponseTime(v)
|
||||
h.epsilonValue = ev
|
||||
sumValues += ev
|
||||
possibleHosts = append(possibleHosts, h)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(possibleHosts) != 0 {
|
||||
// now normalize to the 0..1 range to get a percentage
|
||||
for _, h := range possibleHosts {
|
||||
h.epsilonPercentage = h.epsilonValue / sumValues
|
||||
}
|
||||
|
||||
// do a weighted random choice among hosts
|
||||
ceiling := 0.0
|
||||
pickPercentage := rand.Float64()
|
||||
for _, h := range possibleHosts {
|
||||
ceiling += h.epsilonPercentage
|
||||
if pickPercentage <= ceiling {
|
||||
hostToUse = h
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hostToUse == nil {
|
||||
if len(possibleHosts) != 0 {
|
||||
log.Println("Failed to randomly choose a host, Dan loses")
|
||||
}
|
||||
|
||||
return p.getRoundRobin()
|
||||
}
|
||||
|
||||
if hostToUse.dead {
|
||||
hostToUse.willRetryHost(p.maxRetryInterval)
|
||||
}
|
||||
return hostToUse.host
|
||||
}
|
||||
|
||||
func (p *epsilonGreedyHostPool) markSuccess(hostR HostPoolResponse) {
|
||||
// first do the base markSuccess - a little redundant with host lookup but cleaner than repeating logic
|
||||
p.standardHostPool.markSuccess(hostR)
|
||||
eHostR, ok := hostR.(*epsilonHostPoolResponse)
|
||||
if !ok {
|
||||
log.Printf("Incorrect type in eps markSuccess!") // TODO reflection to print out offending type
|
||||
return
|
||||
}
|
||||
host := eHostR.host
|
||||
duration := p.between(eHostR.started, eHostR.ended)
|
||||
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
h, ok := p.hosts[host]
|
||||
if !ok {
|
||||
log.Fatalf("host %s not in HostPool %v", host, p.Hosts())
|
||||
}
|
||||
h.epsilonCounts[h.epsilonIndex]++
|
||||
h.epsilonValues[h.epsilonIndex] += int64(duration.Seconds() * 1000)
|
||||
}
|
||||
|
||||
// --- timer: this just exists for testing
|
||||
|
||||
type timer interface {
|
||||
between(time.Time, time.Time) time.Duration
|
||||
}
|
||||
|
||||
type realTimer struct{}
|
||||
|
||||
func (rt *realTimer) between(start time.Time, end time.Time) time.Duration {
|
||||
return end.Sub(start)
|
||||
}
|
40
vendor/github.com/hailocab/go-hostpool/epsilon_value_calculators.go
generated
vendored
Normal file
40
vendor/github.com/hailocab/go-hostpool/epsilon_value_calculators.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package hostpool
|
||||
|
||||
// --- Value Calculators -----------------
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// --- Definitions -----------------------
|
||||
|
||||
// Structs implementing this interface are used to convert the average response time for a host
|
||||
// into a score that can be used to weight hosts in the epsilon greedy hostpool. Lower response
|
||||
// times should yield higher scores (we want to select the faster hosts more often) The default
|
||||
// LinearEpsilonValueCalculator just uses the reciprocal of the response time. In practice, any
|
||||
// decreasing function from the positive reals to the positive reals should work.
|
||||
type EpsilonValueCalculator interface {
|
||||
CalcValueFromAvgResponseTime(float64) float64
|
||||
}
|
||||
|
||||
type LinearEpsilonValueCalculator struct{}
|
||||
type LogEpsilonValueCalculator struct{ LinearEpsilonValueCalculator }
|
||||
type PolynomialEpsilonValueCalculator struct {
|
||||
LinearEpsilonValueCalculator
|
||||
Exp float64 // the exponent to which we will raise the value to reweight
|
||||
}
|
||||
|
||||
// -------- Methods -----------------------
|
||||
|
||||
func (c *LinearEpsilonValueCalculator) CalcValueFromAvgResponseTime(v float64) float64 {
|
||||
return 1.0 / v
|
||||
}
|
||||
|
||||
func (c *LogEpsilonValueCalculator) CalcValueFromAvgResponseTime(v float64) float64 {
|
||||
// we need to add 1 to v so that this will be defined on all positive floats
|
||||
return c.LinearEpsilonValueCalculator.CalcValueFromAvgResponseTime(math.Log(v + 1.0))
|
||||
}
|
||||
|
||||
func (c *PolynomialEpsilonValueCalculator) CalcValueFromAvgResponseTime(v float64) float64 {
|
||||
return c.LinearEpsilonValueCalculator.CalcValueFromAvgResponseTime(math.Pow(v, c.Exp))
|
||||
}
|
62
vendor/github.com/hailocab/go-hostpool/host_entry.go
generated
vendored
Normal file
62
vendor/github.com/hailocab/go-hostpool/host_entry.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
package hostpool
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// --- hostEntry - this is due to get upgraded
|
||||
|
||||
type hostEntry struct {
|
||||
host string
|
||||
nextRetry time.Time
|
||||
retryCount int16
|
||||
retryDelay time.Duration
|
||||
dead bool
|
||||
epsilonCounts []int64
|
||||
epsilonValues []int64
|
||||
epsilonIndex int
|
||||
epsilonValue float64
|
||||
epsilonPercentage float64
|
||||
}
|
||||
|
||||
func (h *hostEntry) canTryHost(now time.Time) bool {
|
||||
if !h.dead {
|
||||
return true
|
||||
}
|
||||
if h.nextRetry.Before(now) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *hostEntry) willRetryHost(maxRetryInterval time.Duration) {
|
||||
h.retryCount += 1
|
||||
newDelay := h.retryDelay * 2
|
||||
if newDelay < maxRetryInterval {
|
||||
h.retryDelay = newDelay
|
||||
} else {
|
||||
h.retryDelay = maxRetryInterval
|
||||
}
|
||||
h.nextRetry = time.Now().Add(h.retryDelay)
|
||||
}
|
||||
|
||||
func (h *hostEntry) getWeightedAverageResponseTime() float64 {
|
||||
var value float64
|
||||
var lastValue float64
|
||||
|
||||
// start at 1 so we start with the oldest entry
|
||||
for i := 1; i <= epsilonBuckets; i += 1 {
|
||||
pos := (h.epsilonIndex + i) % epsilonBuckets
|
||||
bucketCount := h.epsilonCounts[pos]
|
||||
// Changing the line below to what I think it should be to get the weights right
|
||||
weight := float64(i) / float64(epsilonBuckets)
|
||||
if bucketCount > 0 {
|
||||
currentValue := float64(h.epsilonValues[pos]) / float64(bucketCount)
|
||||
value += currentValue * weight
|
||||
lastValue = currentValue
|
||||
} else {
|
||||
value += lastValue * weight
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
243
vendor/github.com/hailocab/go-hostpool/hostpool.go
generated
vendored
Normal file
243
vendor/github.com/hailocab/go-hostpool/hostpool.go
generated
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
// A Go package to intelligently and flexibly pool among multiple hosts from your Go application.
|
||||
// Host selection can operate in round robin or epsilon greedy mode, and unresponsive hosts are
|
||||
// avoided. A good overview of Epsilon Greedy is here http://stevehanov.ca/blog/index.php?id=132
|
||||
package hostpool
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Returns current version
|
||||
func Version() string {
|
||||
return "0.1"
|
||||
}
|
||||
|
||||
// --- Response interfaces and structs ----
|
||||
|
||||
// This interface represents the response from HostPool. You can retrieve the
|
||||
// hostname by calling Host(), and after making a request to the host you should
|
||||
// call Mark with any error encountered, which will inform the HostPool issuing
|
||||
// the HostPoolResponse of what happened to the request and allow it to update.
|
||||
type HostPoolResponse interface {
|
||||
Host() string
|
||||
Mark(error)
|
||||
hostPool() HostPool
|
||||
}
|
||||
|
||||
type standardHostPoolResponse struct {
|
||||
host string
|
||||
sync.Once
|
||||
pool HostPool
|
||||
}
|
||||
|
||||
// --- HostPool structs and interfaces ----
|
||||
|
||||
// This is the main HostPool interface. Structs implementing this interface
|
||||
// allow you to Get a HostPoolResponse (which includes a hostname to use),
|
||||
// get the list of all Hosts, and use ResetAll to reset state.
|
||||
type HostPool interface {
|
||||
Get() HostPoolResponse
|
||||
// keep the marks separate so we can override independently
|
||||
markSuccess(HostPoolResponse)
|
||||
markFailed(HostPoolResponse)
|
||||
|
||||
ResetAll()
|
||||
// ReturnUnhealthy when called with true will prevent an unhealthy node from
|
||||
// being returned and will instead return a nil HostPoolResponse. If using
|
||||
// this feature then you should check the result of Get for nil
|
||||
ReturnUnhealthy(v bool)
|
||||
Hosts() []string
|
||||
SetHosts([]string)
|
||||
|
||||
// Close the hostpool and release all resources.
|
||||
Close()
|
||||
}
|
||||
|
||||
type standardHostPool struct {
|
||||
sync.RWMutex
|
||||
hosts map[string]*hostEntry
|
||||
hostList []*hostEntry
|
||||
returnUnhealthy bool
|
||||
initialRetryDelay time.Duration
|
||||
maxRetryInterval time.Duration
|
||||
nextHostIndex int
|
||||
}
|
||||
|
||||
// ------ constants -------------------
|
||||
|
||||
const epsilonBuckets = 120
|
||||
const epsilonDecay = 0.90 // decay the exploration rate
|
||||
const minEpsilon = 0.01 // explore one percent of the time
|
||||
const initialEpsilon = 0.3
|
||||
const defaultDecayDuration = time.Duration(5) * time.Minute
|
||||
|
||||
// Construct a basic HostPool using the hostnames provided
|
||||
func New(hosts []string) HostPool {
|
||||
p := &standardHostPool{
|
||||
returnUnhealthy: true,
|
||||
hosts: make(map[string]*hostEntry, len(hosts)),
|
||||
hostList: make([]*hostEntry, len(hosts)),
|
||||
initialRetryDelay: time.Duration(30) * time.Second,
|
||||
maxRetryInterval: time.Duration(900) * time.Second,
|
||||
}
|
||||
|
||||
for i, h := range hosts {
|
||||
e := &hostEntry{
|
||||
host: h,
|
||||
retryDelay: p.initialRetryDelay,
|
||||
}
|
||||
p.hosts[h] = e
|
||||
p.hostList[i] = e
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (r *standardHostPoolResponse) Host() string {
|
||||
return r.host
|
||||
}
|
||||
|
||||
func (r *standardHostPoolResponse) hostPool() HostPool {
|
||||
return r.pool
|
||||
}
|
||||
|
||||
func (r *standardHostPoolResponse) Mark(err error) {
|
||||
r.Do(func() {
|
||||
doMark(err, r)
|
||||
})
|
||||
}
|
||||
|
||||
func doMark(err error, r HostPoolResponse) {
|
||||
if err == nil {
|
||||
r.hostPool().markSuccess(r)
|
||||
} else {
|
||||
r.hostPool().markFailed(r)
|
||||
}
|
||||
}
|
||||
|
||||
// return an entry from the HostPool
|
||||
func (p *standardHostPool) Get() HostPoolResponse {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
host := p.getRoundRobin()
|
||||
if host == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &standardHostPoolResponse{host: host, pool: p}
|
||||
}
|
||||
|
||||
func (p *standardHostPool) getRoundRobin() string {
|
||||
now := time.Now()
|
||||
hostCount := len(p.hostList)
|
||||
for i := range p.hostList {
|
||||
// iterate via sequenece from where we last iterated
|
||||
currentIndex := (i + p.nextHostIndex) % hostCount
|
||||
|
||||
h := p.hostList[currentIndex]
|
||||
if !h.dead {
|
||||
p.nextHostIndex = currentIndex + 1
|
||||
return h.host
|
||||
}
|
||||
if h.nextRetry.Before(now) {
|
||||
h.willRetryHost(p.maxRetryInterval)
|
||||
p.nextHostIndex = currentIndex + 1
|
||||
return h.host
|
||||
}
|
||||
}
|
||||
|
||||
// all hosts are down and returnUnhealhy is false then return no host
|
||||
if !p.returnUnhealthy {
|
||||
return ""
|
||||
}
|
||||
|
||||
// all hosts are down. re-add them
|
||||
p.doResetAll()
|
||||
p.nextHostIndex = 0
|
||||
return p.hostList[0].host
|
||||
}
|
||||
|
||||
func (p *standardHostPool) ResetAll() {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
p.doResetAll()
|
||||
}
|
||||
|
||||
func (p *standardHostPool) SetHosts(hosts []string) {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
p.setHosts(hosts)
|
||||
}
|
||||
|
||||
func (p *standardHostPool) ReturnUnhealthy(v bool) {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
p.returnUnhealthy = v
|
||||
}
|
||||
|
||||
func (p *standardHostPool) setHosts(hosts []string) {
|
||||
p.hosts = make(map[string]*hostEntry, len(hosts))
|
||||
p.hostList = make([]*hostEntry, len(hosts))
|
||||
|
||||
for i, h := range hosts {
|
||||
e := &hostEntry{
|
||||
host: h,
|
||||
retryDelay: p.initialRetryDelay,
|
||||
}
|
||||
p.hosts[h] = e
|
||||
p.hostList[i] = e
|
||||
}
|
||||
}
|
||||
|
||||
// this actually performs the logic to reset,
|
||||
// and should only be called when the lock has
|
||||
// already been acquired
|
||||
func (p *standardHostPool) doResetAll() {
|
||||
for _, h := range p.hosts {
|
||||
h.dead = false
|
||||
}
|
||||
}
|
||||
|
||||
func (p *standardHostPool) Close() {
|
||||
for _, h := range p.hosts {
|
||||
h.dead = true
|
||||
}
|
||||
}
|
||||
|
||||
func (p *standardHostPool) markSuccess(hostR HostPoolResponse) {
|
||||
host := hostR.Host()
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
h, ok := p.hosts[host]
|
||||
if !ok {
|
||||
log.Fatalf("host %s not in HostPool %v", host, p.Hosts())
|
||||
}
|
||||
h.dead = false
|
||||
}
|
||||
|
||||
func (p *standardHostPool) markFailed(hostR HostPoolResponse) {
|
||||
host := hostR.Host()
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
h, ok := p.hosts[host]
|
||||
if !ok {
|
||||
log.Fatalf("host %s not in HostPool %v", host, p.Hosts())
|
||||
}
|
||||
if !h.dead {
|
||||
h.dead = true
|
||||
h.retryCount = 0
|
||||
h.retryDelay = p.initialRetryDelay
|
||||
h.nextRetry = time.Now().Add(h.retryDelay)
|
||||
}
|
||||
|
||||
}
|
||||
func (p *standardHostPool) Hosts() []string {
|
||||
hosts := make([]string, 0, len(p.hosts))
|
||||
for host := range p.hosts {
|
||||
hosts = append(hosts, host)
|
||||
}
|
||||
return hosts
|
||||
}
|
Reference in New Issue
Block a user