Include go-redsync v1.0.1 in vendor

This commit is contained in:
Tan Jiang 2018-01-24 15:30:20 +08:00
parent e9b656ce79
commit ea38b7eefe
13 changed files with 546 additions and 2 deletions

8
src/Gopkg.lock generated
View File

@ -120,6 +120,12 @@
revision = "47dc60e71eed504e3ef8e77ee3c6fe720f3be57f" revision = "47dc60e71eed504e3ef8e77ee3c6fe720f3be57f"
version = "v1.3.0" version = "v1.3.0"
[[projects]]
name = "github.com/go-redsync/redsync"
packages = ["."]
revision = "98dabdf1c8574561bf976911c14ff652c47b1ddf"
version = "v1.0.1"
[[projects]] [[projects]]
name = "github.com/go-sql-driver/mysql" name = "github.com/go-sql-driver/mysql"
packages = ["."] packages = ["."]
@ -258,6 +264,6 @@
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "1b5bec4304c99684de7fddc82ce9c81788e945f82455125110f32441a6ffd4cc" inputs-digest = "49328284c14629d33811bc9d67012a48314bb52bbb4ad7282699afbd4506f287"
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View File

@ -18,7 +18,7 @@
# [[override]] # [[override]]
# name = "github.com/x/y" # name = "github.com/x/y"
# version = "2.4.0" # version = "2.4.0"
ignored = ["github.com/vmware/harbor"]
[[constraint]] [[constraint]]
name = "github.com/astaxie/beego" name = "github.com/astaxie/beego"
@ -55,3 +55,7 @@
[[constraint]] [[constraint]]
name = "github.com/stretchr/testify" name = "github.com/stretchr/testify"
version = "1.2.0" version = "1.2.0"
[[constraint]]
name = "github.com/go-redsync/redsync"
version = "1.0.1"

View File

@ -0,0 +1,24 @@
before_script:
- mkdir -p $GOPATH/src/github.com/redsync
- ln -s $CI_PROJECT_DIR $GOPATH/src/github.com/redsync/redsync
- cd $GOPATH/src/github.com/redsync/redsync
- apt-get update
- apt-get -y install redis-server
stages:
- build
- test
build-go-1.5:
image: golang:1.5
stage: build
script:
- go get -v
- go build -v
test-go-1.5:
image: golang:1.5
stage: test
script:
- go get -v -t
- go test -v

27
src/vendor/github.com/go-redsync/redsync/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2016, Mahmud Ridwan
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the Redsync nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

29
src/vendor/github.com/go-redsync/redsync/README.md generated vendored Normal file
View File

@ -0,0 +1,29 @@
# Redsync
[![Build Status](https://drone.io/github.com/go-redsync/redsync/status.png)](https://drone.io/github.com/go-redsync/redsync/latest)
Redsync provides a Redis-based distributed mutual exclusion lock implementation for Go as described in [this post](http://redis.io/topics/distlock). A reference library (by [antirez](https://github.com/antirez)) for Ruby is available at [github.com/antirez/redlock-rb](https://github.com/antirez/redlock-rb).
## Installation
Install Redsync using the go get command:
$ go get gopkg.in/redsync.v1
The only dependencies are the Go distribution and [Redigo](github.com/garyburd/redigo).
## Documentation
- [Reference](https://godoc.org/gopkg.in/redsync.v1)
## Contributing
Contributions are welcome.
## License
Redsync is available under the [BSD (3-Clause) License](https://opensource.org/licenses/BSD-3-Clause).
## Disclaimer
This code implements an algorithm which is currently a proposal, it was not formally analyzed. Make sure to understand how it works before using it in production environments.

1
src/vendor/github.com/go-redsync/redsync/VERSION generated vendored Normal file
View File

@ -0,0 +1 @@
v1

4
src/vendor/github.com/go-redsync/redsync/doc.go generated vendored Normal file
View File

@ -0,0 +1,4 @@
// Package redsync provides a Redis-based distributed mutual exclusion lock implementation as described in the post http://redis.io/topics/distlock.
//
// Values containing the types defined in this package should not be copied.
package redsync

5
src/vendor/github.com/go-redsync/redsync/error.go generated vendored Normal file
View File

@ -0,0 +1,5 @@
package redsync
import "errors"
var ErrFailed = errors.New("redsync: failed to acquire lock")

145
src/vendor/github.com/go-redsync/redsync/mutex.go generated vendored Normal file
View File

@ -0,0 +1,145 @@
package redsync
import (
"crypto/rand"
"encoding/base64"
"sync"
"time"
"github.com/garyburd/redigo/redis"
)
// A Mutex is a distributed mutual exclusion lock.
type Mutex struct {
name string
expiry time.Duration
tries int
delay time.Duration
factor float64
quorum int
value string
until time.Time
nodem sync.Mutex
pools []Pool
}
// Lock locks m. In case it returns an error on failure, you may retry to acquire the lock by calling this method again.
func (m *Mutex) Lock() error {
m.nodem.Lock()
defer m.nodem.Unlock()
value, err := m.genValue()
if err != nil {
return err
}
for i := 0; i < m.tries; i++ {
if i != 0 {
time.Sleep(m.delay)
}
start := time.Now()
n := 0
for _, pool := range m.pools {
ok := m.acquire(pool, value)
if ok {
n++
}
}
until := time.Now().Add(m.expiry - time.Now().Sub(start) - time.Duration(int64(float64(m.expiry)*m.factor)) + 2*time.Millisecond)
if n >= m.quorum && time.Now().Before(until) {
m.value = value
m.until = until
return nil
}
for _, pool := range m.pools {
m.release(pool, value)
}
}
return ErrFailed
}
// Unlock unlocks m and returns the status of unlock. It is a run-time error if m is not locked on entry to Unlock.
func (m *Mutex) Unlock() bool {
m.nodem.Lock()
defer m.nodem.Unlock()
n := 0
for _, pool := range m.pools {
ok := m.release(pool, m.value)
if ok {
n++
}
}
return n >= m.quorum
}
// Extend resets the mutex's expiry and returns the status of expiry extension. It is a run-time error if m is not locked on entry to Extend.
func (m *Mutex) Extend() bool {
m.nodem.Lock()
defer m.nodem.Unlock()
n := 0
for _, pool := range m.pools {
ok := m.touch(pool, m.value, int(m.expiry/time.Millisecond))
if ok {
n++
}
}
return n >= m.quorum
}
func (m *Mutex) genValue() (string, error) {
b := make([]byte, 32)
_, err := rand.Read(b)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(b), nil
}
func (m *Mutex) acquire(pool Pool, value string) bool {
conn := pool.Get()
defer conn.Close()
reply, err := redis.String(conn.Do("SET", m.name, value, "NX", "PX", int(m.expiry/time.Millisecond)))
return err == nil && reply == "OK"
}
var deleteScript = redis.NewScript(1, `
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0
end
`)
func (m *Mutex) release(pool Pool, value string) bool {
conn := pool.Get()
defer conn.Close()
status, err := deleteScript.Do(conn, m.name, value)
return err == nil && status != 0
}
var touchScript = redis.NewScript(1, `
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("SET", KEYS[1], ARGV[1], "XX", "PX", ARGV[2])
else
return "ERR"
end
`)
func (m *Mutex) touch(pool Pool, value string, expiry int) bool {
conn := pool.Get()
defer conn.Close()
status, err := redis.String(touchScript.Do(conn, m.name, value, expiry))
return err == nil && status != "ERR"
}

180
src/vendor/github.com/go-redsync/redsync/mutex_test.go generated vendored Normal file
View File

@ -0,0 +1,180 @@
package redsync
import (
"strconv"
"testing"
"time"
"github.com/garyburd/redigo/redis"
"github.com/stvp/tempredis"
)
func TestMutex(t *testing.T) {
pools := newMockPools(8)
mutexes := newTestMutexes(pools, "test-mutex", 8)
orderCh := make(chan int)
for i, mutex := range mutexes {
go func(i int, mutex *Mutex) {
err := mutex.Lock()
if err != nil {
t.Fatalf("Expected err == nil, got %q", err)
}
defer mutex.Unlock()
assertAcquired(t, pools, mutex)
orderCh <- i
}(i, mutex)
}
for range mutexes {
<-orderCh
}
}
func TestMutexExtend(t *testing.T) {
pools := newMockPools(8)
mutexes := newTestMutexes(pools, "test-mutex-extend", 1)
mutex := mutexes[0]
err := mutex.Lock()
if err != nil {
t.Fatalf("Expected err == nil, got %q", err)
}
defer mutex.Unlock()
time.Sleep(1 * time.Second)
expiries := getPoolExpiries(pools, mutex.name)
ok := mutex.Extend()
if !ok {
t.Fatalf("Expected ok == true, got %v", ok)
}
expiries2 := getPoolExpiries(pools, mutex.name)
for i, expiry := range expiries {
if expiry >= expiries2[i] {
t.Fatalf("Expected expiries[%d] > expiry, got %d %d", i, expiries2[i], expiry)
}
}
}
func TestMutexQuorum(t *testing.T) {
pools := newMockPools(4)
for mask := 0; mask < 1<<uint(len(pools)); mask++ {
mutexes := newTestMutexes(pools, "test-mutex-partial-"+strconv.Itoa(mask), 1)
mutex := mutexes[0]
mutex.tries = 1
n := clogPools(pools, mask, mutex)
if n >= len(pools)/2+1 {
err := mutex.Lock()
if err != nil {
t.Fatalf("Expected err == nil, got %q", err)
}
assertAcquired(t, pools, mutex)
} else {
err := mutex.Lock()
if err != ErrFailed {
t.Fatalf("Expected err == %q, got %q", ErrFailed, err)
}
}
}
}
func newMockPools(n int) []Pool {
pools := []Pool{}
for _, server := range servers {
func(server *tempredis.Server) {
pools = append(pools, &redis.Pool{
MaxIdle: 3,
IdleTimeout: 240 * time.Second,
Dial: func() (redis.Conn, error) {
return redis.Dial("unix", server.Socket())
},
TestOnBorrow: func(c redis.Conn, t time.Time) error {
_, err := c.Do("PING")
return err
},
})
}(server)
if len(pools) == n {
break
}
}
return pools
}
func getPoolValues(pools []Pool, name string) []string {
values := []string{}
for _, pool := range pools {
conn := pool.Get()
value, err := redis.String(conn.Do("GET", name))
conn.Close()
if err != nil && err != redis.ErrNil {
panic(err)
}
values = append(values, value)
}
return values
}
func getPoolExpiries(pools []Pool, name string) []int {
expiries := []int{}
for _, pool := range pools {
conn := pool.Get()
expiry, err := redis.Int(conn.Do("PTTL", name))
conn.Close()
if err != nil && err != redis.ErrNil {
panic(err)
}
expiries = append(expiries, expiry)
}
return expiries
}
func clogPools(pools []Pool, mask int, mutex *Mutex) int {
n := 0
for i, pool := range pools {
if mask&(1<<uint(i)) == 0 {
n++
continue
}
conn := pool.Get()
_, err := conn.Do("SET", mutex.name, "foobar")
conn.Close()
if err != nil {
panic(err)
}
}
return n
}
func newTestMutexes(pools []Pool, name string, n int) []*Mutex {
mutexes := []*Mutex{}
for i := 0; i < n; i++ {
mutexes = append(mutexes, &Mutex{
name: name,
expiry: 8 * time.Second,
tries: 32,
delay: 500 * time.Millisecond,
factor: 0.01,
quorum: len(pools)/2 + 1,
pools: pools,
})
}
return mutexes
}
func assertAcquired(t *testing.T, pools []Pool, mutex *Mutex) {
n := 0
values := getPoolValues(pools, mutex.name)
for _, value := range values {
if value == mutex.value {
n++
}
}
if n < mutex.quorum {
t.Fatalf("Expected n >= %d, got %d", mutex.quorum, n)
}
}

8
src/vendor/github.com/go-redsync/redsync/redis.go generated vendored Normal file
View File

@ -0,0 +1,8 @@
package redsync
import "github.com/garyburd/redigo/redis"
// A Pool maintains a pool of Redis connections.
type Pool interface {
Get() redis.Conn
}

73
src/vendor/github.com/go-redsync/redsync/redsync.go generated vendored Normal file
View File

@ -0,0 +1,73 @@
package redsync
import "time"
// Redsync provides a simple method for creating distributed mutexes using multiple Redis connection pools.
type Redsync struct {
pools []Pool
}
// New creates and returns a new Redsync instance from given Redis connection pools.
func New(pools []Pool) *Redsync {
return &Redsync{
pools: pools,
}
}
// NewMutex returns a new distributed mutex with given name.
func (r *Redsync) NewMutex(name string, options ...Option) *Mutex {
m := &Mutex{
name: name,
expiry: 8 * time.Second,
tries: 32,
delay: 500 * time.Millisecond,
factor: 0.01,
quorum: len(r.pools)/2 + 1,
pools: r.pools,
}
for _, o := range options {
o.Apply(m)
}
return m
}
// An Option configures a mutex.
type Option interface {
Apply(*Mutex)
}
// OptionFunc is a function that configures a mutex.
type OptionFunc func(*Mutex)
// Apply calls f(mutex)
func (f OptionFunc) Apply(mutex *Mutex) {
f(mutex)
}
// SetExpiry can be used to set the expiry of a mutex to the given value.
func SetExpiry(expiry time.Duration) Option {
return OptionFunc(func(m *Mutex) {
m.expiry = expiry
})
}
// SetTries can be used to set the number of times lock acquire is attempted.
func SetTries(tries int) Option {
return OptionFunc(func(m *Mutex) {
m.tries = tries
})
}
// SetRetryDelay can be used to set the amount of time to wait between retries.
func SetRetryDelay(delay time.Duration) Option {
return OptionFunc(func(m *Mutex) {
m.delay = delay
})
}
// SetDriftFactor can be used to set the clock drift factor.
func SetDriftFactor(factor float64) Option {
return OptionFunc(func(m *Mutex) {
m.factor = factor
})
}

View File

@ -0,0 +1,38 @@
package redsync
import (
"os"
"testing"
"github.com/stvp/tempredis"
)
var servers []*tempredis.Server
func TestMain(m *testing.M) {
for i := 0; i < 8; i++ {
server, err := tempredis.Start(tempredis.Config{})
if err != nil {
panic(err)
}
servers = append(servers, server)
}
result := m.Run()
for _, server := range servers {
server.Term()
}
os.Exit(result)
}
func TestRedsync(t *testing.T) {
pools := newMockPools(8)
rs := New(pools)
mutex := rs.NewMutex("test-redsync")
err := mutex.Lock()
if err != nil {
}
assertAcquired(t, pools, mutex)
}