mirror of
https://github.com/rancher/steve.git
synced 2025-06-24 05:57:34 +00:00
Update vendor
This commit is contained in:
parent
c922b54153
commit
1dc21e0576
1
go.mod
1
go.mod
@ -16,7 +16,6 @@ require (
|
|||||||
github.com/rancher/wrangler-api v0.1.5-0.20190619170228-c3525df45215
|
github.com/rancher/wrangler-api v0.1.5-0.20190619170228-c3525df45215
|
||||||
github.com/sirupsen/logrus v1.4.2
|
github.com/sirupsen/logrus v1.4.2
|
||||||
github.com/urfave/cli v1.20.0
|
github.com/urfave/cli v1.20.0
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
|
||||||
google.golang.org/appengine v1.5.0 // indirect
|
google.golang.org/appengine v1.5.0 // indirect
|
||||||
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b
|
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b
|
||||||
k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8
|
k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8
|
||||||
|
2
vendor/github.com/rancher/norman/pkg/store/empty/empty_store.go
generated
vendored
2
vendor/github.com/rancher/norman/pkg/store/empty/empty_store.go
generated
vendored
@ -27,6 +27,6 @@ func (e *Store) Update(apiOp *types.APIRequest, schema *types.Schema, data types
|
|||||||
return types.APIObject{}, nil
|
return types.APIObject{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Store) Watch(apiOp *types.APIRequest, schema *types.Schema, opt *types.QueryOptions) (chan types.APIObject, error) {
|
func (e *Store) Watch(apiOp *types.APIRequest, schema *types.Schema, opt *types.QueryOptions) (chan types.APIEvent, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
2
vendor/github.com/rancher/norman/pkg/store/proxy/error_wrapper.go
generated
vendored
2
vendor/github.com/rancher/norman/pkg/store/proxy/error_wrapper.go
generated
vendored
@ -38,7 +38,7 @@ func (e *errorStore) Delete(apiOp *types.APIRequest, schema *types.Schema, id st
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *errorStore) Watch(apiOp *types.APIRequest, schema *types.Schema, opt *types.QueryOptions) (chan types.APIObject, error) {
|
func (e *errorStore) Watch(apiOp *types.APIRequest, schema *types.Schema, opt *types.QueryOptions) (chan types.APIEvent, error) {
|
||||||
data, err := e.Store.Watch(apiOp, schema, opt)
|
data, err := e.Store.Watch(apiOp, schema, opt)
|
||||||
return data, translateError(err)
|
return data, translateError(err)
|
||||||
}
|
}
|
||||||
|
36
vendor/github.com/rancher/norman/pkg/store/proxy/proxy_store.go
generated
vendored
36
vendor/github.com/rancher/norman/pkg/store/proxy/proxy_store.go
generated
vendored
@ -108,17 +108,22 @@ func (s *Store) listNamespace(namespace string, apiOp types.APIRequest, schema *
|
|||||||
return k8sClient.List(metav1.ListOptions{})
|
return k8sClient.List(metav1.ListOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) Watch(apiOp *types.APIRequest, schema *types.Schema, opt *types.QueryOptions) (chan types.APIObject, error) {
|
func (s *Store) Watch(apiOp *types.APIRequest, schema *types.Schema, opt *types.QueryOptions) (chan types.APIEvent, error) {
|
||||||
k8sClient, err := s.clientGetter.Client(apiOp, schema)
|
k8sClient, err := s.clientGetter.Client(apiOp, schema)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list, err := k8sClient.List(metav1.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
timeout := int64(60 * 30)
|
timeout := int64(60 * 30)
|
||||||
watcher, err := k8sClient.Watch(metav1.ListOptions{
|
watcher, err := k8sClient.Watch(metav1.ListOptions{
|
||||||
Watch: true,
|
Watch: true,
|
||||||
TimeoutSeconds: &timeout,
|
TimeoutSeconds: &timeout,
|
||||||
ResourceVersion: "0",
|
ResourceVersion: list.GetResourceVersion(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -131,15 +136,14 @@ func (s *Store) Watch(apiOp *types.APIRequest, schema *types.Schema, opt *types.
|
|||||||
watcher.Stop()
|
watcher.Stop()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
result := make(chan types.APIObject)
|
result := make(chan types.APIEvent)
|
||||||
go func() {
|
go func() {
|
||||||
|
for i, obj := range list.Items {
|
||||||
|
result <- s.toAPIEvent(apiOp, schema, i, len(list.Items), false, &obj)
|
||||||
|
}
|
||||||
for event := range watcher.ResultChan() {
|
for event := range watcher.ResultChan() {
|
||||||
data := event.Object.(*unstructured.Unstructured)
|
data := event.Object.(*unstructured.Unstructured)
|
||||||
s.fromInternal(apiOp, schema, data.Object)
|
result <- s.toAPIEvent(apiOp, schema, 0, 0, event.Type == watch.Deleted, data)
|
||||||
if event.Type == watch.Deleted && data.Object != nil {
|
|
||||||
data.Object[".removed"] = true
|
|
||||||
}
|
|
||||||
result <- types.ToAPI(data.Object)
|
|
||||||
}
|
}
|
||||||
logrus.Debugf("closing watcher for %s", schema.ID)
|
logrus.Debugf("closing watcher for %s", schema.ID)
|
||||||
close(result)
|
close(result)
|
||||||
@ -149,6 +153,22 @@ func (s *Store) Watch(apiOp *types.APIRequest, schema *types.Schema, opt *types.
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Store) toAPIEvent(apiOp *types.APIRequest, schema *types.Schema, index, count int, remove bool, obj *unstructured.Unstructured) types.APIEvent {
|
||||||
|
name := "resource.change"
|
||||||
|
if remove && obj.Object != nil {
|
||||||
|
name = "resource.remove"
|
||||||
|
}
|
||||||
|
|
||||||
|
s.fromInternal(apiOp, schema, obj.Object)
|
||||||
|
|
||||||
|
return types.APIEvent{
|
||||||
|
Name: name,
|
||||||
|
Count: count,
|
||||||
|
Index: index,
|
||||||
|
Object: types.ToAPI(obj.Object),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Store) Create(apiOp *types.APIRequest, schema *types.Schema, params types.APIObject) (types.APIObject, error) {
|
func (s *Store) Create(apiOp *types.APIRequest, schema *types.Schema, params types.APIObject) (types.APIObject, error) {
|
||||||
data := params.Map()
|
data := params.Map()
|
||||||
if err := s.toInternal(schema.Mapper, data); err != nil {
|
if err := s.toInternal(schema.Mapper, data); err != nil {
|
||||||
|
2
vendor/github.com/rancher/norman/pkg/store/schema/schema_store.go
generated
vendored
2
vendor/github.com/rancher/norman/pkg/store/schema/schema_store.go
generated
vendored
@ -34,7 +34,7 @@ func (s *Store) ByID(apiOp *types.APIRequest, schema *types.Schema, id string) (
|
|||||||
return types.APIObject{}, httperror.NewAPIError(httperror.NotFound, "no such schema")
|
return types.APIObject{}, httperror.NewAPIError(httperror.NotFound, "no such schema")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) Watch(apiOp *types.APIRequest, schema *types.Schema, opt *types.QueryOptions) (chan types.APIObject, error) {
|
func (s *Store) Watch(apiOp *types.APIRequest, schema *types.Schema, opt *types.QueryOptions) (chan types.APIEvent, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
57
vendor/github.com/rancher/norman/pkg/subscribe/handler.go
generated
vendored
57
vendor/github.com/rancher/norman/pkg/subscribe/handler.go
generated
vendored
@ -1,9 +1,10 @@
|
|||||||
package subscribe
|
package subscribe
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
@ -75,7 +76,7 @@ func handler(apiOp *types.APIRequest) error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
events := make(chan types.APIObject)
|
events := make(chan types.APIEvent)
|
||||||
for _, schema := range schemas {
|
for _, schema := range schemas {
|
||||||
if apiOp.AccessControl.CanWatch(apiOp, schema) == nil {
|
if apiOp.AccessControl.CanWatch(apiOp, schema) == nil {
|
||||||
streamStore(ctx, readerGroup, apiOp, schema, events)
|
streamStore(ctx, readerGroup, apiOp, schema, events)
|
||||||
@ -87,9 +88,10 @@ func handler(apiOp *types.APIRequest) error {
|
|||||||
close(events)
|
close(events)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
jsonWriter := writer.EncodingResponseWriter{
|
capture := &Capture{}
|
||||||
|
captureWriter := writer.EncodingResponseWriter{
|
||||||
ContentType: "application/json",
|
ContentType: "application/json",
|
||||||
Encoder: types.JSONEncoder,
|
Encoder: capture.Encoder,
|
||||||
}
|
}
|
||||||
t := time.NewTicker(60 * time.Second)
|
t := time.NewTicker(60 * time.Second)
|
||||||
defer t.Stop()
|
defer t.Stop()
|
||||||
@ -103,24 +105,20 @@ func handler(apiOp *types.APIRequest) error {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
header := `{"name":"resource.change","data":`
|
schema := apiOp.Schemas.Schema(convert.ToString(item.Object.Map()["type"]))
|
||||||
if item.Map()[".removed"] == true {
|
|
||||||
header = `{"name":"resource.remove","data":`
|
|
||||||
}
|
|
||||||
schema := apiOp.Schemas.Schema(convert.ToString(item.Map()["type"]))
|
|
||||||
if schema != nil {
|
if schema != nil {
|
||||||
buffer := &bytes.Buffer{}
|
if err := captureWriter.VersionBody(apiOp, nil, item.Object); err != nil {
|
||||||
if err := jsonWriter.VersionBody(apiOp, buffer, item); err != nil {
|
|
||||||
cancel()
|
cancel()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := writeData(c, header, buffer.Bytes()); err != nil {
|
item.Object = types.ToAPI(capture.Object)
|
||||||
|
if err := writeData(c, item); err != nil {
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case <-t.C:
|
case <-t.C:
|
||||||
if err := writeData(c, `{"name":"ping","data":`, []byte("{}")); err != nil {
|
if err := writeData(c, types.APIEvent{Name: "ping"}); err != nil {
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,35 +128,29 @@ func handler(apiOp *types.APIRequest) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeData(c *websocket.Conn, header string, buf []byte) error {
|
func writeData(c *websocket.Conn, event types.APIEvent) error {
|
||||||
|
event.Data = event.Object.Raw()
|
||||||
messageWriter, err := c.NextWriter(websocket.TextMessage)
|
messageWriter, err := c.NextWriter(websocket.TextMessage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer messageWriter.Close()
|
||||||
|
|
||||||
if _, err := messageWriter.Write([]byte(header)); err != nil {
|
return json.NewEncoder(messageWriter).Encode(event)
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := messageWriter.Write(buf); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := messageWriter.Write([]byte(`}`)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return messageWriter.Close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func watch(apiOp *types.APIRequest, schema *types.Schema, opts *types.QueryOptions) (chan types.APIObject, error) {
|
func watch(apiOp *types.APIRequest, schema *types.Schema, opts *types.QueryOptions) (chan types.APIEvent, error) {
|
||||||
c, err := schema.Store.Watch(apiOp, schema, opts)
|
c, err := schema.Store.Watch(apiOp, schema, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return types.APIChan(c, func(data types.APIObject) types.APIObject {
|
return types.APIChan(c, func(data types.APIEvent) types.APIEvent {
|
||||||
return apiOp.FilterObject(nil, schema, data)
|
data.Object = apiOp.FilterObject(nil, schema, data.Object)
|
||||||
|
return data
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func streamStore(ctx context.Context, eg *errgroup.Group, apiOp *types.APIRequest, schema *types.Schema, result chan types.APIObject) {
|
func streamStore(ctx context.Context, eg *errgroup.Group, apiOp *types.APIRequest, schema *types.Schema, result chan types.APIEvent) {
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
opts := parse.QueryOptions(apiOp, schema)
|
opts := parse.QueryOptions(apiOp, schema)
|
||||||
events, err := watch(apiOp, schema, &opts)
|
events, err := watch(apiOp, schema, &opts)
|
||||||
@ -185,3 +177,12 @@ func matches(items []string, item string) bool {
|
|||||||
}
|
}
|
||||||
return slice.ContainsString(items, item)
|
return slice.ContainsString(items, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Capture struct {
|
||||||
|
Object interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Capture) Encoder(w io.Writer, obj interface{}) error {
|
||||||
|
c.Object = obj
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
17
vendor/github.com/rancher/norman/pkg/types/server_types.go
generated
vendored
17
vendor/github.com/rancher/norman/pkg/types/server_types.go
generated
vendored
@ -189,11 +189,20 @@ type Store interface {
|
|||||||
Create(apiOp *APIRequest, schema *Schema, data APIObject) (APIObject, error)
|
Create(apiOp *APIRequest, schema *Schema, data APIObject) (APIObject, error)
|
||||||
Update(apiOp *APIRequest, schema *Schema, data APIObject, id string) (APIObject, error)
|
Update(apiOp *APIRequest, schema *Schema, data APIObject, id string) (APIObject, error)
|
||||||
Delete(apiOp *APIRequest, schema *Schema, id string) (APIObject, error)
|
Delete(apiOp *APIRequest, schema *Schema, id string) (APIObject, error)
|
||||||
Watch(apiOp *APIRequest, schema *Schema, opt *QueryOptions) (chan APIObject, error)
|
Watch(apiOp *APIRequest, schema *Schema, opt *QueryOptions) (chan APIEvent, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type APIEvent struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Count int `json:"count,omitempty"`
|
||||||
|
Index int `json:"index,omitempty"`
|
||||||
|
Object APIObject `json:"-"`
|
||||||
|
// Data should be used
|
||||||
|
Data interface{} `json:"data,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type APIObject struct {
|
type APIObject struct {
|
||||||
Object interface{} `json:",embed"`
|
Object interface{} `json:",inline"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToAPI(data interface{}) APIObject {
|
func ToAPI(data interface{}) APIObject {
|
||||||
@ -277,11 +286,11 @@ func Namespace(data map[string]interface{}) string {
|
|||||||
return convert.ToString(values.GetValueN(data, "metadata", "namespace"))
|
return convert.ToString(values.GetValueN(data, "metadata", "namespace"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func APIChan(c <-chan APIObject, f func(APIObject) APIObject) chan APIObject {
|
func APIChan(c <-chan APIEvent, f func(APIEvent) APIEvent) chan APIEvent {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
result := make(chan APIObject)
|
result := make(chan APIEvent)
|
||||||
go func() {
|
go func() {
|
||||||
for data := range c {
|
for data := range c {
|
||||||
modified := f(data)
|
modified := f(data)
|
||||||
|
62
vendor/github.com/rancher/norman/pkg/urlbuilder/base.go
generated
vendored
62
vendor/github.com/rancher/norman/pkg/urlbuilder/base.go
generated
vendored
@ -3,67 +3,53 @@ package urlbuilder
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseRequestURL(r *http.Request) string {
|
func ParseRequestURL(r *http.Request) string {
|
||||||
// Get url from standard headers
|
scheme := getScheme(r)
|
||||||
requestURL := getURLFromStandardHeaders(r)
|
host := getHost(r, scheme)
|
||||||
if requestURL != "" {
|
return fmt.Sprintf("%s://%s%s%s", scheme, host, r.Header.Get(PrefixHeader), r.URL.Path)
|
||||||
return requestURL
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use incoming url
|
|
||||||
scheme := "http"
|
|
||||||
if r.TLS != nil {
|
|
||||||
scheme = "https"
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s://%s%s%s", scheme, r.Host, r.Header.Get(PrefixHeader), r.URL.Path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getURLFromStandardHeaders(r *http.Request) string {
|
func getHost(r *http.Request, scheme string) string {
|
||||||
xForwardedProto := getOverrideHeader(r, ForwardedProtoHeader, "")
|
host := strings.Split(r.Header.Get(ForwardedHostHeader), ",")[0]
|
||||||
if xForwardedProto == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
host := getOverrideHeader(r, ForwardedHostHeader, "")
|
|
||||||
if host == "" {
|
if host == "" {
|
||||||
host = r.Host
|
host = r.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
if host == "" {
|
port := r.Header.Get(ForwardedPortHeader)
|
||||||
return ""
|
if port == "" {
|
||||||
|
return host
|
||||||
}
|
}
|
||||||
|
|
||||||
port := getOverrideHeader(r, ForwardedPortHeader, "")
|
if port == "80" && scheme == "http" {
|
||||||
if port == "443" || port == "80" {
|
return host
|
||||||
port = "" // Don't include default ports in url
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if port != "" && strings.Contains(host, ":") {
|
if port == "443" && scheme == "http" {
|
||||||
// Have to strip the port that is in the host. Handle IPv6, which has this format: [::1]:8080
|
return host
|
||||||
if (strings.HasPrefix(host, "[") && strings.Contains(host, "]:")) || !strings.HasPrefix(host, "[") {
|
|
||||||
host = host[0:strings.LastIndex(host, ":")]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if port != "" {
|
hostname, _, err := net.SplitHostPort(host)
|
||||||
port = ":" + port
|
if err != nil {
|
||||||
|
return host
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("%s://%s%s%s%s", xForwardedProto, host, port, r.Header.Get(PrefixHeader), r.URL.Path)
|
return strings.Join([]string{hostname, port}, ":")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOverrideHeader(r *http.Request, header string, defaultValue string) string {
|
func getScheme(r *http.Request) string {
|
||||||
// Need to handle comma separated hosts in X-Forwarded-For
|
scheme := r.Header.Get(ForwardedProtoHeader)
|
||||||
value := r.Header.Get(header)
|
if scheme != "" {
|
||||||
if value != "" {
|
return scheme
|
||||||
return strings.TrimSpace(strings.Split(value, ",")[0])
|
} else if r.TLS != nil {
|
||||||
|
return "https"
|
||||||
}
|
}
|
||||||
return defaultValue
|
return "http"
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseResponseURLBase(currentURL string, r *http.Request) (string, error) {
|
func ParseResponseURLBase(currentURL string, r *http.Request) (string, error) {
|
||||||
|
127
vendor/golang.org/x/sync/semaphore/semaphore.go
generated
vendored
127
vendor/golang.org/x/sync/semaphore/semaphore.go
generated
vendored
@ -1,127 +0,0 @@
|
|||||||
// Copyright 2017 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package semaphore provides a weighted semaphore implementation.
|
|
||||||
package semaphore // import "golang.org/x/sync/semaphore"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"container/list"
|
|
||||||
"context"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type waiter struct {
|
|
||||||
n int64
|
|
||||||
ready chan<- struct{} // Closed when semaphore acquired.
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWeighted creates a new weighted semaphore with the given
|
|
||||||
// maximum combined weight for concurrent access.
|
|
||||||
func NewWeighted(n int64) *Weighted {
|
|
||||||
w := &Weighted{size: n}
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
|
|
||||||
// Weighted provides a way to bound concurrent access to a resource.
|
|
||||||
// The callers can request access with a given weight.
|
|
||||||
type Weighted struct {
|
|
||||||
size int64
|
|
||||||
cur int64
|
|
||||||
mu sync.Mutex
|
|
||||||
waiters list.List
|
|
||||||
}
|
|
||||||
|
|
||||||
// Acquire acquires the semaphore with a weight of n, blocking until resources
|
|
||||||
// are available or ctx is done. On success, returns nil. On failure, returns
|
|
||||||
// ctx.Err() and leaves the semaphore unchanged.
|
|
||||||
//
|
|
||||||
// If ctx is already done, Acquire may still succeed without blocking.
|
|
||||||
func (s *Weighted) Acquire(ctx context.Context, n int64) error {
|
|
||||||
s.mu.Lock()
|
|
||||||
if s.size-s.cur >= n && s.waiters.Len() == 0 {
|
|
||||||
s.cur += n
|
|
||||||
s.mu.Unlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if n > s.size {
|
|
||||||
// Don't make other Acquire calls block on one that's doomed to fail.
|
|
||||||
s.mu.Unlock()
|
|
||||||
<-ctx.Done()
|
|
||||||
return ctx.Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
ready := make(chan struct{})
|
|
||||||
w := waiter{n: n, ready: ready}
|
|
||||||
elem := s.waiters.PushBack(w)
|
|
||||||
s.mu.Unlock()
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
err := ctx.Err()
|
|
||||||
s.mu.Lock()
|
|
||||||
select {
|
|
||||||
case <-ready:
|
|
||||||
// Acquired the semaphore after we were canceled. Rather than trying to
|
|
||||||
// fix up the queue, just pretend we didn't notice the cancelation.
|
|
||||||
err = nil
|
|
||||||
default:
|
|
||||||
s.waiters.Remove(elem)
|
|
||||||
}
|
|
||||||
s.mu.Unlock()
|
|
||||||
return err
|
|
||||||
|
|
||||||
case <-ready:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TryAcquire acquires the semaphore with a weight of n without blocking.
|
|
||||||
// On success, returns true. On failure, returns false and leaves the semaphore unchanged.
|
|
||||||
func (s *Weighted) TryAcquire(n int64) bool {
|
|
||||||
s.mu.Lock()
|
|
||||||
success := s.size-s.cur >= n && s.waiters.Len() == 0
|
|
||||||
if success {
|
|
||||||
s.cur += n
|
|
||||||
}
|
|
||||||
s.mu.Unlock()
|
|
||||||
return success
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release releases the semaphore with a weight of n.
|
|
||||||
func (s *Weighted) Release(n int64) {
|
|
||||||
s.mu.Lock()
|
|
||||||
s.cur -= n
|
|
||||||
if s.cur < 0 {
|
|
||||||
s.mu.Unlock()
|
|
||||||
panic("semaphore: released more than held")
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
next := s.waiters.Front()
|
|
||||||
if next == nil {
|
|
||||||
break // No more waiters blocked.
|
|
||||||
}
|
|
||||||
|
|
||||||
w := next.Value.(waiter)
|
|
||||||
if s.size-s.cur < w.n {
|
|
||||||
// Not enough tokens for the next waiter. We could keep going (to try to
|
|
||||||
// find a waiter with a smaller request), but under load that could cause
|
|
||||||
// starvation for large requests; instead, we leave all remaining waiters
|
|
||||||
// blocked.
|
|
||||||
//
|
|
||||||
// Consider a semaphore used as a read-write lock, with N tokens, N
|
|
||||||
// readers, and one writer. Each reader can Acquire(1) to obtain a read
|
|
||||||
// lock. The writer can Acquire(N) to obtain a write lock, excluding all
|
|
||||||
// of the readers. If we allow the readers to jump ahead in the queue,
|
|
||||||
// the writer will starve — there is always one token available for every
|
|
||||||
// reader.
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
s.cur += w.n
|
|
||||||
s.waiters.Remove(next)
|
|
||||||
close(w.ready)
|
|
||||||
}
|
|
||||||
s.mu.Unlock()
|
|
||||||
}
|
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@ -91,7 +91,6 @@ golang.org/x/net/context
|
|||||||
golang.org/x/oauth2
|
golang.org/x/oauth2
|
||||||
golang.org/x/oauth2/internal
|
golang.org/x/oauth2/internal
|
||||||
# golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
# golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
||||||
golang.org/x/sync/semaphore
|
|
||||||
golang.org/x/sync/errgroup
|
golang.org/x/sync/errgroup
|
||||||
# golang.org/x/sys v0.0.0-20190422165155-953cdadca894
|
# golang.org/x/sys v0.0.0-20190422165155-953cdadca894
|
||||||
golang.org/x/sys/unix
|
golang.org/x/sys/unix
|
||||||
|
Loading…
Reference in New Issue
Block a user