mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-23 10:45:45 +01:00
Merge pull request #4121 from reasonerjt/add-go-redsync-vendor
Include go-redsync v1.0.1 in vendor
This commit is contained in:
commit
2519601d9f
8
src/Gopkg.lock
generated
8
src/Gopkg.lock
generated
@ -120,6 +120,12 @@
|
||||
revision = "47dc60e71eed504e3ef8e77ee3c6fe720f3be57f"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-redsync/redsync"
|
||||
packages = ["."]
|
||||
revision = "98dabdf1c8574561bf976911c14ff652c47b1ddf"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-sql-driver/mysql"
|
||||
packages = ["."]
|
||||
@ -258,6 +264,6 @@
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "1b5bec4304c99684de7fddc82ce9c81788e945f82455125110f32441a6ffd4cc"
|
||||
inputs-digest = "49328284c14629d33811bc9d67012a48314bb52bbb4ad7282699afbd4506f287"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
@ -18,7 +18,7 @@
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
ignored = ["github.com/vmware/harbor"]
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/astaxie/beego"
|
||||
@ -55,3 +55,7 @@
|
||||
[[constraint]]
|
||||
name = "github.com/stretchr/testify"
|
||||
version = "1.2.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/go-redsync/redsync"
|
||||
version = "1.0.1"
|
||||
|
24
src/vendor/github.com/go-redsync/redsync/.gitlab-ci.yml
generated
vendored
Normal file
24
src/vendor/github.com/go-redsync/redsync/.gitlab-ci.yml
generated
vendored
Normal 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
27
src/vendor/github.com/go-redsync/redsync/LICENSE
generated
vendored
Normal 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
29
src/vendor/github.com/go-redsync/redsync/README.md
generated
vendored
Normal 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
1
src/vendor/github.com/go-redsync/redsync/VERSION
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
v1
|
4
src/vendor/github.com/go-redsync/redsync/doc.go
generated
vendored
Normal file
4
src/vendor/github.com/go-redsync/redsync/doc.go
generated
vendored
Normal 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
5
src/vendor/github.com/go-redsync/redsync/error.go
generated
vendored
Normal 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
145
src/vendor/github.com/go-redsync/redsync/mutex.go
generated
vendored
Normal 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
180
src/vendor/github.com/go-redsync/redsync/mutex_test.go
generated
vendored
Normal 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
8
src/vendor/github.com/go-redsync/redsync/redis.go
generated
vendored
Normal 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
73
src/vendor/github.com/go-redsync/redsync/redsync.go
generated
vendored
Normal 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
|
||||
})
|
||||
}
|
38
src/vendor/github.com/go-redsync/redsync/redsync_test.go
generated
vendored
Normal file
38
src/vendor/github.com/go-redsync/redsync/redsync_test.go
generated
vendored
Normal 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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user