mirror of
https://github.com/kubernetes-sigs/prometheus-adapter.git
synced 2026-04-06 17:57:51 +00:00
Add vendor folder to git
This commit is contained in:
parent
66cf5eaafb
commit
183585f56f
6916 changed files with 2629581 additions and 1 deletions
2
vendor/github.com/coreos/etcd/pkg/README.md
generated
vendored
Normal file
2
vendor/github.com/coreos/etcd/pkg/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
pkg/ is a collection of utility packages used by etcd without being specific to etcd itself. A package belongs here
|
||||
only if it could possibly be moved out into its own repository in the future.
|
||||
16
vendor/github.com/coreos/etcd/pkg/adt/doc.go
generated
vendored
Normal file
16
vendor/github.com/coreos/etcd/pkg/adt/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package adt implements useful abstract data types.
|
||||
package adt
|
||||
37
vendor/github.com/coreos/etcd/pkg/adt/example_test.go
generated
vendored
Normal file
37
vendor/github.com/coreos/etcd/pkg/adt/example_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package adt_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/coreos/etcd/pkg/adt"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
ivt := &adt.IntervalTree{}
|
||||
|
||||
ivt.Insert(adt.NewInt64Interval(1, 3), 123)
|
||||
ivt.Insert(adt.NewInt64Interval(9, 13), 456)
|
||||
ivt.Insert(adt.NewInt64Interval(7, 20), 789)
|
||||
|
||||
rs := ivt.Stab(adt.NewInt64Point(10))
|
||||
for _, v := range rs {
|
||||
fmt.Printf("Overlapping range: %+v\n", v)
|
||||
}
|
||||
// output:
|
||||
// Overlapping range: &{Ivl:{Begin:7 End:20} Val:789}
|
||||
// Overlapping range: &{Ivl:{Begin:9 End:13} Val:456}
|
||||
}
|
||||
531
vendor/github.com/coreos/etcd/pkg/adt/interval_tree.go
generated
vendored
Normal file
531
vendor/github.com/coreos/etcd/pkg/adt/interval_tree.go
generated
vendored
Normal file
|
|
@ -0,0 +1,531 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package adt
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// Comparable is an interface for trichotomic comparisons.
|
||||
type Comparable interface {
|
||||
// Compare gives the result of a 3-way comparison
|
||||
// a.Compare(b) = 1 => a > b
|
||||
// a.Compare(b) = 0 => a == b
|
||||
// a.Compare(b) = -1 => a < b
|
||||
Compare(c Comparable) int
|
||||
}
|
||||
|
||||
type rbcolor int
|
||||
|
||||
const (
|
||||
black rbcolor = iota
|
||||
red
|
||||
)
|
||||
|
||||
// Interval implements a Comparable interval [begin, end)
|
||||
// TODO: support different sorts of intervals: (a,b), [a,b], (a, b]
|
||||
type Interval struct {
|
||||
Begin Comparable
|
||||
End Comparable
|
||||
}
|
||||
|
||||
// Compare on an interval gives == if the interval overlaps.
|
||||
func (ivl *Interval) Compare(c Comparable) int {
|
||||
ivl2 := c.(*Interval)
|
||||
ivbCmpBegin := ivl.Begin.Compare(ivl2.Begin)
|
||||
ivbCmpEnd := ivl.Begin.Compare(ivl2.End)
|
||||
iveCmpBegin := ivl.End.Compare(ivl2.Begin)
|
||||
|
||||
// ivl is left of ivl2
|
||||
if ivbCmpBegin < 0 && iveCmpBegin <= 0 {
|
||||
return -1
|
||||
}
|
||||
|
||||
// iv is right of iv2
|
||||
if ivbCmpEnd >= 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
type intervalNode struct {
|
||||
// iv is the interval-value pair entry.
|
||||
iv IntervalValue
|
||||
// max endpoint of all descendent nodes.
|
||||
max Comparable
|
||||
// left and right are sorted by low endpoint of key interval
|
||||
left, right *intervalNode
|
||||
// parent is the direct ancestor of the node
|
||||
parent *intervalNode
|
||||
c rbcolor
|
||||
}
|
||||
|
||||
func (x *intervalNode) color() rbcolor {
|
||||
if x == nil {
|
||||
return black
|
||||
}
|
||||
return x.c
|
||||
}
|
||||
|
||||
func (n *intervalNode) height() int {
|
||||
if n == nil {
|
||||
return 0
|
||||
}
|
||||
ld := n.left.height()
|
||||
rd := n.right.height()
|
||||
if ld < rd {
|
||||
return rd + 1
|
||||
}
|
||||
return ld + 1
|
||||
}
|
||||
|
||||
func (x *intervalNode) min() *intervalNode {
|
||||
for x.left != nil {
|
||||
x = x.left
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// successor is the next in-order node in the tree
|
||||
func (x *intervalNode) successor() *intervalNode {
|
||||
if x.right != nil {
|
||||
return x.right.min()
|
||||
}
|
||||
y := x.parent
|
||||
for y != nil && x == y.right {
|
||||
x = y
|
||||
y = y.parent
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
// updateMax updates the maximum values for a node and its ancestors
|
||||
func (x *intervalNode) updateMax() {
|
||||
for x != nil {
|
||||
oldmax := x.max
|
||||
max := x.iv.Ivl.End
|
||||
if x.left != nil && x.left.max.Compare(max) > 0 {
|
||||
max = x.left.max
|
||||
}
|
||||
if x.right != nil && x.right.max.Compare(max) > 0 {
|
||||
max = x.right.max
|
||||
}
|
||||
if oldmax.Compare(max) == 0 {
|
||||
break
|
||||
}
|
||||
x.max = max
|
||||
x = x.parent
|
||||
}
|
||||
}
|
||||
|
||||
type nodeVisitor func(n *intervalNode) bool
|
||||
|
||||
// visit will call a node visitor on each node that overlaps the given interval
|
||||
func (x *intervalNode) visit(iv *Interval, nv nodeVisitor) {
|
||||
if x == nil {
|
||||
return
|
||||
}
|
||||
v := iv.Compare(&x.iv.Ivl)
|
||||
switch {
|
||||
case v < 0:
|
||||
x.left.visit(iv, nv)
|
||||
case v > 0:
|
||||
maxiv := Interval{x.iv.Ivl.Begin, x.max}
|
||||
if maxiv.Compare(iv) == 0 {
|
||||
x.left.visit(iv, nv)
|
||||
x.right.visit(iv, nv)
|
||||
}
|
||||
default:
|
||||
nv(x)
|
||||
x.left.visit(iv, nv)
|
||||
x.right.visit(iv, nv)
|
||||
}
|
||||
}
|
||||
|
||||
type IntervalValue struct {
|
||||
Ivl Interval
|
||||
Val interface{}
|
||||
}
|
||||
|
||||
// IntervalTree represents a (mostly) textbook implementation of the
|
||||
// "Introduction to Algorithms" (Cormen et al, 2nd ed.) chapter 13 red-black tree
|
||||
// and chapter 14.3 interval tree with search supporting "stabbing queries".
|
||||
type IntervalTree struct {
|
||||
root *intervalNode
|
||||
count int
|
||||
}
|
||||
|
||||
// Delete removes the node with the given interval from the tree, returning
|
||||
// true if a node is in fact removed.
|
||||
func (ivt *IntervalTree) Delete(ivl Interval) bool {
|
||||
z := ivt.find(ivl)
|
||||
if z == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
y := z
|
||||
if z.left != nil && z.right != nil {
|
||||
y = z.successor()
|
||||
}
|
||||
|
||||
x := y.left
|
||||
if x == nil {
|
||||
x = y.right
|
||||
}
|
||||
if x != nil {
|
||||
x.parent = y.parent
|
||||
}
|
||||
|
||||
if y.parent == nil {
|
||||
ivt.root = x
|
||||
} else {
|
||||
if y == y.parent.left {
|
||||
y.parent.left = x
|
||||
} else {
|
||||
y.parent.right = x
|
||||
}
|
||||
y.parent.updateMax()
|
||||
}
|
||||
if y != z {
|
||||
z.iv = y.iv
|
||||
z.updateMax()
|
||||
}
|
||||
|
||||
if y.color() == black && x != nil {
|
||||
ivt.deleteFixup(x)
|
||||
}
|
||||
|
||||
ivt.count--
|
||||
return true
|
||||
}
|
||||
|
||||
func (ivt *IntervalTree) deleteFixup(x *intervalNode) {
|
||||
for x != ivt.root && x.color() == black && x.parent != nil {
|
||||
if x == x.parent.left {
|
||||
w := x.parent.right
|
||||
if w.color() == red {
|
||||
w.c = black
|
||||
x.parent.c = red
|
||||
ivt.rotateLeft(x.parent)
|
||||
w = x.parent.right
|
||||
}
|
||||
if w == nil {
|
||||
break
|
||||
}
|
||||
if w.left.color() == black && w.right.color() == black {
|
||||
w.c = red
|
||||
x = x.parent
|
||||
} else {
|
||||
if w.right.color() == black {
|
||||
w.left.c = black
|
||||
w.c = red
|
||||
ivt.rotateRight(w)
|
||||
w = x.parent.right
|
||||
}
|
||||
w.c = x.parent.color()
|
||||
x.parent.c = black
|
||||
w.right.c = black
|
||||
ivt.rotateLeft(x.parent)
|
||||
x = ivt.root
|
||||
}
|
||||
} else {
|
||||
// same as above but with left and right exchanged
|
||||
w := x.parent.left
|
||||
if w.color() == red {
|
||||
w.c = black
|
||||
x.parent.c = red
|
||||
ivt.rotateRight(x.parent)
|
||||
w = x.parent.left
|
||||
}
|
||||
if w == nil {
|
||||
break
|
||||
}
|
||||
if w.left.color() == black && w.right.color() == black {
|
||||
w.c = red
|
||||
x = x.parent
|
||||
} else {
|
||||
if w.left.color() == black {
|
||||
w.right.c = black
|
||||
w.c = red
|
||||
ivt.rotateLeft(w)
|
||||
w = x.parent.left
|
||||
}
|
||||
w.c = x.parent.color()
|
||||
x.parent.c = black
|
||||
w.left.c = black
|
||||
ivt.rotateRight(x.parent)
|
||||
x = ivt.root
|
||||
}
|
||||
}
|
||||
}
|
||||
if x != nil {
|
||||
x.c = black
|
||||
}
|
||||
}
|
||||
|
||||
// Insert adds a node with the given interval into the tree.
|
||||
func (ivt *IntervalTree) Insert(ivl Interval, val interface{}) {
|
||||
var y *intervalNode
|
||||
z := &intervalNode{iv: IntervalValue{ivl, val}, max: ivl.End, c: red}
|
||||
x := ivt.root
|
||||
for x != nil {
|
||||
y = x
|
||||
if z.iv.Ivl.Begin.Compare(x.iv.Ivl.Begin) < 0 {
|
||||
x = x.left
|
||||
} else {
|
||||
x = x.right
|
||||
}
|
||||
}
|
||||
|
||||
z.parent = y
|
||||
if y == nil {
|
||||
ivt.root = z
|
||||
} else {
|
||||
if z.iv.Ivl.Begin.Compare(y.iv.Ivl.Begin) < 0 {
|
||||
y.left = z
|
||||
} else {
|
||||
y.right = z
|
||||
}
|
||||
y.updateMax()
|
||||
}
|
||||
z.c = red
|
||||
ivt.insertFixup(z)
|
||||
ivt.count++
|
||||
}
|
||||
|
||||
func (ivt *IntervalTree) insertFixup(z *intervalNode) {
|
||||
for z.parent != nil && z.parent.parent != nil && z.parent.color() == red {
|
||||
if z.parent == z.parent.parent.left {
|
||||
y := z.parent.parent.right
|
||||
if y.color() == red {
|
||||
y.c = black
|
||||
z.parent.c = black
|
||||
z.parent.parent.c = red
|
||||
z = z.parent.parent
|
||||
} else {
|
||||
if z == z.parent.right {
|
||||
z = z.parent
|
||||
ivt.rotateLeft(z)
|
||||
}
|
||||
z.parent.c = black
|
||||
z.parent.parent.c = red
|
||||
ivt.rotateRight(z.parent.parent)
|
||||
}
|
||||
} else {
|
||||
// same as then with left/right exchanged
|
||||
y := z.parent.parent.left
|
||||
if y.color() == red {
|
||||
y.c = black
|
||||
z.parent.c = black
|
||||
z.parent.parent.c = red
|
||||
z = z.parent.parent
|
||||
} else {
|
||||
if z == z.parent.left {
|
||||
z = z.parent
|
||||
ivt.rotateRight(z)
|
||||
}
|
||||
z.parent.c = black
|
||||
z.parent.parent.c = red
|
||||
ivt.rotateLeft(z.parent.parent)
|
||||
}
|
||||
}
|
||||
}
|
||||
ivt.root.c = black
|
||||
}
|
||||
|
||||
// rotateLeft moves x so it is left of its right child
|
||||
func (ivt *IntervalTree) rotateLeft(x *intervalNode) {
|
||||
y := x.right
|
||||
x.right = y.left
|
||||
if y.left != nil {
|
||||
y.left.parent = x
|
||||
}
|
||||
x.updateMax()
|
||||
ivt.replaceParent(x, y)
|
||||
y.left = x
|
||||
y.updateMax()
|
||||
}
|
||||
|
||||
// rotateLeft moves x so it is right of its left child
|
||||
func (ivt *IntervalTree) rotateRight(x *intervalNode) {
|
||||
if x == nil {
|
||||
return
|
||||
}
|
||||
y := x.left
|
||||
x.left = y.right
|
||||
if y.right != nil {
|
||||
y.right.parent = x
|
||||
}
|
||||
x.updateMax()
|
||||
ivt.replaceParent(x, y)
|
||||
y.right = x
|
||||
y.updateMax()
|
||||
}
|
||||
|
||||
// replaceParent replaces x's parent with y
|
||||
func (ivt *IntervalTree) replaceParent(x *intervalNode, y *intervalNode) {
|
||||
y.parent = x.parent
|
||||
if x.parent == nil {
|
||||
ivt.root = y
|
||||
} else {
|
||||
if x == x.parent.left {
|
||||
x.parent.left = y
|
||||
} else {
|
||||
x.parent.right = y
|
||||
}
|
||||
x.parent.updateMax()
|
||||
}
|
||||
x.parent = y
|
||||
}
|
||||
|
||||
// Len gives the number of elements in the tree
|
||||
func (ivt *IntervalTree) Len() int { return ivt.count }
|
||||
|
||||
// Height is the number of levels in the tree; one node has height 1.
|
||||
func (ivt *IntervalTree) Height() int { return ivt.root.height() }
|
||||
|
||||
// MaxHeight is the expected maximum tree height given the number of nodes
|
||||
func (ivt *IntervalTree) MaxHeight() int {
|
||||
return int((2 * math.Log2(float64(ivt.Len()+1))) + 0.5)
|
||||
}
|
||||
|
||||
// IntervalVisitor is used on tree searchs; return false to stop searching.
|
||||
type IntervalVisitor func(n *IntervalValue) bool
|
||||
|
||||
// Visit calls a visitor function on every tree node intersecting the given interval.
|
||||
func (ivt *IntervalTree) Visit(ivl Interval, ivv IntervalVisitor) {
|
||||
ivt.root.visit(&ivl, func(n *intervalNode) bool { return ivv(&n.iv) })
|
||||
}
|
||||
|
||||
// find the exact node for a given interval
|
||||
func (ivt *IntervalTree) find(ivl Interval) (ret *intervalNode) {
|
||||
f := func(n *intervalNode) bool {
|
||||
if n.iv.Ivl != ivl {
|
||||
return true
|
||||
}
|
||||
ret = n
|
||||
return false
|
||||
}
|
||||
ivt.root.visit(&ivl, f)
|
||||
return ret
|
||||
}
|
||||
|
||||
// Find gets the IntervalValue for the node matching the given interval
|
||||
func (ivt *IntervalTree) Find(ivl Interval) (ret *IntervalValue) {
|
||||
n := ivt.find(ivl)
|
||||
if n == nil {
|
||||
return nil
|
||||
}
|
||||
return &n.iv
|
||||
}
|
||||
|
||||
// Contains returns true if there is some tree node intersecting the given interval.
|
||||
func (ivt *IntervalTree) Contains(iv Interval) bool {
|
||||
x := ivt.root
|
||||
for x != nil && iv.Compare(&x.iv.Ivl) != 0 {
|
||||
if x.left != nil && x.left.max.Compare(iv.Begin) > 0 {
|
||||
x = x.left
|
||||
} else {
|
||||
x = x.right
|
||||
}
|
||||
}
|
||||
return x != nil
|
||||
}
|
||||
|
||||
// Stab returns a slice with all elements in the tree intersecting the interval.
|
||||
func (ivt *IntervalTree) Stab(iv Interval) (ivs []*IntervalValue) {
|
||||
if ivt.count == 0 {
|
||||
return nil
|
||||
}
|
||||
f := func(n *IntervalValue) bool { ivs = append(ivs, n); return true }
|
||||
ivt.Visit(iv, f)
|
||||
return ivs
|
||||
}
|
||||
|
||||
type StringComparable string
|
||||
|
||||
func (s StringComparable) Compare(c Comparable) int {
|
||||
sc := c.(StringComparable)
|
||||
if s < sc {
|
||||
return -1
|
||||
}
|
||||
if s > sc {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func NewStringInterval(begin, end string) Interval {
|
||||
return Interval{StringComparable(begin), StringComparable(end)}
|
||||
}
|
||||
|
||||
func NewStringPoint(s string) Interval {
|
||||
return Interval{StringComparable(s), StringComparable(s + "\x00")}
|
||||
}
|
||||
|
||||
// StringAffineComparable treats "" as > all other strings
|
||||
type StringAffineComparable string
|
||||
|
||||
func (s StringAffineComparable) Compare(c Comparable) int {
|
||||
sc := c.(StringAffineComparable)
|
||||
|
||||
if len(s) == 0 {
|
||||
if len(sc) == 0 {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
if len(sc) == 0 {
|
||||
return -1
|
||||
}
|
||||
|
||||
if s < sc {
|
||||
return -1
|
||||
}
|
||||
if s > sc {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func NewStringAffineInterval(begin, end string) Interval {
|
||||
return Interval{StringAffineComparable(begin), StringAffineComparable(end)}
|
||||
}
|
||||
func NewStringAffinePoint(s string) Interval {
|
||||
return NewStringAffineInterval(s, s+"\x00")
|
||||
}
|
||||
|
||||
func NewInt64Interval(a int64, b int64) Interval {
|
||||
return Interval{Int64Comparable(a), Int64Comparable(b)}
|
||||
}
|
||||
|
||||
func NewInt64Point(a int64) Interval {
|
||||
return Interval{Int64Comparable(a), Int64Comparable(a + 1)}
|
||||
}
|
||||
|
||||
type Int64Comparable int64
|
||||
|
||||
func (v Int64Comparable) Compare(c Comparable) int {
|
||||
vc := c.(Int64Comparable)
|
||||
cmp := v - vc
|
||||
if cmp < 0 {
|
||||
return -1
|
||||
}
|
||||
if cmp > 0 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
138
vendor/github.com/coreos/etcd/pkg/adt/interval_tree_test.go
generated
vendored
Normal file
138
vendor/github.com/coreos/etcd/pkg/adt/interval_tree_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package adt
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestIntervalTreeContains(t *testing.T) {
|
||||
ivt := &IntervalTree{}
|
||||
ivt.Insert(NewStringInterval("1", "3"), 123)
|
||||
|
||||
if ivt.Contains(NewStringPoint("0")) {
|
||||
t.Errorf("contains 0")
|
||||
}
|
||||
if !ivt.Contains(NewStringPoint("1")) {
|
||||
t.Errorf("missing 1")
|
||||
}
|
||||
if !ivt.Contains(NewStringPoint("11")) {
|
||||
t.Errorf("missing 11")
|
||||
}
|
||||
if !ivt.Contains(NewStringPoint("2")) {
|
||||
t.Errorf("missing 2")
|
||||
}
|
||||
if ivt.Contains(NewStringPoint("3")) {
|
||||
t.Errorf("contains 3")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntervalTreeStringAffine(t *testing.T) {
|
||||
ivt := &IntervalTree{}
|
||||
ivt.Insert(NewStringAffineInterval("8", ""), 123)
|
||||
if !ivt.Contains(NewStringAffinePoint("9")) {
|
||||
t.Errorf("missing 9")
|
||||
}
|
||||
if ivt.Contains(NewStringAffinePoint("7")) {
|
||||
t.Errorf("contains 7")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntervalTreeStab(t *testing.T) {
|
||||
ivt := &IntervalTree{}
|
||||
ivt.Insert(NewStringInterval("0", "1"), 123)
|
||||
ivt.Insert(NewStringInterval("0", "2"), 456)
|
||||
ivt.Insert(NewStringInterval("5", "6"), 789)
|
||||
ivt.Insert(NewStringInterval("6", "8"), 999)
|
||||
ivt.Insert(NewStringInterval("0", "3"), 0)
|
||||
|
||||
if ivt.root.max.Compare(StringComparable("8")) != 0 {
|
||||
t.Fatalf("wrong root max got %v, expected 8", ivt.root.max)
|
||||
}
|
||||
if x := len(ivt.Stab(NewStringPoint("0"))); x != 3 {
|
||||
t.Errorf("got %d, expected 3", x)
|
||||
}
|
||||
if x := len(ivt.Stab(NewStringPoint("1"))); x != 2 {
|
||||
t.Errorf("got %d, expected 2", x)
|
||||
}
|
||||
if x := len(ivt.Stab(NewStringPoint("2"))); x != 1 {
|
||||
t.Errorf("got %d, expected 1", x)
|
||||
}
|
||||
if x := len(ivt.Stab(NewStringPoint("3"))); x != 0 {
|
||||
t.Errorf("got %d, expected 0", x)
|
||||
}
|
||||
if x := len(ivt.Stab(NewStringPoint("5"))); x != 1 {
|
||||
t.Errorf("got %d, expected 1", x)
|
||||
}
|
||||
if x := len(ivt.Stab(NewStringPoint("55"))); x != 1 {
|
||||
t.Errorf("got %d, expected 1", x)
|
||||
}
|
||||
if x := len(ivt.Stab(NewStringPoint("6"))); x != 1 {
|
||||
t.Errorf("got %d, expected 1", x)
|
||||
}
|
||||
}
|
||||
|
||||
type xy struct {
|
||||
x int64
|
||||
y int64
|
||||
}
|
||||
|
||||
func TestIntervalTreeRandom(t *testing.T) {
|
||||
// generate unique intervals
|
||||
ivs := make(map[xy]struct{})
|
||||
ivt := &IntervalTree{}
|
||||
maxv := 128
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
for i := rand.Intn(maxv) + 1; i != 0; i-- {
|
||||
x, y := int64(rand.Intn(maxv)), int64(rand.Intn(maxv))
|
||||
if x > y {
|
||||
t := x
|
||||
x = y
|
||||
y = t
|
||||
} else if x == y {
|
||||
y++
|
||||
}
|
||||
iv := xy{x, y}
|
||||
if _, ok := ivs[iv]; ok {
|
||||
// don't double insert
|
||||
continue
|
||||
}
|
||||
ivt.Insert(NewInt64Interval(x, y), 123)
|
||||
ivs[iv] = struct{}{}
|
||||
}
|
||||
|
||||
for ab := range ivs {
|
||||
for xy := range ivs {
|
||||
v := xy.x + int64(rand.Intn(int(xy.y-xy.x)))
|
||||
if slen := len(ivt.Stab(NewInt64Point(v))); slen == 0 {
|
||||
t.Fatalf("expected %v stab non-zero for [%+v)", v, xy)
|
||||
}
|
||||
if !ivt.Contains(NewInt64Point(v)) {
|
||||
t.Fatalf("did not get %d as expected for [%+v)", v, xy)
|
||||
}
|
||||
}
|
||||
if !ivt.Delete(NewInt64Interval(ab.x, ab.y)) {
|
||||
t.Errorf("did not delete %v as expected", ab)
|
||||
}
|
||||
delete(ivs, ab)
|
||||
}
|
||||
|
||||
if ivt.Len() != 0 {
|
||||
t.Errorf("got ivt.Len() = %v, expected 0", ivt.Len())
|
||||
}
|
||||
}
|
||||
69
vendor/github.com/coreos/etcd/pkg/contention/contention.go
generated
vendored
Normal file
69
vendor/github.com/coreos/etcd/pkg/contention/contention.go
generated
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package contention
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TimeoutDetector detects routine starvations by
|
||||
// observing the actual time duration to finish an action
|
||||
// or between two events that should happen in a fixed
|
||||
// interval. If the observed duration is longer than
|
||||
// the expectation, the detector will report the result.
|
||||
type TimeoutDetector struct {
|
||||
mu sync.Mutex // protects all
|
||||
maxDuration time.Duration
|
||||
// map from event to time
|
||||
// time is the last seen time of the event.
|
||||
records map[uint64]time.Time
|
||||
}
|
||||
|
||||
// NewTimeoutDetector creates the TimeoutDetector.
|
||||
func NewTimeoutDetector(maxDuration time.Duration) *TimeoutDetector {
|
||||
return &TimeoutDetector{
|
||||
maxDuration: maxDuration,
|
||||
records: make(map[uint64]time.Time),
|
||||
}
|
||||
}
|
||||
|
||||
// Reset resets the NewTimeoutDetector.
|
||||
func (td *TimeoutDetector) Reset() {
|
||||
td.mu.Lock()
|
||||
defer td.mu.Unlock()
|
||||
|
||||
td.records = make(map[uint64]time.Time)
|
||||
}
|
||||
|
||||
// Observe observes an event for given id. It returns false and exceeded duration
|
||||
// if the interval is longer than the expectation.
|
||||
func (td *TimeoutDetector) Observe(which uint64) (bool, time.Duration) {
|
||||
td.mu.Lock()
|
||||
defer td.mu.Unlock()
|
||||
|
||||
ok := true
|
||||
now := time.Now()
|
||||
exceed := time.Duration(0)
|
||||
|
||||
if pt, found := td.records[which]; found {
|
||||
exceed = now.Sub(pt) - td.maxDuration
|
||||
if exceed > 0 {
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
td.records[which] = now
|
||||
return ok, exceed
|
||||
}
|
||||
16
vendor/github.com/coreos/etcd/pkg/contention/doc.go
generated
vendored
Normal file
16
vendor/github.com/coreos/etcd/pkg/contention/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package contention provides facilities for detecting system contention.
|
||||
package contention
|
||||
90
vendor/github.com/coreos/etcd/pkg/cors/cors.go
generated
vendored
Normal file
90
vendor/github.com/coreos/etcd/pkg/cors/cors.go
generated
vendored
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package cors handles cross-origin HTTP requests (CORS).
|
||||
package cors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CORSInfo map[string]bool
|
||||
|
||||
// Set implements the flag.Value interface to allow users to define a list of CORS origins
|
||||
func (ci *CORSInfo) Set(s string) error {
|
||||
m := make(map[string]bool)
|
||||
for _, v := range strings.Split(s, ",") {
|
||||
v = strings.TrimSpace(v)
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
if v != "*" {
|
||||
if _, err := url.Parse(v); err != nil {
|
||||
return fmt.Errorf("Invalid CORS origin: %s", err)
|
||||
}
|
||||
}
|
||||
m[v] = true
|
||||
|
||||
}
|
||||
*ci = CORSInfo(m)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ci *CORSInfo) String() string {
|
||||
o := make([]string, 0)
|
||||
for k := range *ci {
|
||||
o = append(o, k)
|
||||
}
|
||||
sort.StringSlice(o).Sort()
|
||||
return strings.Join(o, ",")
|
||||
}
|
||||
|
||||
// OriginAllowed determines whether the server will allow a given CORS origin.
|
||||
func (c CORSInfo) OriginAllowed(origin string) bool {
|
||||
return c["*"] || c[origin]
|
||||
}
|
||||
|
||||
type CORSHandler struct {
|
||||
Handler http.Handler
|
||||
Info *CORSInfo
|
||||
}
|
||||
|
||||
// addHeader adds the correct cors headers given an origin
|
||||
func (h *CORSHandler) addHeader(w http.ResponseWriter, origin string) {
|
||||
w.Header().Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
|
||||
w.Header().Add("Access-Control-Allow-Origin", origin)
|
||||
w.Header().Add("Access-Control-Allow-Headers", "accept, content-type, authorization")
|
||||
}
|
||||
|
||||
// ServeHTTP adds the correct CORS headers based on the origin and returns immediately
|
||||
// with a 200 OK if the method is OPTIONS.
|
||||
func (h *CORSHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
// Write CORS header.
|
||||
if h.Info.OriginAllowed("*") {
|
||||
h.addHeader(w, "*")
|
||||
} else if origin := req.Header.Get("Origin"); h.Info.OriginAllowed(origin) {
|
||||
h.addHeader(w, origin)
|
||||
}
|
||||
|
||||
if req.Method == "OPTIONS" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
h.Handler.ServeHTTP(w, req)
|
||||
}
|
||||
125
vendor/github.com/coreos/etcd/pkg/cors/cors_test.go
generated
vendored
Normal file
125
vendor/github.com/coreos/etcd/pkg/cors/cors_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cors
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCORSInfo(t *testing.T) {
|
||||
tests := []struct {
|
||||
s string
|
||||
winfo CORSInfo
|
||||
ws string
|
||||
}{
|
||||
{"", CORSInfo{}, ""},
|
||||
{"http://127.0.0.1", CORSInfo{"http://127.0.0.1": true}, "http://127.0.0.1"},
|
||||
{"*", CORSInfo{"*": true}, "*"},
|
||||
// with space around
|
||||
{" http://127.0.0.1 ", CORSInfo{"http://127.0.0.1": true}, "http://127.0.0.1"},
|
||||
// multiple addrs
|
||||
{
|
||||
"http://127.0.0.1,http://127.0.0.2",
|
||||
CORSInfo{"http://127.0.0.1": true, "http://127.0.0.2": true},
|
||||
"http://127.0.0.1,http://127.0.0.2",
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
info := CORSInfo{}
|
||||
if err := info.Set(tt.s); err != nil {
|
||||
t.Errorf("#%d: set error = %v, want nil", i, err)
|
||||
}
|
||||
if !reflect.DeepEqual(info, tt.winfo) {
|
||||
t.Errorf("#%d: info = %v, want %v", i, info, tt.winfo)
|
||||
}
|
||||
if g := info.String(); g != tt.ws {
|
||||
t.Errorf("#%d: info string = %s, want %s", i, g, tt.ws)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCORSInfoOriginAllowed(t *testing.T) {
|
||||
tests := []struct {
|
||||
set string
|
||||
origin string
|
||||
wallowed bool
|
||||
}{
|
||||
{"http://127.0.0.1,http://127.0.0.2", "http://127.0.0.1", true},
|
||||
{"http://127.0.0.1,http://127.0.0.2", "http://127.0.0.2", true},
|
||||
{"http://127.0.0.1,http://127.0.0.2", "*", false},
|
||||
{"http://127.0.0.1,http://127.0.0.2", "http://127.0.0.3", false},
|
||||
{"*", "*", true},
|
||||
{"*", "http://127.0.0.1", true},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
info := CORSInfo{}
|
||||
if err := info.Set(tt.set); err != nil {
|
||||
t.Errorf("#%d: set error = %v, want nil", i, err)
|
||||
}
|
||||
if g := info.OriginAllowed(tt.origin); g != tt.wallowed {
|
||||
t.Errorf("#%d: allowed = %v, want %v", i, g, tt.wallowed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCORSHandler(t *testing.T) {
|
||||
info := &CORSInfo{}
|
||||
if err := info.Set("http://127.0.0.1,http://127.0.0.2"); err != nil {
|
||||
t.Fatalf("unexpected set error: %v", err)
|
||||
}
|
||||
h := &CORSHandler{
|
||||
Handler: http.NotFoundHandler(),
|
||||
Info: info,
|
||||
}
|
||||
|
||||
header := func(origin string) http.Header {
|
||||
return http.Header{
|
||||
"Access-Control-Allow-Methods": []string{"POST, GET, OPTIONS, PUT, DELETE"},
|
||||
"Access-Control-Allow-Origin": []string{origin},
|
||||
"Access-Control-Allow-Headers": []string{"accept, content-type, authorization"},
|
||||
}
|
||||
}
|
||||
tests := []struct {
|
||||
method string
|
||||
origin string
|
||||
wcode int
|
||||
wheader http.Header
|
||||
}{
|
||||
{"GET", "http://127.0.0.1", http.StatusNotFound, header("http://127.0.0.1")},
|
||||
{"GET", "http://127.0.0.2", http.StatusNotFound, header("http://127.0.0.2")},
|
||||
{"GET", "http://127.0.0.3", http.StatusNotFound, http.Header{}},
|
||||
{"OPTIONS", "http://127.0.0.1", http.StatusOK, header("http://127.0.0.1")},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
rr := httptest.NewRecorder()
|
||||
req := &http.Request{
|
||||
Method: tt.method,
|
||||
Header: http.Header{"Origin": []string{tt.origin}},
|
||||
}
|
||||
h.ServeHTTP(rr, req)
|
||||
if rr.Code != tt.wcode {
|
||||
t.Errorf("#%d: code = %v, want %v", i, rr.Code, tt.wcode)
|
||||
}
|
||||
// it is set by http package, and there is no need to test it
|
||||
rr.HeaderMap.Del("Content-Type")
|
||||
rr.HeaderMap.Del("X-Content-Type-Options")
|
||||
if !reflect.DeepEqual(rr.HeaderMap, tt.wheader) {
|
||||
t.Errorf("#%d: header = %+v, want %+v", i, rr.HeaderMap, tt.wheader)
|
||||
}
|
||||
}
|
||||
}
|
||||
16
vendor/github.com/coreos/etcd/pkg/cpuutil/doc.go
generated
vendored
Normal file
16
vendor/github.com/coreos/etcd/pkg/cpuutil/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2017 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package cpuutil provides facilities for detecting cpu-specific features.
|
||||
package cpuutil
|
||||
36
vendor/github.com/coreos/etcd/pkg/cpuutil/endian.go
generated
vendored
Normal file
36
vendor/github.com/coreos/etcd/pkg/cpuutil/endian.go
generated
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2017 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cpuutil
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const intWidth int = int(unsafe.Sizeof(0))
|
||||
|
||||
var byteOrder binary.ByteOrder
|
||||
|
||||
// ByteOrder returns the byte order for the CPU's native endianness.
|
||||
func ByteOrder() binary.ByteOrder { return byteOrder }
|
||||
|
||||
func init() {
|
||||
var i int = 0x1
|
||||
if v := (*[intWidth]byte)(unsafe.Pointer(&i)); v[0] == 0 {
|
||||
byteOrder = binary.BigEndian
|
||||
} else {
|
||||
byteOrder = binary.LittleEndian
|
||||
}
|
||||
}
|
||||
43
vendor/github.com/coreos/etcd/pkg/crc/crc.go
generated
vendored
Normal file
43
vendor/github.com/coreos/etcd/pkg/crc/crc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2009 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 crc provides utility function for cyclic redundancy check
|
||||
// algorithms.
|
||||
package crc
|
||||
|
||||
import (
|
||||
"hash"
|
||||
"hash/crc32"
|
||||
)
|
||||
|
||||
// The size of a CRC-32 checksum in bytes.
|
||||
const Size = 4
|
||||
|
||||
type digest struct {
|
||||
crc uint32
|
||||
tab *crc32.Table
|
||||
}
|
||||
|
||||
// New creates a new hash.Hash32 computing the CRC-32 checksum
|
||||
// using the polynomial represented by the Table.
|
||||
// Modified by xiangli to take a prevcrc.
|
||||
func New(prev uint32, tab *crc32.Table) hash.Hash32 { return &digest{prev, tab} }
|
||||
|
||||
func (d *digest) Size() int { return Size }
|
||||
|
||||
func (d *digest) BlockSize() int { return 1 }
|
||||
|
||||
func (d *digest) Reset() { d.crc = 0 }
|
||||
|
||||
func (d *digest) Write(p []byte) (n int, err error) {
|
||||
d.crc = crc32.Update(d.crc, d.tab, p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (d *digest) Sum32() uint32 { return d.crc }
|
||||
|
||||
func (d *digest) Sum(in []byte) []byte {
|
||||
s := d.Sum32()
|
||||
return append(in, byte(s>>24), byte(s>>16), byte(s>>8), byte(s))
|
||||
}
|
||||
59
vendor/github.com/coreos/etcd/pkg/crc/crc_test.go
generated
vendored
Normal file
59
vendor/github.com/coreos/etcd/pkg/crc/crc_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2009 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 crc
|
||||
|
||||
import (
|
||||
"hash/crc32"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestHash32 tests that Hash32 provided by this package can take an initial
|
||||
// crc and behaves exactly the same as the standard one in the following calls.
|
||||
func TestHash32(t *testing.T) {
|
||||
stdhash := crc32.New(crc32.IEEETable)
|
||||
if _, err := stdhash.Write([]byte("test data")); err != nil {
|
||||
t.Fatalf("unexpected write error: %v", err)
|
||||
}
|
||||
// create a new hash with stdhash.Sum32() as initial crc
|
||||
hash := New(stdhash.Sum32(), crc32.IEEETable)
|
||||
|
||||
wsize := stdhash.Size()
|
||||
if g := hash.Size(); g != wsize {
|
||||
t.Errorf("size = %d, want %d", g, wsize)
|
||||
}
|
||||
wbsize := stdhash.BlockSize()
|
||||
if g := hash.BlockSize(); g != wbsize {
|
||||
t.Errorf("block size = %d, want %d", g, wbsize)
|
||||
}
|
||||
wsum32 := stdhash.Sum32()
|
||||
if g := hash.Sum32(); g != wsum32 {
|
||||
t.Errorf("Sum32 = %d, want %d", g, wsum32)
|
||||
}
|
||||
wsum := stdhash.Sum(make([]byte, 32))
|
||||
if g := hash.Sum(make([]byte, 32)); !reflect.DeepEqual(g, wsum) {
|
||||
t.Errorf("sum = %v, want %v", g, wsum)
|
||||
}
|
||||
|
||||
// write something
|
||||
if _, err := stdhash.Write([]byte("test data")); err != nil {
|
||||
t.Fatalf("unexpected write error: %v", err)
|
||||
}
|
||||
if _, err := hash.Write([]byte("test data")); err != nil {
|
||||
t.Fatalf("unexpected write error: %v", err)
|
||||
}
|
||||
wsum32 = stdhash.Sum32()
|
||||
if g := hash.Sum32(); g != wsum32 {
|
||||
t.Errorf("Sum32 after write = %d, want %d", g, wsum32)
|
||||
}
|
||||
|
||||
// reset
|
||||
stdhash.Reset()
|
||||
hash.Reset()
|
||||
wsum32 = stdhash.Sum32()
|
||||
if g := hash.Sum32(); g != wsum32 {
|
||||
t.Errorf("Sum32 after reset = %d, want %d", g, wsum32)
|
||||
}
|
||||
}
|
||||
160
vendor/github.com/coreos/etcd/pkg/expect/expect.go
generated
vendored
Normal file
160
vendor/github.com/coreos/etcd/pkg/expect/expect.go
generated
vendored
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package expect implements a small expect-style interface
|
||||
package expect
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/kr/pty"
|
||||
)
|
||||
|
||||
type ExpectProcess struct {
|
||||
cmd *exec.Cmd
|
||||
fpty *os.File
|
||||
wg sync.WaitGroup
|
||||
|
||||
ptyMu sync.Mutex // protects accessing fpty
|
||||
cond *sync.Cond // for broadcasting updates are available
|
||||
mu sync.Mutex // protects lines and err
|
||||
lines []string
|
||||
count int // increment whenever new line gets added
|
||||
err error
|
||||
}
|
||||
|
||||
var printDebugLines = os.Getenv("EXPECT_DEBUG") != ""
|
||||
|
||||
// NewExpect creates a new process for expect testing.
|
||||
func NewExpect(name string, arg ...string) (ep *ExpectProcess, err error) {
|
||||
ep = &ExpectProcess{cmd: exec.Command(name, arg...)}
|
||||
ep.cond = sync.NewCond(&ep.mu)
|
||||
ep.cmd.Stderr = ep.cmd.Stdout
|
||||
ep.cmd.Stdin = nil
|
||||
|
||||
if ep.fpty, err = pty.Start(ep.cmd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ep.wg.Add(1)
|
||||
go ep.read()
|
||||
return ep, nil
|
||||
}
|
||||
|
||||
func (ep *ExpectProcess) read() {
|
||||
defer ep.wg.Done()
|
||||
r := bufio.NewReader(ep.fpty)
|
||||
for ep.err == nil {
|
||||
ep.ptyMu.Lock()
|
||||
l, rerr := r.ReadString('\n')
|
||||
ep.ptyMu.Unlock()
|
||||
ep.mu.Lock()
|
||||
ep.err = rerr
|
||||
if l != "" {
|
||||
if printDebugLines {
|
||||
fmt.Printf("%s-%d: %s", ep.cmd.Path, ep.cmd.Process.Pid, l)
|
||||
}
|
||||
ep.lines = append(ep.lines, l)
|
||||
ep.count++
|
||||
if len(ep.lines) == 1 {
|
||||
ep.cond.Signal()
|
||||
}
|
||||
}
|
||||
ep.mu.Unlock()
|
||||
}
|
||||
ep.cond.Signal()
|
||||
}
|
||||
|
||||
// ExpectFunc returns the first line satisfying the function f.
|
||||
func (ep *ExpectProcess) ExpectFunc(f func(string) bool) (string, error) {
|
||||
ep.mu.Lock()
|
||||
for {
|
||||
for len(ep.lines) == 0 && ep.err == nil {
|
||||
ep.cond.Wait()
|
||||
}
|
||||
if len(ep.lines) == 0 {
|
||||
break
|
||||
}
|
||||
l := ep.lines[0]
|
||||
ep.lines = ep.lines[1:]
|
||||
if f(l) {
|
||||
ep.mu.Unlock()
|
||||
return l, nil
|
||||
}
|
||||
}
|
||||
ep.mu.Unlock()
|
||||
return "", ep.err
|
||||
}
|
||||
|
||||
// Expect returns the first line containing the given string.
|
||||
func (ep *ExpectProcess) Expect(s string) (string, error) {
|
||||
return ep.ExpectFunc(func(txt string) bool { return strings.Contains(txt, s) })
|
||||
}
|
||||
|
||||
// LineCount returns the number of recorded lines since
|
||||
// the beginning of the process.
|
||||
func (ep *ExpectProcess) LineCount() int {
|
||||
ep.mu.Lock()
|
||||
defer ep.mu.Unlock()
|
||||
return ep.count
|
||||
}
|
||||
|
||||
// Stop kills the expect process and waits for it to exit.
|
||||
func (ep *ExpectProcess) Stop() error { return ep.close(true) }
|
||||
|
||||
// Signal sends a signal to the expect process
|
||||
func (ep *ExpectProcess) Signal(sig os.Signal) error {
|
||||
return ep.cmd.Process.Signal(sig)
|
||||
}
|
||||
|
||||
// Close waits for the expect process to exit.
|
||||
func (ep *ExpectProcess) Close() error { return ep.close(false) }
|
||||
|
||||
func (ep *ExpectProcess) close(kill bool) error {
|
||||
if ep.cmd == nil {
|
||||
return ep.err
|
||||
}
|
||||
if kill {
|
||||
ep.cmd.Process.Kill()
|
||||
}
|
||||
|
||||
err := ep.cmd.Wait()
|
||||
ep.ptyMu.Lock()
|
||||
ep.fpty.Close()
|
||||
ep.ptyMu.Unlock()
|
||||
ep.wg.Wait()
|
||||
|
||||
if err != nil {
|
||||
ep.err = err
|
||||
if !kill && strings.Contains(err.Error(), "exit status") {
|
||||
// non-zero exit code
|
||||
err = nil
|
||||
} else if kill && strings.Contains(err.Error(), "signal:") {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
ep.cmd = nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (ep *ExpectProcess) Send(command string) error {
|
||||
_, err := io.WriteString(ep.fpty, command)
|
||||
return err
|
||||
}
|
||||
120
vendor/github.com/coreos/etcd/pkg/expect/expect_test.go
generated
vendored
Normal file
120
vendor/github.com/coreos/etcd/pkg/expect/expect_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// build !windows
|
||||
|
||||
package expect
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestExpectFunc(t *testing.T) {
|
||||
ep, err := NewExpect("/bin/echo", "hello world")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wstr := "hello world\r\n"
|
||||
l, eerr := ep.ExpectFunc(func(a string) bool { return len(a) > 10 })
|
||||
if eerr != nil {
|
||||
t.Fatal(eerr)
|
||||
}
|
||||
if l != wstr {
|
||||
t.Fatalf(`got "%v", expected "%v"`, l, wstr)
|
||||
}
|
||||
if cerr := ep.Close(); cerr != nil {
|
||||
t.Fatal(cerr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEcho(t *testing.T) {
|
||||
ep, err := NewExpect("/bin/echo", "hello world")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
l, eerr := ep.Expect("world")
|
||||
if eerr != nil {
|
||||
t.Fatal(eerr)
|
||||
}
|
||||
wstr := "hello world"
|
||||
if l[:len(wstr)] != wstr {
|
||||
t.Fatalf(`got "%v", expected "%v"`, l, wstr)
|
||||
}
|
||||
if cerr := ep.Close(); cerr != nil {
|
||||
t.Fatal(cerr)
|
||||
}
|
||||
if _, eerr = ep.Expect("..."); eerr == nil {
|
||||
t.Fatalf("expected error on closed expect process")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLineCount(t *testing.T) {
|
||||
ep, err := NewExpect("/usr/bin/printf", "1\n2\n3")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wstr := "3"
|
||||
l, eerr := ep.Expect(wstr)
|
||||
if eerr != nil {
|
||||
t.Fatal(eerr)
|
||||
}
|
||||
if l != wstr {
|
||||
t.Fatalf(`got "%v", expected "%v"`, l, wstr)
|
||||
}
|
||||
if ep.LineCount() != 3 {
|
||||
t.Fatalf("got %d, expected 3", ep.LineCount())
|
||||
}
|
||||
if cerr := ep.Close(); cerr != nil {
|
||||
t.Fatal(cerr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSend(t *testing.T) {
|
||||
ep, err := NewExpect("/usr/bin/tr", "a", "b")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ep.Send("a\r"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := ep.Expect("b"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ep.Stop(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignal(t *testing.T) {
|
||||
ep, err := NewExpect("/bin/sleep", "100")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ep.Signal(os.Interrupt)
|
||||
donec := make(chan struct{})
|
||||
go func() {
|
||||
defer close(donec)
|
||||
werr := "signal: interrupt"
|
||||
if cerr := ep.Close(); cerr == nil || cerr.Error() != werr {
|
||||
t.Fatalf("got error %v, wanted error %s", cerr, werr)
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatalf("signal test timed out")
|
||||
case <-donec:
|
||||
}
|
||||
}
|
||||
22
vendor/github.com/coreos/etcd/pkg/fileutil/dir_unix.go
generated
vendored
Normal file
22
vendor/github.com/coreos/etcd/pkg/fileutil/dir_unix.go
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !windows
|
||||
|
||||
package fileutil
|
||||
|
||||
import "os"
|
||||
|
||||
// OpenDir opens a directory for syncing.
|
||||
func OpenDir(path string) (*os.File, error) { return os.Open(path) }
|
||||
46
vendor/github.com/coreos/etcd/pkg/fileutil/dir_windows.go
generated
vendored
Normal file
46
vendor/github.com/coreos/etcd/pkg/fileutil/dir_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build windows
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// OpenDir opens a directory in windows with write access for syncing.
|
||||
func OpenDir(path string) (*os.File, error) {
|
||||
fd, err := openDir(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return os.NewFile(uintptr(fd), path), nil
|
||||
}
|
||||
|
||||
func openDir(path string) (fd syscall.Handle, err error) {
|
||||
if len(path) == 0 {
|
||||
return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND
|
||||
}
|
||||
pathp, err := syscall.UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
return syscall.InvalidHandle, err
|
||||
}
|
||||
access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE)
|
||||
sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE)
|
||||
createmode := uint32(syscall.OPEN_EXISTING)
|
||||
fl := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
|
||||
return syscall.CreateFile(pathp, access, sharemode, nil, createmode, fl, 0)
|
||||
}
|
||||
121
vendor/github.com/coreos/etcd/pkg/fileutil/fileutil.go
generated
vendored
Normal file
121
vendor/github.com/coreos/etcd/pkg/fileutil/fileutil.go
generated
vendored
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package fileutil implements utility functions related to files and paths.
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/coreos/pkg/capnslog"
|
||||
)
|
||||
|
||||
const (
|
||||
// PrivateFileMode grants owner to read/write a file.
|
||||
PrivateFileMode = 0600
|
||||
// PrivateDirMode grants owner to make/remove files inside the directory.
|
||||
PrivateDirMode = 0700
|
||||
)
|
||||
|
||||
var (
|
||||
plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "pkg/fileutil")
|
||||
)
|
||||
|
||||
// IsDirWriteable checks if dir is writable by writing and removing a file
|
||||
// to dir. It returns nil if dir is writable.
|
||||
func IsDirWriteable(dir string) error {
|
||||
f := filepath.Join(dir, ".touch")
|
||||
if err := ioutil.WriteFile(f, []byte(""), PrivateFileMode); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Remove(f)
|
||||
}
|
||||
|
||||
// ReadDir returns the filenames in the given directory in sorted order.
|
||||
func ReadDir(dirpath string) ([]string, error) {
|
||||
dir, err := os.Open(dirpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer dir.Close()
|
||||
names, err := dir.Readdirnames(-1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Strings(names)
|
||||
return names, nil
|
||||
}
|
||||
|
||||
// TouchDirAll is similar to os.MkdirAll. It creates directories with 0700 permission if any directory
|
||||
// does not exists. TouchDirAll also ensures the given directory is writable.
|
||||
func TouchDirAll(dir string) error {
|
||||
// If path is already a directory, MkdirAll does nothing
|
||||
// and returns nil.
|
||||
err := os.MkdirAll(dir, PrivateDirMode)
|
||||
if err != nil {
|
||||
// if mkdirAll("a/text") and "text" is not
|
||||
// a directory, this will return syscall.ENOTDIR
|
||||
return err
|
||||
}
|
||||
return IsDirWriteable(dir)
|
||||
}
|
||||
|
||||
// CreateDirAll is similar to TouchDirAll but returns error
|
||||
// if the deepest directory was not empty.
|
||||
func CreateDirAll(dir string) error {
|
||||
err := TouchDirAll(dir)
|
||||
if err == nil {
|
||||
var ns []string
|
||||
ns, err = ReadDir(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(ns) != 0 {
|
||||
err = fmt.Errorf("expected %q to be empty, got %q", dir, ns)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func Exist(name string) bool {
|
||||
_, err := os.Stat(name)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// ZeroToEnd zeros a file starting from SEEK_CUR to its SEEK_END. May temporarily
|
||||
// shorten the length of the file.
|
||||
func ZeroToEnd(f *os.File) error {
|
||||
// TODO: support FALLOC_FL_ZERO_RANGE
|
||||
off, err := f.Seek(0, os.SEEK_CUR)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lenf, lerr := f.Seek(0, os.SEEK_END)
|
||||
if lerr != nil {
|
||||
return lerr
|
||||
}
|
||||
if err = f.Truncate(off); err != nil {
|
||||
return err
|
||||
}
|
||||
// make sure blocks remain allocated
|
||||
if err = Preallocate(f, lenf, true); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Seek(off, os.SEEK_SET)
|
||||
return err
|
||||
}
|
||||
159
vendor/github.com/coreos/etcd/pkg/fileutil/fileutil_test.go
generated
vendored
Normal file
159
vendor/github.com/coreos/etcd/pkg/fileutil/fileutil_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIsDirWriteable(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected ioutil.TempDir error: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
if err = IsDirWriteable(tmpdir); err != nil {
|
||||
t.Fatalf("unexpected IsDirWriteable error: %v", err)
|
||||
}
|
||||
if err = os.Chmod(tmpdir, 0444); err != nil {
|
||||
t.Fatalf("unexpected os.Chmod error: %v", err)
|
||||
}
|
||||
me, err := user.Current()
|
||||
if err != nil {
|
||||
// err can be non-nil when cross compiled
|
||||
// http://stackoverflow.com/questions/20609415/cross-compiling-user-current-not-implemented-on-linux-amd64
|
||||
t.Skipf("failed to get current user: %v", err)
|
||||
}
|
||||
if me.Name == "root" || runtime.GOOS == "windows" {
|
||||
// ideally we should check CAP_DAC_OVERRIDE.
|
||||
// but it does not matter for tests.
|
||||
// Chmod is not supported under windows.
|
||||
t.Skipf("running as a superuser or in windows")
|
||||
}
|
||||
if err := IsDirWriteable(tmpdir); err == nil {
|
||||
t.Fatalf("expected IsDirWriteable to error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadDir(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
defer os.RemoveAll(tmpdir)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected ioutil.TempDir error: %v", err)
|
||||
}
|
||||
files := []string{"def", "abc", "xyz", "ghi"}
|
||||
for _, f := range files {
|
||||
var fh *os.File
|
||||
fh, err = os.Create(filepath.Join(tmpdir, f))
|
||||
if err != nil {
|
||||
t.Fatalf("error creating file: %v", err)
|
||||
}
|
||||
if err = fh.Close(); err != nil {
|
||||
t.Fatalf("error closing file: %v", err)
|
||||
}
|
||||
}
|
||||
fs, err := ReadDir(tmpdir)
|
||||
if err != nil {
|
||||
t.Fatalf("error calling ReadDir: %v", err)
|
||||
}
|
||||
wfs := []string{"abc", "def", "ghi", "xyz"}
|
||||
if !reflect.DeepEqual(fs, wfs) {
|
||||
t.Fatalf("ReadDir: got %v, want %v", fs, wfs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateDirAll(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir(os.TempDir(), "foo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
tmpdir2 := filepath.Join(tmpdir, "testdir")
|
||||
if err = CreateDirAll(tmpdir2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile(filepath.Join(tmpdir2, "text.txt"), []byte("test text"), PrivateFileMode); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err = CreateDirAll(tmpdir2); err == nil || !strings.Contains(err.Error(), "to be empty, got") {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExist(t *testing.T) {
|
||||
f, err := ioutil.TempFile(os.TempDir(), "fileutil")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
if g := Exist(f.Name()); !g {
|
||||
t.Errorf("exist = %v, want true", g)
|
||||
}
|
||||
|
||||
os.Remove(f.Name())
|
||||
if g := Exist(f.Name()); g {
|
||||
t.Errorf("exist = %v, want false", g)
|
||||
}
|
||||
}
|
||||
|
||||
func TestZeroToEnd(t *testing.T) {
|
||||
f, err := ioutil.TempFile(os.TempDir(), "fileutil")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
b := make([]byte, 1024)
|
||||
for i := range b {
|
||||
b[i] = 12
|
||||
}
|
||||
if _, err = f.Write(b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err = f.Seek(512, os.SEEK_SET); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = ZeroToEnd(f); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
off, serr := f.Seek(0, os.SEEK_CUR)
|
||||
if serr != nil {
|
||||
t.Fatal(serr)
|
||||
}
|
||||
if off != 512 {
|
||||
t.Fatalf("expected offset 512, got %d", off)
|
||||
}
|
||||
|
||||
b = make([]byte, 512)
|
||||
if _, err = f.Read(b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := range b {
|
||||
if b[i] != 0 {
|
||||
t.Errorf("expected b[%d] = 0, got %d", i, b[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
26
vendor/github.com/coreos/etcd/pkg/fileutil/lock.go
generated
vendored
Normal file
26
vendor/github.com/coreos/etcd/pkg/fileutil/lock.go
generated
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrLocked = errors.New("fileutil: file already locked")
|
||||
)
|
||||
|
||||
type LockedFile struct{ *os.File }
|
||||
49
vendor/github.com/coreos/etcd/pkg/fileutil/lock_flock.go
generated
vendored
Normal file
49
vendor/github.com/coreos/etcd/pkg/fileutil/lock_flock.go
generated
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !windows,!plan9,!solaris
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func flockTryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
|
||||
f, err := os.OpenFile(path, flag, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB); err != nil {
|
||||
f.Close()
|
||||
if err == syscall.EWOULDBLOCK {
|
||||
err = ErrLocked
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &LockedFile{f}, nil
|
||||
}
|
||||
|
||||
func flockLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
|
||||
f, err := os.OpenFile(path, flag, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX); err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &LockedFile{f}, err
|
||||
}
|
||||
96
vendor/github.com/coreos/etcd/pkg/fileutil/lock_linux.go
generated
vendored
Normal file
96
vendor/github.com/coreos/etcd/pkg/fileutil/lock_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build linux
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// This used to call syscall.Flock() but that call fails with EBADF on NFS.
|
||||
// An alternative is lockf() which works on NFS but that call lets a process lock
|
||||
// the same file twice. Instead, use Linux's non-standard open file descriptor
|
||||
// locks which will block if the process already holds the file lock.
|
||||
//
|
||||
// constants from /usr/include/bits/fcntl-linux.h
|
||||
const (
|
||||
F_OFD_GETLK = 37
|
||||
F_OFD_SETLK = 37
|
||||
F_OFD_SETLKW = 38
|
||||
)
|
||||
|
||||
var (
|
||||
wrlck = syscall.Flock_t{
|
||||
Type: syscall.F_WRLCK,
|
||||
Whence: int16(os.SEEK_SET),
|
||||
Start: 0,
|
||||
Len: 0,
|
||||
}
|
||||
|
||||
linuxTryLockFile = flockTryLockFile
|
||||
linuxLockFile = flockLockFile
|
||||
)
|
||||
|
||||
func init() {
|
||||
// use open file descriptor locks if the system supports it
|
||||
getlk := syscall.Flock_t{Type: syscall.F_RDLCK}
|
||||
if err := syscall.FcntlFlock(0, F_OFD_GETLK, &getlk); err == nil {
|
||||
linuxTryLockFile = ofdTryLockFile
|
||||
linuxLockFile = ofdLockFile
|
||||
}
|
||||
}
|
||||
|
||||
func TryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
|
||||
return linuxTryLockFile(path, flag, perm)
|
||||
}
|
||||
|
||||
func ofdTryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
|
||||
f, err := os.OpenFile(path, flag, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
flock := wrlck
|
||||
if err = syscall.FcntlFlock(f.Fd(), F_OFD_SETLK, &flock); err != nil {
|
||||
f.Close()
|
||||
if err == syscall.EWOULDBLOCK {
|
||||
err = ErrLocked
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &LockedFile{f}, nil
|
||||
}
|
||||
|
||||
func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
|
||||
return linuxLockFile(path, flag, perm)
|
||||
}
|
||||
|
||||
func ofdLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
|
||||
f, err := os.OpenFile(path, flag, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
flock := wrlck
|
||||
err = syscall.FcntlFlock(f.Fd(), F_OFD_SETLKW, &flock)
|
||||
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &LockedFile{f}, err
|
||||
}
|
||||
45
vendor/github.com/coreos/etcd/pkg/fileutil/lock_plan9.go
generated
vendored
Normal file
45
vendor/github.com/coreos/etcd/pkg/fileutil/lock_plan9.go
generated
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
|
||||
if err := os.Chmod(path, syscall.DMEXCL|PrivateFileMode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := os.Open(path, flag, perm)
|
||||
if err != nil {
|
||||
return nil, ErrLocked
|
||||
}
|
||||
return &LockedFile{f}, nil
|
||||
}
|
||||
|
||||
func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
|
||||
if err := os.Chmod(path, syscall.DMEXCL|PrivateFileMode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for {
|
||||
f, err := os.OpenFile(path, flag, perm)
|
||||
if err == nil {
|
||||
return &LockedFile{f}, nil
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
62
vendor/github.com/coreos/etcd/pkg/fileutil/lock_solaris.go
generated
vendored
Normal file
62
vendor/github.com/coreos/etcd/pkg/fileutil/lock_solaris.go
generated
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build solaris
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func TryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
|
||||
var lock syscall.Flock_t
|
||||
lock.Start = 0
|
||||
lock.Len = 0
|
||||
lock.Pid = 0
|
||||
lock.Type = syscall.F_WRLCK
|
||||
lock.Whence = 0
|
||||
lock.Pid = 0
|
||||
f, err := os.OpenFile(path, flag, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := syscall.FcntlFlock(f.Fd(), syscall.F_SETLK, &lock); err != nil {
|
||||
f.Close()
|
||||
if err == syscall.EAGAIN {
|
||||
err = ErrLocked
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &LockedFile{f}, nil
|
||||
}
|
||||
|
||||
func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
|
||||
var lock syscall.Flock_t
|
||||
lock.Start = 0
|
||||
lock.Len = 0
|
||||
lock.Pid = 0
|
||||
lock.Type = syscall.F_WRLCK
|
||||
lock.Whence = 0
|
||||
f, err := os.OpenFile(path, flag, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = syscall.FcntlFlock(f.Fd(), syscall.F_SETLKW, &lock); err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &LockedFile{f}, nil
|
||||
}
|
||||
89
vendor/github.com/coreos/etcd/pkg/fileutil/lock_test.go
generated
vendored
Normal file
89
vendor/github.com/coreos/etcd/pkg/fileutil/lock_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestLockAndUnlock(t *testing.T) {
|
||||
f, err := ioutil.TempFile("", "lock")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f.Close()
|
||||
defer func() {
|
||||
err = os.Remove(f.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// lock the file
|
||||
l, err := LockFile(f.Name(), os.O_WRONLY, PrivateFileMode)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// try lock a locked file
|
||||
if _, err = TryLockFile(f.Name(), os.O_WRONLY, PrivateFileMode); err != ErrLocked {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// unlock the file
|
||||
if err = l.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// try lock the unlocked file
|
||||
dupl, err := TryLockFile(f.Name(), os.O_WRONLY, PrivateFileMode)
|
||||
if err != nil {
|
||||
t.Errorf("err = %v, want %v", err, nil)
|
||||
}
|
||||
|
||||
// blocking on locked file
|
||||
locked := make(chan struct{}, 1)
|
||||
go func() {
|
||||
bl, blerr := LockFile(f.Name(), os.O_WRONLY, PrivateFileMode)
|
||||
if blerr != nil {
|
||||
t.Fatal(blerr)
|
||||
}
|
||||
locked <- struct{}{}
|
||||
if blerr = bl.Close(); blerr != nil {
|
||||
t.Fatal(blerr)
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-locked:
|
||||
t.Error("unexpected unblocking")
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
}
|
||||
|
||||
// unlock
|
||||
if err = dupl.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// the previously blocked routine should be unblocked
|
||||
select {
|
||||
case <-locked:
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Error("unexpected blocking")
|
||||
}
|
||||
}
|
||||
29
vendor/github.com/coreos/etcd/pkg/fileutil/lock_unix.go
generated
vendored
Normal file
29
vendor/github.com/coreos/etcd/pkg/fileutil/lock_unix.go
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !windows,!plan9,!solaris,!linux
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func TryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
|
||||
return flockTryLockFile(path, flag, perm)
|
||||
}
|
||||
|
||||
func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
|
||||
return flockLockFile(path, flag, perm)
|
||||
}
|
||||
125
vendor/github.com/coreos/etcd/pkg/fileutil/lock_windows.go
generated
vendored
Normal file
125
vendor/github.com/coreos/etcd/pkg/fileutil/lock_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build windows
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
procLockFileEx = modkernel32.NewProc("LockFileEx")
|
||||
|
||||
errLocked = errors.New("The process cannot access the file because another process has locked a portion of the file.")
|
||||
)
|
||||
|
||||
const (
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
|
||||
LOCKFILE_EXCLUSIVE_LOCK = 2
|
||||
LOCKFILE_FAIL_IMMEDIATELY = 1
|
||||
|
||||
// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
|
||||
errLockViolation syscall.Errno = 0x21
|
||||
)
|
||||
|
||||
func TryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
|
||||
f, err := open(path, flag, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := lockFile(syscall.Handle(f.Fd()), LOCKFILE_FAIL_IMMEDIATELY); err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &LockedFile{f}, nil
|
||||
}
|
||||
|
||||
func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
|
||||
f, err := open(path, flag, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := lockFile(syscall.Handle(f.Fd()), 0); err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
return &LockedFile{f}, nil
|
||||
}
|
||||
|
||||
func open(path string, flag int, perm os.FileMode) (*os.File, error) {
|
||||
if path == "" {
|
||||
return nil, fmt.Errorf("cannot open empty filename")
|
||||
}
|
||||
var access uint32
|
||||
switch flag {
|
||||
case syscall.O_RDONLY:
|
||||
access = syscall.GENERIC_READ
|
||||
case syscall.O_WRONLY:
|
||||
access = syscall.GENERIC_WRITE
|
||||
case syscall.O_RDWR:
|
||||
access = syscall.GENERIC_READ | syscall.GENERIC_WRITE
|
||||
case syscall.O_WRONLY | syscall.O_CREAT:
|
||||
access = syscall.GENERIC_ALL
|
||||
default:
|
||||
panic(fmt.Errorf("flag %v is not supported", flag))
|
||||
}
|
||||
fd, err := syscall.CreateFile(&(syscall.StringToUTF16(path)[0]),
|
||||
access,
|
||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
|
||||
nil,
|
||||
syscall.OPEN_ALWAYS,
|
||||
syscall.FILE_ATTRIBUTE_NORMAL,
|
||||
0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return os.NewFile(uintptr(fd), path), nil
|
||||
}
|
||||
|
||||
func lockFile(fd syscall.Handle, flags uint32) error {
|
||||
var flag uint32 = LOCKFILE_EXCLUSIVE_LOCK
|
||||
flag |= flags
|
||||
if fd == syscall.InvalidHandle {
|
||||
return nil
|
||||
}
|
||||
err := lockFileEx(fd, flag, 1, 0, &syscall.Overlapped{})
|
||||
if err == nil {
|
||||
return nil
|
||||
} else if err.Error() == errLocked.Error() {
|
||||
return ErrLocked
|
||||
} else if err != errLockViolation {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func lockFileEx(h syscall.Handle, flags, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
|
||||
var reserved uint32 = 0
|
||||
r1, _, e1 := syscall.Syscall6(procLockFileEx.Addr(), 6, uintptr(h), uintptr(flags), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
47
vendor/github.com/coreos/etcd/pkg/fileutil/preallocate.go
generated
vendored
Normal file
47
vendor/github.com/coreos/etcd/pkg/fileutil/preallocate.go
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package fileutil
|
||||
|
||||
import "os"
|
||||
|
||||
// Preallocate tries to allocate the space for given
|
||||
// file. This operation is only supported on linux by a
|
||||
// few filesystems (btrfs, ext4, etc.).
|
||||
// If the operation is unsupported, no error will be returned.
|
||||
// Otherwise, the error encountered will be returned.
|
||||
func Preallocate(f *os.File, sizeInBytes int64, extendFile bool) error {
|
||||
if extendFile {
|
||||
return preallocExtend(f, sizeInBytes)
|
||||
}
|
||||
return preallocFixed(f, sizeInBytes)
|
||||
}
|
||||
|
||||
func preallocExtendTrunc(f *os.File, sizeInBytes int64) error {
|
||||
curOff, err := f.Seek(0, os.SEEK_CUR)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
size, err := f.Seek(sizeInBytes, os.SEEK_END)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = f.Seek(curOff, os.SEEK_SET); err != nil {
|
||||
return err
|
||||
}
|
||||
if sizeInBytes > size {
|
||||
return nil
|
||||
}
|
||||
return f.Truncate(sizeInBytes)
|
||||
}
|
||||
43
vendor/github.com/coreos/etcd/pkg/fileutil/preallocate_darwin.go
generated
vendored
Normal file
43
vendor/github.com/coreos/etcd/pkg/fileutil/preallocate_darwin.go
generated
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build darwin
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func preallocExtend(f *os.File, sizeInBytes int64) error {
|
||||
if err := preallocFixed(f, sizeInBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
return preallocExtendTrunc(f, sizeInBytes)
|
||||
}
|
||||
|
||||
func preallocFixed(f *os.File, sizeInBytes int64) error {
|
||||
fstore := &syscall.Fstore_t{
|
||||
Flags: syscall.F_ALLOCATEALL,
|
||||
Posmode: syscall.F_PEOFPOSMODE,
|
||||
Length: sizeInBytes}
|
||||
p := unsafe.Pointer(fstore)
|
||||
_, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_PREALLOCATE), uintptr(p))
|
||||
if errno == 0 || errno == syscall.ENOTSUP {
|
||||
return nil
|
||||
}
|
||||
return errno
|
||||
}
|
||||
67
vendor/github.com/coreos/etcd/pkg/fileutil/preallocate_test.go
generated
vendored
Normal file
67
vendor/github.com/coreos/etcd/pkg/fileutil/preallocate_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPreallocateExtend(t *testing.T) { runPreallocTest(t, testPreallocateExtend) }
|
||||
func testPreallocateExtend(t *testing.T, f *os.File) {
|
||||
size := int64(64 * 1000)
|
||||
if err := Preallocate(f, size, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stat, err := f.Stat()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if stat.Size() != size {
|
||||
t.Errorf("size = %d, want %d", stat.Size(), size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPreallocateFixed(t *testing.T) { runPreallocTest(t, testPreallocateFixed) }
|
||||
func testPreallocateFixed(t *testing.T, f *os.File) {
|
||||
size := int64(64 * 1000)
|
||||
if err := Preallocate(f, size, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stat, err := f.Stat()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if stat.Size() != 0 {
|
||||
t.Errorf("size = %d, want %d", stat.Size(), 0)
|
||||
}
|
||||
}
|
||||
|
||||
func runPreallocTest(t *testing.T, test func(*testing.T, *os.File)) {
|
||||
p, err := ioutil.TempDir(os.TempDir(), "preallocateTest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(p)
|
||||
|
||||
f, err := ioutil.TempFile(p, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
test(t, f)
|
||||
}
|
||||
49
vendor/github.com/coreos/etcd/pkg/fileutil/preallocate_unix.go
generated
vendored
Normal file
49
vendor/github.com/coreos/etcd/pkg/fileutil/preallocate_unix.go
generated
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build linux
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func preallocExtend(f *os.File, sizeInBytes int64) error {
|
||||
// use mode = 0 to change size
|
||||
err := syscall.Fallocate(int(f.Fd()), 0, 0, sizeInBytes)
|
||||
if err != nil {
|
||||
errno, ok := err.(syscall.Errno)
|
||||
// not supported; fallback
|
||||
// fallocate EINTRs frequently in some environments; fallback
|
||||
if ok && (errno == syscall.ENOTSUP || errno == syscall.EINTR) {
|
||||
return preallocExtendTrunc(f, sizeInBytes)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func preallocFixed(f *os.File, sizeInBytes int64) error {
|
||||
// use mode = 1 to keep size; see FALLOC_FL_KEEP_SIZE
|
||||
err := syscall.Fallocate(int(f.Fd()), 1, 0, sizeInBytes)
|
||||
if err != nil {
|
||||
errno, ok := err.(syscall.Errno)
|
||||
// treat not supported as nil error
|
||||
if ok && errno == syscall.ENOTSUP {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
25
vendor/github.com/coreos/etcd/pkg/fileutil/preallocate_unsupported.go
generated
vendored
Normal file
25
vendor/github.com/coreos/etcd/pkg/fileutil/preallocate_unsupported.go
generated
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !linux,!darwin
|
||||
|
||||
package fileutil
|
||||
|
||||
import "os"
|
||||
|
||||
func preallocExtend(f *os.File, sizeInBytes int64) error {
|
||||
return preallocExtendTrunc(f, sizeInBytes)
|
||||
}
|
||||
|
||||
func preallocFixed(f *os.File, sizeInBytes int64) error { return nil }
|
||||
78
vendor/github.com/coreos/etcd/pkg/fileutil/purge.go
generated
vendored
Normal file
78
vendor/github.com/coreos/etcd/pkg/fileutil/purge.go
generated
vendored
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func PurgeFile(dirname string, suffix string, max uint, interval time.Duration, stop <-chan struct{}) <-chan error {
|
||||
return purgeFile(dirname, suffix, max, interval, stop, nil)
|
||||
}
|
||||
|
||||
// purgeFile is the internal implementation for PurgeFile which can post purged files to purgec if non-nil.
|
||||
func purgeFile(dirname string, suffix string, max uint, interval time.Duration, stop <-chan struct{}, purgec chan<- string) <-chan error {
|
||||
errC := make(chan error, 1)
|
||||
go func() {
|
||||
for {
|
||||
fnames, err := ReadDir(dirname)
|
||||
if err != nil {
|
||||
errC <- err
|
||||
return
|
||||
}
|
||||
newfnames := make([]string, 0)
|
||||
for _, fname := range fnames {
|
||||
if strings.HasSuffix(fname, suffix) {
|
||||
newfnames = append(newfnames, fname)
|
||||
}
|
||||
}
|
||||
sort.Strings(newfnames)
|
||||
fnames = newfnames
|
||||
for len(newfnames) > int(max) {
|
||||
f := filepath.Join(dirname, newfnames[0])
|
||||
l, err := TryLockFile(f, os.O_WRONLY, PrivateFileMode)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if err = os.Remove(f); err != nil {
|
||||
errC <- err
|
||||
return
|
||||
}
|
||||
if err = l.Close(); err != nil {
|
||||
plog.Errorf("error unlocking %s when purging file (%v)", l.Name(), err)
|
||||
errC <- err
|
||||
return
|
||||
}
|
||||
plog.Infof("purged file %s successfully", f)
|
||||
newfnames = newfnames[1:]
|
||||
}
|
||||
if purgec != nil {
|
||||
for i := 0; i < len(fnames)-len(newfnames); i++ {
|
||||
purgec <- fnames[i]
|
||||
}
|
||||
}
|
||||
select {
|
||||
case <-time.After(interval):
|
||||
case <-stop:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return errC
|
||||
}
|
||||
177
vendor/github.com/coreos/etcd/pkg/fileutil/purge_test.go
generated
vendored
Normal file
177
vendor/github.com/coreos/etcd/pkg/fileutil/purge_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestPurgeFile(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "purgefile")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
// minimal file set
|
||||
for i := 0; i < 3; i++ {
|
||||
f, ferr := os.Create(filepath.Join(dir, fmt.Sprintf("%d.test", i)))
|
||||
if ferr != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
|
||||
stop, purgec := make(chan struct{}), make(chan string, 10)
|
||||
|
||||
// keep 3 most recent files
|
||||
errch := purgeFile(dir, "test", 3, time.Millisecond, stop, purgec)
|
||||
select {
|
||||
case f := <-purgec:
|
||||
t.Errorf("unexpected purge on %q", f)
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
}
|
||||
|
||||
// rest of the files
|
||||
for i := 4; i < 10; i++ {
|
||||
go func(n int) {
|
||||
f, ferr := os.Create(filepath.Join(dir, fmt.Sprintf("%d.test", n)))
|
||||
if ferr != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f.Close()
|
||||
}(i)
|
||||
}
|
||||
|
||||
// watch files purge away
|
||||
for i := 4; i < 10; i++ {
|
||||
select {
|
||||
case <-purgec:
|
||||
case <-time.After(time.Second):
|
||||
t.Errorf("purge took too long")
|
||||
}
|
||||
}
|
||||
|
||||
fnames, rerr := ReadDir(dir)
|
||||
if rerr != nil {
|
||||
t.Fatal(rerr)
|
||||
}
|
||||
wnames := []string{"7.test", "8.test", "9.test"}
|
||||
if !reflect.DeepEqual(fnames, wnames) {
|
||||
t.Errorf("filenames = %v, want %v", fnames, wnames)
|
||||
}
|
||||
|
||||
// no error should be reported from purge routine
|
||||
select {
|
||||
case f := <-purgec:
|
||||
t.Errorf("unexpected purge on %q", f)
|
||||
case err := <-errch:
|
||||
t.Errorf("unexpected purge error %v", err)
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
}
|
||||
close(stop)
|
||||
}
|
||||
|
||||
func TestPurgeFileHoldingLockFile(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "purgefile")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
var f *os.File
|
||||
f, err = os.Create(filepath.Join(dir, fmt.Sprintf("%d.test", i)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
|
||||
// create a purge barrier at 5
|
||||
p := filepath.Join(dir, fmt.Sprintf("%d.test", 5))
|
||||
l, err := LockFile(p, os.O_WRONLY, PrivateFileMode)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stop, purgec := make(chan struct{}), make(chan string, 10)
|
||||
errch := purgeFile(dir, "test", 3, time.Millisecond, stop, purgec)
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
select {
|
||||
case <-purgec:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatalf("purge took too long")
|
||||
}
|
||||
}
|
||||
|
||||
fnames, rerr := ReadDir(dir)
|
||||
if rerr != nil {
|
||||
t.Fatal(rerr)
|
||||
}
|
||||
|
||||
wnames := []string{"5.test", "6.test", "7.test", "8.test", "9.test"}
|
||||
if !reflect.DeepEqual(fnames, wnames) {
|
||||
t.Errorf("filenames = %v, want %v", fnames, wnames)
|
||||
}
|
||||
|
||||
select {
|
||||
case s := <-purgec:
|
||||
t.Errorf("unexpected purge %q", s)
|
||||
case err = <-errch:
|
||||
t.Errorf("unexpected purge error %v", err)
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
}
|
||||
|
||||
// remove the purge barrier
|
||||
if err = l.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// wait for rest of purges (5, 6)
|
||||
for i := 0; i < 2; i++ {
|
||||
select {
|
||||
case <-purgec:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatalf("purge took too long")
|
||||
}
|
||||
}
|
||||
|
||||
fnames, rerr = ReadDir(dir)
|
||||
if rerr != nil {
|
||||
t.Fatal(rerr)
|
||||
}
|
||||
wnames = []string{"7.test", "8.test", "9.test"}
|
||||
if !reflect.DeepEqual(fnames, wnames) {
|
||||
t.Errorf("filenames = %v, want %v", fnames, wnames)
|
||||
}
|
||||
|
||||
select {
|
||||
case f := <-purgec:
|
||||
t.Errorf("unexpected purge on %q", f)
|
||||
case err := <-errch:
|
||||
t.Errorf("unexpected purge error %v", err)
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
}
|
||||
|
||||
close(stop)
|
||||
}
|
||||
29
vendor/github.com/coreos/etcd/pkg/fileutil/sync.go
generated
vendored
Normal file
29
vendor/github.com/coreos/etcd/pkg/fileutil/sync.go
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !linux,!darwin
|
||||
|
||||
package fileutil
|
||||
|
||||
import "os"
|
||||
|
||||
// Fsync is a wrapper around file.Sync(). Special handling is needed on darwin platform.
|
||||
func Fsync(f *os.File) error {
|
||||
return f.Sync()
|
||||
}
|
||||
|
||||
// Fdatasync is a wrapper around file.Sync(). Special handling is needed on linux platform.
|
||||
func Fdatasync(f *os.File) error {
|
||||
return f.Sync()
|
||||
}
|
||||
40
vendor/github.com/coreos/etcd/pkg/fileutil/sync_darwin.go
generated
vendored
Normal file
40
vendor/github.com/coreos/etcd/pkg/fileutil/sync_darwin.go
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build darwin
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Fsync on HFS/OSX flushes the data on to the physical drive but the drive
|
||||
// may not write it to the persistent media for quite sometime and it may be
|
||||
// written in out-of-order sequence. Using F_FULLFSYNC ensures that the
|
||||
// physical drive's buffer will also get flushed to the media.
|
||||
func Fsync(f *os.File) error {
|
||||
_, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_FULLFSYNC), uintptr(0))
|
||||
if errno == 0 {
|
||||
return nil
|
||||
}
|
||||
return errno
|
||||
}
|
||||
|
||||
// Fdatasync on darwin platform invokes fcntl(F_FULLFSYNC) for actual persistence
|
||||
// on physical drive media.
|
||||
func Fdatasync(f *os.File) error {
|
||||
return Fsync(f)
|
||||
}
|
||||
34
vendor/github.com/coreos/etcd/pkg/fileutil/sync_linux.go
generated
vendored
Normal file
34
vendor/github.com/coreos/etcd/pkg/fileutil/sync_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build linux
|
||||
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Fsync is a wrapper around file.Sync(). Special handling is needed on darwin platform.
|
||||
func Fsync(f *os.File) error {
|
||||
return f.Sync()
|
||||
}
|
||||
|
||||
// Fdatasync is similar to fsync(), but does not flush modified metadata
|
||||
// unless that metadata is needed in order to allow a subsequent data retrieval
|
||||
// to be correctly handled.
|
||||
func Fdatasync(f *os.File) error {
|
||||
return syscall.Fdatasync(int(f.Fd()))
|
||||
}
|
||||
164
vendor/github.com/coreos/etcd/pkg/flags/flag.go
generated
vendored
Normal file
164
vendor/github.com/coreos/etcd/pkg/flags/flag.go
generated
vendored
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package flags implements command-line flag parsing.
|
||||
package flags
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/coreos/pkg/capnslog"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var (
|
||||
plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "pkg/flags")
|
||||
)
|
||||
|
||||
// DeprecatedFlag encapsulates a flag that may have been previously valid but
|
||||
// is now deprecated. If a DeprecatedFlag is set, an error occurs.
|
||||
type DeprecatedFlag struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (f *DeprecatedFlag) Set(_ string) error {
|
||||
return fmt.Errorf(`flag "-%s" is no longer supported.`, f.Name)
|
||||
}
|
||||
|
||||
func (f *DeprecatedFlag) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// IgnoredFlag encapsulates a flag that may have been previously valid but is
|
||||
// now ignored. If an IgnoredFlag is set, a warning is printed and
|
||||
// operation continues.
|
||||
type IgnoredFlag struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
// IsBoolFlag is defined to allow the flag to be defined without an argument
|
||||
func (f *IgnoredFlag) IsBoolFlag() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (f *IgnoredFlag) Set(s string) error {
|
||||
plog.Warningf(`flag "-%s" is no longer supported - ignoring.`, f.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *IgnoredFlag) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// SetFlagsFromEnv parses all registered flags in the given flagset,
|
||||
// and if they are not already set it attempts to set their values from
|
||||
// environment variables. Environment variables take the name of the flag but
|
||||
// are UPPERCASE, have the given prefix and any dashes are replaced by
|
||||
// underscores - for example: some-flag => ETCD_SOME_FLAG
|
||||
func SetFlagsFromEnv(prefix string, fs *flag.FlagSet) error {
|
||||
var err error
|
||||
alreadySet := make(map[string]bool)
|
||||
fs.Visit(func(f *flag.Flag) {
|
||||
alreadySet[FlagToEnv(prefix, f.Name)] = true
|
||||
})
|
||||
usedEnvKey := make(map[string]bool)
|
||||
fs.VisitAll(func(f *flag.Flag) {
|
||||
err = setFlagFromEnv(fs, prefix, f.Name, usedEnvKey, alreadySet, true)
|
||||
})
|
||||
|
||||
verifyEnv(prefix, usedEnvKey, alreadySet)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// SetPflagsFromEnv is similar to SetFlagsFromEnv. However, the accepted flagset type is pflag.FlagSet
|
||||
// and it does not do any logging.
|
||||
func SetPflagsFromEnv(prefix string, fs *pflag.FlagSet) error {
|
||||
var err error
|
||||
alreadySet := make(map[string]bool)
|
||||
usedEnvKey := make(map[string]bool)
|
||||
fs.VisitAll(func(f *pflag.Flag) {
|
||||
if f.Changed {
|
||||
alreadySet[FlagToEnv(prefix, f.Name)] = true
|
||||
}
|
||||
if serr := setFlagFromEnv(fs, prefix, f.Name, usedEnvKey, alreadySet, false); serr != nil {
|
||||
err = serr
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// FlagToEnv converts flag string to upper-case environment variable key string.
|
||||
func FlagToEnv(prefix, name string) string {
|
||||
return prefix + "_" + strings.ToUpper(strings.Replace(name, "-", "_", -1))
|
||||
}
|
||||
|
||||
func verifyEnv(prefix string, usedEnvKey, alreadySet map[string]bool) {
|
||||
for _, env := range os.Environ() {
|
||||
kv := strings.SplitN(env, "=", 2)
|
||||
if len(kv) != 2 {
|
||||
plog.Warningf("found invalid env %s", env)
|
||||
}
|
||||
if usedEnvKey[kv[0]] {
|
||||
continue
|
||||
}
|
||||
if alreadySet[kv[0]] {
|
||||
plog.Infof("recognized environment variable %s, but unused: shadowed by corresponding flag ", kv[0])
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(env, prefix+"_") {
|
||||
plog.Warningf("unrecognized environment variable %s", env)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type flagSetter interface {
|
||||
Set(fk string, fv string) error
|
||||
}
|
||||
|
||||
func setFlagFromEnv(fs flagSetter, prefix, fname string, usedEnvKey, alreadySet map[string]bool, log bool) error {
|
||||
key := FlagToEnv(prefix, fname)
|
||||
if !alreadySet[key] {
|
||||
val := os.Getenv(key)
|
||||
if val != "" {
|
||||
usedEnvKey[key] = true
|
||||
if serr := fs.Set(fname, val); serr != nil {
|
||||
return fmt.Errorf("invalid value %q for %s: %v", val, key, serr)
|
||||
}
|
||||
if log {
|
||||
plog.Infof("recognized and used environment variable %s=%s", key, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// URLsFromFlag returns a slices from url got from the flag.
|
||||
func URLsFromFlag(fs *flag.FlagSet, urlsFlagName string) []url.URL {
|
||||
return []url.URL(*fs.Lookup(urlsFlagName).Value.(*URLsValue))
|
||||
}
|
||||
|
||||
func IsSet(fs *flag.FlagSet, name string) bool {
|
||||
set := false
|
||||
fs.Visit(func(f *flag.Flag) {
|
||||
if f.Name == name {
|
||||
set = true
|
||||
}
|
||||
})
|
||||
return set
|
||||
}
|
||||
78
vendor/github.com/coreos/etcd/pkg/flags/flag_test.go
generated
vendored
Normal file
78
vendor/github.com/coreos/etcd/pkg/flags/flag_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package flags
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSetFlagsFromEnv(t *testing.T) {
|
||||
fs := flag.NewFlagSet("testing", flag.ExitOnError)
|
||||
fs.String("a", "", "")
|
||||
fs.String("b", "", "")
|
||||
fs.String("c", "", "")
|
||||
fs.Parse([]string{})
|
||||
|
||||
os.Clearenv()
|
||||
// flags should be settable using env vars
|
||||
os.Setenv("ETCD_A", "foo")
|
||||
// and command-line flags
|
||||
if err := fs.Set("b", "bar"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// command-line flags take precedence over env vars
|
||||
os.Setenv("ETCD_C", "woof")
|
||||
if err := fs.Set("c", "quack"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// first verify that flags are as expected before reading the env
|
||||
for f, want := range map[string]string{
|
||||
"a": "",
|
||||
"b": "bar",
|
||||
"c": "quack",
|
||||
} {
|
||||
if got := fs.Lookup(f).Value.String(); got != want {
|
||||
t.Fatalf("flag %q=%q, want %q", f, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// now read the env and verify flags were updated as expected
|
||||
err := SetFlagsFromEnv("ETCD", fs)
|
||||
if err != nil {
|
||||
t.Errorf("err=%v, want nil", err)
|
||||
}
|
||||
for f, want := range map[string]string{
|
||||
"a": "foo",
|
||||
"b": "bar",
|
||||
"c": "quack",
|
||||
} {
|
||||
if got := fs.Lookup(f).Value.String(); got != want {
|
||||
t.Errorf("flag %q=%q, want %q", f, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetFlagsFromEnvBad(t *testing.T) {
|
||||
// now verify that an error is propagated
|
||||
fs := flag.NewFlagSet("testing", flag.ExitOnError)
|
||||
fs.Int("x", 0, "")
|
||||
os.Setenv("ETCD_X", "not_a_number")
|
||||
if err := SetFlagsFromEnv("ETCD", fs); err == nil {
|
||||
t.Errorf("err=nil, want != nil")
|
||||
}
|
||||
}
|
||||
46
vendor/github.com/coreos/etcd/pkg/flags/strings.go
generated
vendored
Normal file
46
vendor/github.com/coreos/etcd/pkg/flags/strings.go
generated
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package flags
|
||||
|
||||
import "errors"
|
||||
|
||||
// NewStringsFlag creates a new string flag for which any one of the given
|
||||
// strings is a valid value, and any other value is an error.
|
||||
func NewStringsFlag(valids ...string) *StringsFlag {
|
||||
return &StringsFlag{Values: valids}
|
||||
}
|
||||
|
||||
// StringsFlag implements the flag.Value interface.
|
||||
type StringsFlag struct {
|
||||
Values []string
|
||||
val string
|
||||
}
|
||||
|
||||
// Set verifies the argument to be a valid member of the allowed values
|
||||
// before setting the underlying flag value.
|
||||
func (ss *StringsFlag) Set(s string) error {
|
||||
for _, v := range ss.Values {
|
||||
if s == v {
|
||||
ss.val = s
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.New("invalid value")
|
||||
}
|
||||
|
||||
// String returns the set value (if any) of the StringsFlag
|
||||
func (ss *StringsFlag) String() string {
|
||||
return ss.val
|
||||
}
|
||||
45
vendor/github.com/coreos/etcd/pkg/flags/strings_test.go
generated
vendored
Normal file
45
vendor/github.com/coreos/etcd/pkg/flags/strings_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package flags
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStringsSet(t *testing.T) {
|
||||
tests := []struct {
|
||||
vals []string
|
||||
|
||||
val string
|
||||
pass bool
|
||||
}{
|
||||
// known values
|
||||
{[]string{"abc", "def"}, "abc", true},
|
||||
{[]string{"on", "off", "false"}, "on", true},
|
||||
|
||||
// unrecognized values
|
||||
{[]string{"abc", "def"}, "ghi", false},
|
||||
{[]string{"on", "off"}, "", false},
|
||||
{[]string{}, "asdf", false},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
sf := NewStringsFlag(tt.vals...)
|
||||
err := sf.Set(tt.val)
|
||||
if tt.pass != (err == nil) {
|
||||
t.Errorf("#%d: want pass=%t, but got err=%v", i, tt.pass, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
52
vendor/github.com/coreos/etcd/pkg/flags/urls.go
generated
vendored
Normal file
52
vendor/github.com/coreos/etcd/pkg/flags/urls.go
generated
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package flags
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/coreos/etcd/pkg/types"
|
||||
)
|
||||
|
||||
type URLsValue types.URLs
|
||||
|
||||
// Set parses a command line set of URLs formatted like:
|
||||
// http://127.0.0.1:2380,http://10.1.1.2:80
|
||||
func (us *URLsValue) Set(s string) error {
|
||||
strs := strings.Split(s, ",")
|
||||
nus, err := types.NewURLs(strs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*us = URLsValue(nus)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (us *URLsValue) String() string {
|
||||
all := make([]string, len(*us))
|
||||
for i, u := range *us {
|
||||
all[i] = u.String()
|
||||
}
|
||||
return strings.Join(all, ",")
|
||||
}
|
||||
|
||||
func NewURLsValue(init string) *URLsValue {
|
||||
v := &URLsValue{}
|
||||
if err := v.Set(init); err != nil {
|
||||
plog.Panicf("new URLsValue should never fail: %v", err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
61
vendor/github.com/coreos/etcd/pkg/flags/urls_test.go
generated
vendored
Normal file
61
vendor/github.com/coreos/etcd/pkg/flags/urls_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package flags
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidateURLsValueBad(t *testing.T) {
|
||||
tests := []string{
|
||||
// bad IP specification
|
||||
":2379",
|
||||
"127.0:8080",
|
||||
"123:456",
|
||||
// bad port specification
|
||||
"127.0.0.1:foo",
|
||||
"127.0.0.1:",
|
||||
// unix sockets not supported
|
||||
"unix://",
|
||||
"unix://tmp/etcd.sock",
|
||||
// bad strings
|
||||
"somewhere",
|
||||
"234#$",
|
||||
"file://foo/bar",
|
||||
"http://hello/asdf",
|
||||
"http://10.1.1.1",
|
||||
}
|
||||
for i, in := range tests {
|
||||
u := URLsValue{}
|
||||
if err := u.Set(in); err == nil {
|
||||
t.Errorf(`#%d: unexpected nil error for in=%q`, i, in)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateURLsValueGood(t *testing.T) {
|
||||
tests := []string{
|
||||
"https://1.2.3.4:8080",
|
||||
"http://10.1.1.1:80",
|
||||
"http://localhost:80",
|
||||
"http://:80",
|
||||
}
|
||||
for i, in := range tests {
|
||||
u := URLsValue{}
|
||||
if err := u.Set(in); err != nil {
|
||||
t.Errorf("#%d: err=%v, want nil for in=%q", i, err, in)
|
||||
}
|
||||
}
|
||||
}
|
||||
31
vendor/github.com/coreos/etcd/pkg/httputil/httputil.go
generated
vendored
Normal file
31
vendor/github.com/coreos/etcd/pkg/httputil/httputil.go
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// borrowed from golang/net/context/ctxhttp/cancelreq.go
|
||||
|
||||
// Package httputil provides HTTP utility functions.
|
||||
package httputil
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func RequestCanceler(req *http.Request) func() {
|
||||
ch := make(chan struct{})
|
||||
req.Cancel = ch
|
||||
|
||||
return func() {
|
||||
close(ch)
|
||||
}
|
||||
}
|
||||
|
||||
// GracefulClose drains http.Response.Body until it hits EOF
|
||||
// and closes it. This prevents TCP/TLS connections from closing,
|
||||
// therefore available for reuse.
|
||||
func GracefulClose(resp *http.Response) {
|
||||
io.Copy(ioutil.Discard, resp.Body)
|
||||
resp.Body.Close()
|
||||
}
|
||||
78
vendor/github.com/coreos/etcd/pkg/idutil/id.go
generated
vendored
Normal file
78
vendor/github.com/coreos/etcd/pkg/idutil/id.go
generated
vendored
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package idutil implements utility functions for generating unique,
|
||||
// randomized ids.
|
||||
package idutil
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
tsLen = 5 * 8
|
||||
cntLen = 8
|
||||
suffixLen = tsLen + cntLen
|
||||
)
|
||||
|
||||
// Generator generates unique identifiers based on counters, timestamps, and
|
||||
// a node member ID.
|
||||
//
|
||||
// The initial id is in this format:
|
||||
// High order byte is memberID, next 5 bytes are from timestamp,
|
||||
// and low order 2 bytes are 0s.
|
||||
// | prefix | suffix |
|
||||
// | 2 bytes | 5 bytes | 1 byte |
|
||||
// | memberID | timestamp | cnt |
|
||||
//
|
||||
// The timestamp 5 bytes is different when the machine is restart
|
||||
// after 1 ms and before 35 years.
|
||||
//
|
||||
// It increases suffix to generate the next id.
|
||||
// The count field may overflow to timestamp field, which is intentional.
|
||||
// It helps to extend the event window to 2^56. This doesn't break that
|
||||
// id generated after restart is unique because etcd throughput is <<
|
||||
// 256req/ms(250k reqs/second).
|
||||
type Generator struct {
|
||||
mu sync.Mutex
|
||||
// high order 2 bytes
|
||||
prefix uint64
|
||||
// low order 6 bytes
|
||||
suffix uint64
|
||||
}
|
||||
|
||||
func NewGenerator(memberID uint16, now time.Time) *Generator {
|
||||
prefix := uint64(memberID) << suffixLen
|
||||
unixMilli := uint64(now.UnixNano()) / uint64(time.Millisecond/time.Nanosecond)
|
||||
suffix := lowbit(unixMilli, tsLen) << cntLen
|
||||
return &Generator{
|
||||
prefix: prefix,
|
||||
suffix: suffix,
|
||||
}
|
||||
}
|
||||
|
||||
// Next generates a id that is unique.
|
||||
func (g *Generator) Next() uint64 {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
g.suffix++
|
||||
id := g.prefix | lowbit(g.suffix, suffixLen)
|
||||
return id
|
||||
}
|
||||
|
||||
func lowbit(x uint64, n uint) uint64 {
|
||||
return x & (math.MaxUint64 >> (64 - n))
|
||||
}
|
||||
55
vendor/github.com/coreos/etcd/pkg/idutil/id_test.go
generated
vendored
Normal file
55
vendor/github.com/coreos/etcd/pkg/idutil/id_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package idutil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNewGenerator(t *testing.T) {
|
||||
g := NewGenerator(0x12, time.Unix(0, 0).Add(0x3456*time.Millisecond))
|
||||
id := g.Next()
|
||||
wid := uint64(0x12000000345601)
|
||||
if id != wid {
|
||||
t.Errorf("id = %x, want %x", id, wid)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewGeneratorUnique(t *testing.T) {
|
||||
g := NewGenerator(0, time.Time{})
|
||||
id := g.Next()
|
||||
// different server generates different ID
|
||||
g1 := NewGenerator(1, time.Time{})
|
||||
if gid := g1.Next(); id == gid {
|
||||
t.Errorf("generate the same id %x using different server ID", id)
|
||||
}
|
||||
// restarted server generates different ID
|
||||
g2 := NewGenerator(0, time.Now())
|
||||
if gid := g2.Next(); id == gid {
|
||||
t.Errorf("generate the same id %x after restart", id)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNext(t *testing.T) {
|
||||
g := NewGenerator(0x12, time.Unix(0, 0).Add(0x3456*time.Millisecond))
|
||||
wid := uint64(0x12000000345601)
|
||||
for i := 0; i < 1000; i++ {
|
||||
id := g.Next()
|
||||
if id != wid+uint64(i) {
|
||||
t.Errorf("id = %x, want %x", id, wid+uint64(i))
|
||||
}
|
||||
}
|
||||
}
|
||||
106
vendor/github.com/coreos/etcd/pkg/ioutil/pagewriter.go
generated
vendored
Normal file
106
vendor/github.com/coreos/etcd/pkg/ioutil/pagewriter.go
generated
vendored
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ioutil
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
var defaultBufferBytes = 128 * 1024
|
||||
|
||||
// PageWriter implements the io.Writer interface so that writes will
|
||||
// either be in page chunks or from flushing.
|
||||
type PageWriter struct {
|
||||
w io.Writer
|
||||
// pageOffset tracks the page offset of the base of the buffer
|
||||
pageOffset int
|
||||
// pageBytes is the number of bytes per page
|
||||
pageBytes int
|
||||
// bufferedBytes counts the number of bytes pending for write in the buffer
|
||||
bufferedBytes int
|
||||
// buf holds the write buffer
|
||||
buf []byte
|
||||
// bufWatermarkBytes is the number of bytes the buffer can hold before it needs
|
||||
// to be flushed. It is less than len(buf) so there is space for slack writes
|
||||
// to bring the writer to page alignment.
|
||||
bufWatermarkBytes int
|
||||
}
|
||||
|
||||
// NewPageWriter creates a new PageWriter. pageBytes is the number of bytes
|
||||
// to write per page. pageOffset is the starting offset of io.Writer.
|
||||
func NewPageWriter(w io.Writer, pageBytes, pageOffset int) *PageWriter {
|
||||
return &PageWriter{
|
||||
w: w,
|
||||
pageOffset: pageOffset,
|
||||
pageBytes: pageBytes,
|
||||
buf: make([]byte, defaultBufferBytes+pageBytes),
|
||||
bufWatermarkBytes: defaultBufferBytes,
|
||||
}
|
||||
}
|
||||
|
||||
func (pw *PageWriter) Write(p []byte) (n int, err error) {
|
||||
if len(p)+pw.bufferedBytes <= pw.bufWatermarkBytes {
|
||||
// no overflow
|
||||
copy(pw.buf[pw.bufferedBytes:], p)
|
||||
pw.bufferedBytes += len(p)
|
||||
return len(p), nil
|
||||
}
|
||||
// complete the slack page in the buffer if unaligned
|
||||
slack := pw.pageBytes - ((pw.pageOffset + pw.bufferedBytes) % pw.pageBytes)
|
||||
if slack != pw.pageBytes {
|
||||
partial := slack > len(p)
|
||||
if partial {
|
||||
// not enough data to complete the slack page
|
||||
slack = len(p)
|
||||
}
|
||||
// special case: writing to slack page in buffer
|
||||
copy(pw.buf[pw.bufferedBytes:], p[:slack])
|
||||
pw.bufferedBytes += slack
|
||||
n = slack
|
||||
p = p[slack:]
|
||||
if partial {
|
||||
// avoid forcing an unaligned flush
|
||||
return n, nil
|
||||
}
|
||||
}
|
||||
// buffer contents are now page-aligned; clear out
|
||||
if err = pw.Flush(); err != nil {
|
||||
return n, err
|
||||
}
|
||||
// directly write all complete pages without copying
|
||||
if len(p) > pw.pageBytes {
|
||||
pages := len(p) / pw.pageBytes
|
||||
c, werr := pw.w.Write(p[:pages*pw.pageBytes])
|
||||
n += c
|
||||
if werr != nil {
|
||||
return n, werr
|
||||
}
|
||||
p = p[pages*pw.pageBytes:]
|
||||
}
|
||||
// write remaining tail to buffer
|
||||
c, werr := pw.Write(p)
|
||||
n += c
|
||||
return n, werr
|
||||
}
|
||||
|
||||
func (pw *PageWriter) Flush() error {
|
||||
if pw.bufferedBytes == 0 {
|
||||
return nil
|
||||
}
|
||||
_, err := pw.w.Write(pw.buf[:pw.bufferedBytes])
|
||||
pw.pageOffset = (pw.pageOffset + pw.bufferedBytes) % pw.pageBytes
|
||||
pw.bufferedBytes = 0
|
||||
return err
|
||||
}
|
||||
129
vendor/github.com/coreos/etcd/pkg/ioutil/pagewriter_test.go
generated
vendored
Normal file
129
vendor/github.com/coreos/etcd/pkg/ioutil/pagewriter_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ioutil
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPageWriterRandom(t *testing.T) {
|
||||
// smaller buffer for stress testing
|
||||
defaultBufferBytes = 8 * 1024
|
||||
pageBytes := 128
|
||||
buf := make([]byte, 4*defaultBufferBytes)
|
||||
cw := &checkPageWriter{pageBytes: pageBytes, t: t}
|
||||
w := NewPageWriter(cw, pageBytes, 0)
|
||||
n := 0
|
||||
for i := 0; i < 4096; i++ {
|
||||
c, err := w.Write(buf[:rand.Intn(len(buf))])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
n += c
|
||||
}
|
||||
if cw.writeBytes > n {
|
||||
t.Fatalf("wrote %d bytes to io.Writer, but only wrote %d bytes", cw.writeBytes, n)
|
||||
}
|
||||
if cw.writeBytes-n > pageBytes {
|
||||
t.Fatalf("got %d bytes pending, expected less than %d bytes", cw.writeBytes-n, pageBytes)
|
||||
}
|
||||
t.Logf("total writes: %d", cw.writes)
|
||||
t.Logf("total write bytes: %d (of %d)", cw.writeBytes, n)
|
||||
}
|
||||
|
||||
// TestPageWriterPariallack tests the case where a write overflows the buffer
|
||||
// but there is not enough data to complete the slack write.
|
||||
func TestPageWriterPartialSlack(t *testing.T) {
|
||||
defaultBufferBytes = 1024
|
||||
pageBytes := 128
|
||||
buf := make([]byte, defaultBufferBytes)
|
||||
cw := &checkPageWriter{pageBytes: 64, t: t}
|
||||
w := NewPageWriter(cw, pageBytes, 0)
|
||||
// put writer in non-zero page offset
|
||||
if _, err := w.Write(buf[:64]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := w.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if cw.writes != 1 {
|
||||
t.Fatalf("got %d writes, expected 1", cw.writes)
|
||||
}
|
||||
// nearly fill buffer
|
||||
if _, err := w.Write(buf[:1022]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// overflow buffer, but without enough to write as aligned
|
||||
if _, err := w.Write(buf[:8]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if cw.writes != 1 {
|
||||
t.Fatalf("got %d writes, expected 1", cw.writes)
|
||||
}
|
||||
// finish writing slack space
|
||||
if _, err := w.Write(buf[:128]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if cw.writes != 2 {
|
||||
t.Fatalf("got %d writes, expected 2", cw.writes)
|
||||
}
|
||||
}
|
||||
|
||||
// TestPageWriterOffset tests if page writer correctly repositions when offset is given.
|
||||
func TestPageWriterOffset(t *testing.T) {
|
||||
defaultBufferBytes = 1024
|
||||
pageBytes := 128
|
||||
buf := make([]byte, defaultBufferBytes)
|
||||
cw := &checkPageWriter{pageBytes: 64, t: t}
|
||||
w := NewPageWriter(cw, pageBytes, 0)
|
||||
if _, err := w.Write(buf[:64]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := w.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if w.pageOffset != 64 {
|
||||
t.Fatalf("w.pageOffset expected 64, got %d", w.pageOffset)
|
||||
}
|
||||
|
||||
w = NewPageWriter(cw, w.pageOffset, pageBytes)
|
||||
if _, err := w.Write(buf[:64]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := w.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if w.pageOffset != 0 {
|
||||
t.Fatalf("w.pageOffset expected 0, got %d", w.pageOffset)
|
||||
}
|
||||
}
|
||||
|
||||
// checkPageWriter implements an io.Writer that fails a test on unaligned writes.
|
||||
type checkPageWriter struct {
|
||||
pageBytes int
|
||||
writes int
|
||||
writeBytes int
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
func (cw *checkPageWriter) Write(p []byte) (int, error) {
|
||||
if len(p)%cw.pageBytes != 0 {
|
||||
cw.t.Fatalf("got write len(p) = %d, expected len(p) == k*cw.pageBytes", len(p))
|
||||
}
|
||||
cw.writes++
|
||||
cw.writeBytes += len(p)
|
||||
return len(p), nil
|
||||
}
|
||||
66
vendor/github.com/coreos/etcd/pkg/ioutil/readcloser.go
generated
vendored
Normal file
66
vendor/github.com/coreos/etcd/pkg/ioutil/readcloser.go
generated
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ioutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// ReaderAndCloser implements io.ReadCloser interface by combining
|
||||
// reader and closer together.
|
||||
type ReaderAndCloser struct {
|
||||
io.Reader
|
||||
io.Closer
|
||||
}
|
||||
|
||||
var (
|
||||
ErrShortRead = fmt.Errorf("ioutil: short read")
|
||||
ErrExpectEOF = fmt.Errorf("ioutil: expect EOF")
|
||||
)
|
||||
|
||||
// NewExactReadCloser returns a ReadCloser that returns errors if the underlying
|
||||
// reader does not read back exactly the requested number of bytes.
|
||||
func NewExactReadCloser(rc io.ReadCloser, totalBytes int64) io.ReadCloser {
|
||||
return &exactReadCloser{rc: rc, totalBytes: totalBytes}
|
||||
}
|
||||
|
||||
type exactReadCloser struct {
|
||||
rc io.ReadCloser
|
||||
br int64
|
||||
totalBytes int64
|
||||
}
|
||||
|
||||
func (e *exactReadCloser) Read(p []byte) (int, error) {
|
||||
n, err := e.rc.Read(p)
|
||||
e.br += int64(n)
|
||||
if e.br > e.totalBytes {
|
||||
return 0, ErrExpectEOF
|
||||
}
|
||||
if e.br < e.totalBytes && n == 0 {
|
||||
return 0, ErrShortRead
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (e *exactReadCloser) Close() error {
|
||||
if err := e.rc.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
if e.br < e.totalBytes {
|
||||
return ErrShortRead
|
||||
}
|
||||
return nil
|
||||
}
|
||||
46
vendor/github.com/coreos/etcd/pkg/ioutil/readcloser_test.go
generated
vendored
Normal file
46
vendor/github.com/coreos/etcd/pkg/ioutil/readcloser_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ioutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type readerNilCloser struct{ io.Reader }
|
||||
|
||||
func (rc *readerNilCloser) Close() error { return nil }
|
||||
|
||||
// TestExactReadCloserExpectEOF expects an eof when reading too much.
|
||||
func TestExactReadCloserExpectEOF(t *testing.T) {
|
||||
buf := bytes.NewBuffer(make([]byte, 10))
|
||||
rc := NewExactReadCloser(&readerNilCloser{buf}, 1)
|
||||
if _, err := rc.Read(make([]byte, 10)); err != ErrExpectEOF {
|
||||
t.Fatalf("expected %v, got %v", ErrExpectEOF, err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestExactReadCloserShort expects an eof when reading too little
|
||||
func TestExactReadCloserShort(t *testing.T) {
|
||||
buf := bytes.NewBuffer(make([]byte, 5))
|
||||
rc := NewExactReadCloser(&readerNilCloser{buf}, 10)
|
||||
if _, err := rc.Read(make([]byte, 10)); err != nil {
|
||||
t.Fatalf("Read expected nil err, got %v", err)
|
||||
}
|
||||
if err := rc.Close(); err != ErrShortRead {
|
||||
t.Fatalf("Close expected %v, got %v", ErrShortRead, err)
|
||||
}
|
||||
}
|
||||
40
vendor/github.com/coreos/etcd/pkg/ioutil/reader.go
generated
vendored
Normal file
40
vendor/github.com/coreos/etcd/pkg/ioutil/reader.go
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package ioutil implements I/O utility functions.
|
||||
package ioutil
|
||||
|
||||
import "io"
|
||||
|
||||
// NewLimitedBufferReader returns a reader that reads from the given reader
|
||||
// but limits the amount of data returned to at most n bytes.
|
||||
func NewLimitedBufferReader(r io.Reader, n int) io.Reader {
|
||||
return &limitedBufferReader{
|
||||
r: r,
|
||||
n: n,
|
||||
}
|
||||
}
|
||||
|
||||
type limitedBufferReader struct {
|
||||
r io.Reader
|
||||
n int
|
||||
}
|
||||
|
||||
func (r *limitedBufferReader) Read(p []byte) (n int, err error) {
|
||||
np := p
|
||||
if len(np) > r.n {
|
||||
np = np[:r.n]
|
||||
}
|
||||
return r.r.Read(np)
|
||||
}
|
||||
33
vendor/github.com/coreos/etcd/pkg/ioutil/reader_test.go
generated
vendored
Normal file
33
vendor/github.com/coreos/etcd/pkg/ioutil/reader_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ioutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLimitedBufferReaderRead(t *testing.T) {
|
||||
buf := bytes.NewBuffer(make([]byte, 10))
|
||||
ln := 1
|
||||
lr := NewLimitedBufferReader(buf, ln)
|
||||
n, err := lr.Read(make([]byte, 10))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected read error: %v", err)
|
||||
}
|
||||
if n != ln {
|
||||
t.Errorf("len(data read) = %d, want %d", n, ln)
|
||||
}
|
||||
}
|
||||
43
vendor/github.com/coreos/etcd/pkg/ioutil/util.go
generated
vendored
Normal file
43
vendor/github.com/coreos/etcd/pkg/ioutil/util.go
generated
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ioutil
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/coreos/etcd/pkg/fileutil"
|
||||
)
|
||||
|
||||
// WriteAndSyncFile behaves just like ioutil.WriteFile in the standard library,
|
||||
// but calls Sync before closing the file. WriteAndSyncFile guarantees the data
|
||||
// is synced if there is no error returned.
|
||||
func WriteAndSyncFile(filename string, data []byte, perm os.FileMode) error {
|
||||
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, err := f.Write(data)
|
||||
if err == nil && n < len(data) {
|
||||
err = io.ErrShortWrite
|
||||
}
|
||||
if err == nil {
|
||||
err = fileutil.Fsync(f)
|
||||
}
|
||||
if err1 := f.Close(); err == nil {
|
||||
err = err1
|
||||
}
|
||||
return err
|
||||
}
|
||||
195
vendor/github.com/coreos/etcd/pkg/logutil/merge_logger.go
generated
vendored
Normal file
195
vendor/github.com/coreos/etcd/pkg/logutil/merge_logger.go
generated
vendored
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package logutil includes utilities to facilitate logging.
|
||||
package logutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/pkg/capnslog"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultMergePeriod = time.Second
|
||||
defaultTimeOutputScale = 10 * time.Millisecond
|
||||
|
||||
outputInterval = time.Second
|
||||
)
|
||||
|
||||
// line represents a log line that can be printed out
|
||||
// through capnslog.PackageLogger.
|
||||
type line struct {
|
||||
level capnslog.LogLevel
|
||||
str string
|
||||
}
|
||||
|
||||
func (l line) append(s string) line {
|
||||
return line{
|
||||
level: l.level,
|
||||
str: l.str + " " + s,
|
||||
}
|
||||
}
|
||||
|
||||
// status represents the merge status of a line.
|
||||
type status struct {
|
||||
period time.Duration
|
||||
|
||||
start time.Time // start time of latest merge period
|
||||
count int // number of merged lines from starting
|
||||
}
|
||||
|
||||
func (s *status) isInMergePeriod(now time.Time) bool {
|
||||
return s.period == 0 || s.start.Add(s.period).After(now)
|
||||
}
|
||||
|
||||
func (s *status) isEmpty() bool { return s.count == 0 }
|
||||
|
||||
func (s *status) summary(now time.Time) string {
|
||||
ts := s.start.Round(defaultTimeOutputScale)
|
||||
took := now.Round(defaultTimeOutputScale).Sub(ts)
|
||||
return fmt.Sprintf("[merged %d repeated lines in %s]", s.count, took)
|
||||
}
|
||||
|
||||
func (s *status) reset(now time.Time) {
|
||||
s.start = now
|
||||
s.count = 0
|
||||
}
|
||||
|
||||
// MergeLogger supports merge logging, which merges repeated log lines
|
||||
// and prints summary log lines instead.
|
||||
//
|
||||
// For merge logging, MergeLogger prints out the line when the line appears
|
||||
// at the first time. MergeLogger holds the same log line printed within
|
||||
// defaultMergePeriod, and prints out summary log line at the end of defaultMergePeriod.
|
||||
// It stops merging when the line doesn't appear within the
|
||||
// defaultMergePeriod.
|
||||
type MergeLogger struct {
|
||||
*capnslog.PackageLogger
|
||||
|
||||
mu sync.Mutex // protect statusm
|
||||
statusm map[line]*status
|
||||
}
|
||||
|
||||
func NewMergeLogger(logger *capnslog.PackageLogger) *MergeLogger {
|
||||
l := &MergeLogger{
|
||||
PackageLogger: logger,
|
||||
statusm: make(map[line]*status),
|
||||
}
|
||||
go l.outputLoop()
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *MergeLogger) MergeInfo(entries ...interface{}) {
|
||||
l.merge(line{
|
||||
level: capnslog.INFO,
|
||||
str: fmt.Sprint(entries...),
|
||||
})
|
||||
}
|
||||
|
||||
func (l *MergeLogger) MergeInfof(format string, args ...interface{}) {
|
||||
l.merge(line{
|
||||
level: capnslog.INFO,
|
||||
str: fmt.Sprintf(format, args...),
|
||||
})
|
||||
}
|
||||
|
||||
func (l *MergeLogger) MergeNotice(entries ...interface{}) {
|
||||
l.merge(line{
|
||||
level: capnslog.NOTICE,
|
||||
str: fmt.Sprint(entries...),
|
||||
})
|
||||
}
|
||||
|
||||
func (l *MergeLogger) MergeNoticef(format string, args ...interface{}) {
|
||||
l.merge(line{
|
||||
level: capnslog.NOTICE,
|
||||
str: fmt.Sprintf(format, args...),
|
||||
})
|
||||
}
|
||||
|
||||
func (l *MergeLogger) MergeWarning(entries ...interface{}) {
|
||||
l.merge(line{
|
||||
level: capnslog.WARNING,
|
||||
str: fmt.Sprint(entries...),
|
||||
})
|
||||
}
|
||||
|
||||
func (l *MergeLogger) MergeWarningf(format string, args ...interface{}) {
|
||||
l.merge(line{
|
||||
level: capnslog.WARNING,
|
||||
str: fmt.Sprintf(format, args...),
|
||||
})
|
||||
}
|
||||
|
||||
func (l *MergeLogger) MergeError(entries ...interface{}) {
|
||||
l.merge(line{
|
||||
level: capnslog.ERROR,
|
||||
str: fmt.Sprint(entries...),
|
||||
})
|
||||
}
|
||||
|
||||
func (l *MergeLogger) MergeErrorf(format string, args ...interface{}) {
|
||||
l.merge(line{
|
||||
level: capnslog.ERROR,
|
||||
str: fmt.Sprintf(format, args...),
|
||||
})
|
||||
}
|
||||
|
||||
func (l *MergeLogger) merge(ln line) {
|
||||
l.mu.Lock()
|
||||
|
||||
// increase count if the logger is merging the line
|
||||
if status, ok := l.statusm[ln]; ok {
|
||||
status.count++
|
||||
l.mu.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// initialize status of the line
|
||||
l.statusm[ln] = &status{
|
||||
period: defaultMergePeriod,
|
||||
start: time.Now(),
|
||||
}
|
||||
// release the lock before IO operation
|
||||
l.mu.Unlock()
|
||||
// print out the line at its first time
|
||||
l.PackageLogger.Logf(ln.level, ln.str)
|
||||
}
|
||||
|
||||
func (l *MergeLogger) outputLoop() {
|
||||
for now := range time.Tick(outputInterval) {
|
||||
var outputs []line
|
||||
|
||||
l.mu.Lock()
|
||||
for ln, status := range l.statusm {
|
||||
if status.isInMergePeriod(now) {
|
||||
continue
|
||||
}
|
||||
if status.isEmpty() {
|
||||
delete(l.statusm, ln)
|
||||
continue
|
||||
}
|
||||
outputs = append(outputs, ln.append(status.summary(now)))
|
||||
status.reset(now)
|
||||
}
|
||||
l.mu.Unlock()
|
||||
|
||||
for _, o := range outputs {
|
||||
l.PackageLogger.Logf(o.level, o.str)
|
||||
}
|
||||
}
|
||||
}
|
||||
71
vendor/github.com/coreos/etcd/pkg/logutil/merge_logger_test.go
generated
vendored
Normal file
71
vendor/github.com/coreos/etcd/pkg/logutil/merge_logger_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package logutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/pkg/capnslog"
|
||||
)
|
||||
|
||||
var (
|
||||
testLogger = capnslog.NewPackageLogger("github.com/coreos/etcd", "pkg/logutil")
|
||||
)
|
||||
|
||||
func TestMergeLogger(t *testing.T) {
|
||||
var (
|
||||
txt = "hello"
|
||||
repeatN = 6
|
||||
duration = 2049843762 * time.Nanosecond
|
||||
mg = NewMergeLogger(testLogger)
|
||||
)
|
||||
// overwrite this for testing
|
||||
defaultMergePeriod = time.Minute
|
||||
|
||||
for i := 0; i < repeatN; i++ {
|
||||
mg.MergeError(txt)
|
||||
if i == 0 {
|
||||
time.Sleep(duration)
|
||||
}
|
||||
}
|
||||
|
||||
if len(mg.statusm) != 1 {
|
||||
t.Errorf("got = %d, want = %d", len(mg.statusm), 1)
|
||||
}
|
||||
|
||||
var l line
|
||||
for k := range mg.statusm {
|
||||
l = k
|
||||
break
|
||||
}
|
||||
|
||||
if l.level != capnslog.ERROR {
|
||||
t.Errorf("got = %v, want = %v", l.level, capnslog.DEBUG)
|
||||
}
|
||||
if l.str != txt {
|
||||
t.Errorf("got = %s, want = %s", l.str, txt)
|
||||
}
|
||||
if mg.statusm[l].count != repeatN-1 {
|
||||
t.Errorf("got = %d, want = %d", mg.statusm[l].count, repeatN-1)
|
||||
}
|
||||
sum := mg.statusm[l].summary(time.Now())
|
||||
pre := fmt.Sprintf("[merged %d repeated lines in ", repeatN-1)
|
||||
if !strings.HasPrefix(sum, pre) {
|
||||
t.Errorf("got = %s, want = %s...", sum, pre)
|
||||
}
|
||||
}
|
||||
16
vendor/github.com/coreos/etcd/pkg/mock/mockstorage/doc.go
generated
vendored
Normal file
16
vendor/github.com/coreos/etcd/pkg/mock/mockstorage/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package mockstorage provides mock implementations for etcdserver's storage interface.
|
||||
package mockstorage
|
||||
59
vendor/github.com/coreos/etcd/pkg/mock/mockstorage/storage_recorder.go
generated
vendored
Normal file
59
vendor/github.com/coreos/etcd/pkg/mock/mockstorage/storage_recorder.go
generated
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package mockstorage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/coreos/etcd/pkg/testutil"
|
||||
"github.com/coreos/etcd/raft"
|
||||
"github.com/coreos/etcd/raft/raftpb"
|
||||
)
|
||||
|
||||
type storageRecorder struct {
|
||||
testutil.Recorder
|
||||
dbPath string // must have '/' suffix if set
|
||||
}
|
||||
|
||||
func NewStorageRecorder(db string) *storageRecorder {
|
||||
return &storageRecorder{&testutil.RecorderBuffered{}, db}
|
||||
}
|
||||
|
||||
func NewStorageRecorderStream(db string) *storageRecorder {
|
||||
return &storageRecorder{testutil.NewRecorderStream(), db}
|
||||
}
|
||||
|
||||
func (p *storageRecorder) Save(st raftpb.HardState, ents []raftpb.Entry) error {
|
||||
p.Record(testutil.Action{Name: "Save"})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *storageRecorder) SaveSnap(st raftpb.Snapshot) error {
|
||||
if !raft.IsEmptySnap(st) {
|
||||
p.Record(testutil.Action{Name: "SaveSnap"})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *storageRecorder) DBFilePath(id uint64) (string, error) {
|
||||
p.Record(testutil.Action{Name: "DBFilePath"})
|
||||
path := p.dbPath
|
||||
if path != "" {
|
||||
path = path + "/"
|
||||
}
|
||||
return fmt.Sprintf("%s%016x.snap.db", path, id), nil
|
||||
}
|
||||
|
||||
func (p *storageRecorder) Close() error { return nil }
|
||||
16
vendor/github.com/coreos/etcd/pkg/mock/mockstore/doc.go
generated
vendored
Normal file
16
vendor/github.com/coreos/etcd/pkg/mock/mockstore/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package mockstore provides mock structures for the etcd store package.
|
||||
package mockstore
|
||||
157
vendor/github.com/coreos/etcd/pkg/mock/mockstore/store_recorder.go
generated
vendored
Normal file
157
vendor/github.com/coreos/etcd/pkg/mock/mockstore/store_recorder.go
generated
vendored
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package mockstore
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/pkg/testutil"
|
||||
"github.com/coreos/etcd/store"
|
||||
)
|
||||
|
||||
// StoreRecorder provides a Store interface with a testutil.Recorder
|
||||
type StoreRecorder struct {
|
||||
store.Store
|
||||
testutil.Recorder
|
||||
}
|
||||
|
||||
// storeRecorder records all the methods it receives.
|
||||
// storeRecorder DOES NOT work as a actual store.
|
||||
// It always returns invalid empty response and no error.
|
||||
type storeRecorder struct {
|
||||
store.Store
|
||||
testutil.Recorder
|
||||
}
|
||||
|
||||
func NewNop() store.Store { return &storeRecorder{Recorder: &testutil.RecorderBuffered{}} }
|
||||
func NewRecorder() *StoreRecorder {
|
||||
sr := &storeRecorder{Recorder: &testutil.RecorderBuffered{}}
|
||||
return &StoreRecorder{Store: sr, Recorder: sr.Recorder}
|
||||
}
|
||||
func NewRecorderStream() *StoreRecorder {
|
||||
sr := &storeRecorder{Recorder: testutil.NewRecorderStream()}
|
||||
return &StoreRecorder{Store: sr, Recorder: sr.Recorder}
|
||||
}
|
||||
|
||||
func (s *storeRecorder) Version() int { return 0 }
|
||||
func (s *storeRecorder) Index() uint64 { return 0 }
|
||||
func (s *storeRecorder) Get(path string, recursive, sorted bool) (*store.Event, error) {
|
||||
s.Record(testutil.Action{
|
||||
Name: "Get",
|
||||
Params: []interface{}{path, recursive, sorted},
|
||||
})
|
||||
return &store.Event{}, nil
|
||||
}
|
||||
func (s *storeRecorder) Set(path string, dir bool, val string, expireOpts store.TTLOptionSet) (*store.Event, error) {
|
||||
s.Record(testutil.Action{
|
||||
Name: "Set",
|
||||
Params: []interface{}{path, dir, val, expireOpts},
|
||||
})
|
||||
return &store.Event{}, nil
|
||||
}
|
||||
func (s *storeRecorder) Update(path, val string, expireOpts store.TTLOptionSet) (*store.Event, error) {
|
||||
s.Record(testutil.Action{
|
||||
Name: "Update",
|
||||
Params: []interface{}{path, val, expireOpts},
|
||||
})
|
||||
return &store.Event{}, nil
|
||||
}
|
||||
func (s *storeRecorder) Create(path string, dir bool, val string, uniq bool, expireOpts store.TTLOptionSet) (*store.Event, error) {
|
||||
s.Record(testutil.Action{
|
||||
Name: "Create",
|
||||
Params: []interface{}{path, dir, val, uniq, expireOpts},
|
||||
})
|
||||
return &store.Event{}, nil
|
||||
}
|
||||
func (s *storeRecorder) CompareAndSwap(path, prevVal string, prevIdx uint64, val string, expireOpts store.TTLOptionSet) (*store.Event, error) {
|
||||
s.Record(testutil.Action{
|
||||
Name: "CompareAndSwap",
|
||||
Params: []interface{}{path, prevVal, prevIdx, val, expireOpts},
|
||||
})
|
||||
return &store.Event{}, nil
|
||||
}
|
||||
func (s *storeRecorder) Delete(path string, dir, recursive bool) (*store.Event, error) {
|
||||
s.Record(testutil.Action{
|
||||
Name: "Delete",
|
||||
Params: []interface{}{path, dir, recursive},
|
||||
})
|
||||
return &store.Event{}, nil
|
||||
}
|
||||
func (s *storeRecorder) CompareAndDelete(path, prevVal string, prevIdx uint64) (*store.Event, error) {
|
||||
s.Record(testutil.Action{
|
||||
Name: "CompareAndDelete",
|
||||
Params: []interface{}{path, prevVal, prevIdx},
|
||||
})
|
||||
return &store.Event{}, nil
|
||||
}
|
||||
func (s *storeRecorder) Watch(_ string, _, _ bool, _ uint64) (store.Watcher, error) {
|
||||
s.Record(testutil.Action{Name: "Watch"})
|
||||
return store.NewNopWatcher(), nil
|
||||
}
|
||||
func (s *storeRecorder) Save() ([]byte, error) {
|
||||
s.Record(testutil.Action{Name: "Save"})
|
||||
return nil, nil
|
||||
}
|
||||
func (s *storeRecorder) Recovery(b []byte) error {
|
||||
s.Record(testutil.Action{Name: "Recovery"})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *storeRecorder) SaveNoCopy() ([]byte, error) {
|
||||
s.Record(testutil.Action{Name: "SaveNoCopy"})
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *storeRecorder) Clone() store.Store {
|
||||
s.Record(testutil.Action{Name: "Clone"})
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *storeRecorder) JsonStats() []byte { return nil }
|
||||
func (s *storeRecorder) DeleteExpiredKeys(cutoff time.Time) {
|
||||
s.Record(testutil.Action{
|
||||
Name: "DeleteExpiredKeys",
|
||||
Params: []interface{}{cutoff},
|
||||
})
|
||||
}
|
||||
|
||||
func (s *storeRecorder) HasTTLKeys() bool {
|
||||
s.Record(testutil.Action{
|
||||
Name: "HasTTLKeys",
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
// errStoreRecorder is a storeRecorder, but returns the given error on
|
||||
// Get, Watch methods.
|
||||
type errStoreRecorder struct {
|
||||
storeRecorder
|
||||
err error
|
||||
}
|
||||
|
||||
func NewErrRecorder(err error) *StoreRecorder {
|
||||
sr := &errStoreRecorder{err: err}
|
||||
sr.Recorder = &testutil.RecorderBuffered{}
|
||||
return &StoreRecorder{Store: sr, Recorder: sr.Recorder}
|
||||
}
|
||||
|
||||
func (s *errStoreRecorder) Get(path string, recursive, sorted bool) (*store.Event, error) {
|
||||
s.storeRecorder.Get(path, recursive, sorted)
|
||||
return nil, s.err
|
||||
}
|
||||
func (s *errStoreRecorder) Watch(path string, recursive, sorted bool, index uint64) (store.Watcher, error) {
|
||||
s.storeRecorder.Watch(path, recursive, sorted, index)
|
||||
return nil, s.err
|
||||
}
|
||||
16
vendor/github.com/coreos/etcd/pkg/mock/mockwait/doc.go
generated
vendored
Normal file
16
vendor/github.com/coreos/etcd/pkg/mock/mockwait/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package mockwait provides mock implementations for pkg/wait.
|
||||
package mockwait
|
||||
47
vendor/github.com/coreos/etcd/pkg/mock/mockwait/wait_recorder.go
generated
vendored
Normal file
47
vendor/github.com/coreos/etcd/pkg/mock/mockwait/wait_recorder.go
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package mockwait
|
||||
|
||||
import (
|
||||
"github.com/coreos/etcd/pkg/testutil"
|
||||
"github.com/coreos/etcd/pkg/wait"
|
||||
)
|
||||
|
||||
type WaitRecorder struct {
|
||||
wait.Wait
|
||||
testutil.Recorder
|
||||
}
|
||||
|
||||
type waitRecorder struct {
|
||||
testutil.RecorderBuffered
|
||||
}
|
||||
|
||||
func NewRecorder() *WaitRecorder {
|
||||
wr := &waitRecorder{}
|
||||
return &WaitRecorder{Wait: wr, Recorder: wr}
|
||||
}
|
||||
func NewNop() wait.Wait { return NewRecorder() }
|
||||
|
||||
func (w *waitRecorder) Register(id uint64) <-chan interface{} {
|
||||
w.Record(testutil.Action{Name: "Register"})
|
||||
return nil
|
||||
}
|
||||
func (w *waitRecorder) Trigger(id uint64, x interface{}) {
|
||||
w.Record(testutil.Action{Name: "Trigger"})
|
||||
}
|
||||
|
||||
func (w *waitRecorder) IsRegistered(id uint64) bool {
|
||||
panic("waitRecorder.IsRegistered() shouldn't be called")
|
||||
}
|
||||
6
vendor/github.com/coreos/etcd/pkg/monotime/issue15006.s
generated
vendored
Normal file
6
vendor/github.com/coreos/etcd/pkg/monotime/issue15006.s
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// Copyright (C) 2016 Arista Networks, Inc.
|
||||
// Use of this source code is governed by the Apache License 2.0
|
||||
// that can be found in the COPYING file.
|
||||
|
||||
// This file is intentionally empty.
|
||||
// It's a workaround for https://github.com/golang/go/issues/15006
|
||||
26
vendor/github.com/coreos/etcd/pkg/monotime/monotime.go
generated
vendored
Normal file
26
vendor/github.com/coreos/etcd/pkg/monotime/monotime.go
generated
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package monotime
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Time represents a point in monotonic time
|
||||
type Time uint64
|
||||
|
||||
func (t Time) Add(d time.Duration) Time {
|
||||
return Time(uint64(t) + uint64(d.Nanoseconds()))
|
||||
}
|
||||
24
vendor/github.com/coreos/etcd/pkg/monotime/nanotime.go
generated
vendored
Normal file
24
vendor/github.com/coreos/etcd/pkg/monotime/nanotime.go
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (C) 2016 Arista Networks, Inc.
|
||||
// Use of this source code is governed by the Apache License 2.0
|
||||
// that can be found in the COPYING file.
|
||||
|
||||
// Package monotime provides a fast monotonic clock source.
|
||||
package monotime
|
||||
|
||||
import (
|
||||
_ "unsafe" // required to use //go:linkname
|
||||
)
|
||||
|
||||
//go:noescape
|
||||
//go:linkname nanotime runtime.nanotime
|
||||
func nanotime() int64
|
||||
|
||||
// Now returns the current time in nanoseconds from a monotonic clock.
|
||||
// The time returned is based on some arbitrary platform-specific point in the
|
||||
// past. The time returned is guaranteed to increase monotonically at a
|
||||
// constant rate, unlike time.Now() from the Go standard library, which may
|
||||
// slow down, speed up, jump forward or backward, due to NTP activity or leap
|
||||
// seconds.
|
||||
func Now() Time {
|
||||
return Time(nanotime())
|
||||
}
|
||||
22
vendor/github.com/coreos/etcd/pkg/monotime/nanotime_test.go
generated
vendored
Normal file
22
vendor/github.com/coreos/etcd/pkg/monotime/nanotime_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (C) 2016 Arista Networks, Inc.
|
||||
// Use of this source code is governed by the Apache License 2.0
|
||||
|
||||
// Package monotime provides a fast monotonic clock source.
|
||||
|
||||
package monotime
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNow(t *testing.T) {
|
||||
for i := 0; i < 100; i++ {
|
||||
t1 := Now()
|
||||
t2 := Now()
|
||||
// I honestly thought that we needed >= here, but in some environments
|
||||
// two consecutive calls can return the same value!
|
||||
if t1 > t2 {
|
||||
t.Fatalf("t1=%d should have been less than or equal to t2=%d", t1, t2)
|
||||
}
|
||||
}
|
||||
}
|
||||
82
vendor/github.com/coreos/etcd/pkg/netutil/isolate_linux.go
generated
vendored
Normal file
82
vendor/github.com/coreos/etcd/pkg/netutil/isolate_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// DropPort drops all tcp packets that are received from the given port and sent to the given port.
|
||||
func DropPort(port int) error {
|
||||
cmdStr := fmt.Sprintf("sudo iptables -A OUTPUT -p tcp --destination-port %d -j DROP", port)
|
||||
if _, err := exec.Command("/bin/sh", "-c", cmdStr).Output(); err != nil {
|
||||
return err
|
||||
}
|
||||
cmdStr = fmt.Sprintf("sudo iptables -A INPUT -p tcp --destination-port %d -j DROP", port)
|
||||
_, err := exec.Command("/bin/sh", "-c", cmdStr).Output()
|
||||
return err
|
||||
}
|
||||
|
||||
// RecoverPort stops dropping tcp packets at given port.
|
||||
func RecoverPort(port int) error {
|
||||
cmdStr := fmt.Sprintf("sudo iptables -D OUTPUT -p tcp --destination-port %d -j DROP", port)
|
||||
if _, err := exec.Command("/bin/sh", "-c", cmdStr).Output(); err != nil {
|
||||
return err
|
||||
}
|
||||
cmdStr = fmt.Sprintf("sudo iptables -D INPUT -p tcp --destination-port %d -j DROP", port)
|
||||
_, err := exec.Command("/bin/sh", "-c", cmdStr).Output()
|
||||
return err
|
||||
}
|
||||
|
||||
// SetLatency adds latency in millisecond scale with random variations.
|
||||
func SetLatency(ms, rv int) error {
|
||||
ifces, err := GetDefaultInterfaces()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if rv > ms {
|
||||
rv = 1
|
||||
}
|
||||
for ifce := range ifces {
|
||||
cmdStr := fmt.Sprintf("sudo tc qdisc add dev %s root netem delay %dms %dms distribution normal", ifce, ms, rv)
|
||||
_, err = exec.Command("/bin/sh", "-c", cmdStr).Output()
|
||||
if err != nil {
|
||||
// the rule has already been added. Overwrite it.
|
||||
cmdStr = fmt.Sprintf("sudo tc qdisc change dev %s root netem delay %dms %dms distribution normal", ifce, ms, rv)
|
||||
_, err = exec.Command("/bin/sh", "-c", cmdStr).Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveLatency resets latency configurations.
|
||||
func RemoveLatency() error {
|
||||
ifces, err := GetDefaultInterfaces()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for ifce := range ifces {
|
||||
_, err = exec.Command("/bin/sh", "-c", fmt.Sprintf("sudo tc qdisc del dev %s root netem", ifce)).Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
25
vendor/github.com/coreos/etcd/pkg/netutil/isolate_stub.go
generated
vendored
Normal file
25
vendor/github.com/coreos/etcd/pkg/netutil/isolate_stub.go
generated
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !linux
|
||||
|
||||
package netutil
|
||||
|
||||
func DropPort(port int) error { return nil }
|
||||
|
||||
func RecoverPort(port int) error { return nil }
|
||||
|
||||
func SetLatency(ms, rv int) error { return nil }
|
||||
|
||||
func RemoveLatency() error { return nil }
|
||||
143
vendor/github.com/coreos/etcd/pkg/netutil/netutil.go
generated
vendored
Normal file
143
vendor/github.com/coreos/etcd/pkg/netutil/netutil.go
generated
vendored
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package netutil implements network-related utility functions.
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/coreos/etcd/pkg/types"
|
||||
"github.com/coreos/pkg/capnslog"
|
||||
)
|
||||
|
||||
var (
|
||||
plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "pkg/netutil")
|
||||
|
||||
// indirection for testing
|
||||
resolveTCPAddr = net.ResolveTCPAddr
|
||||
)
|
||||
|
||||
const retryInterval = time.Second
|
||||
|
||||
// resolveTCPAddrs is a convenience wrapper for net.ResolveTCPAddr.
|
||||
// resolveTCPAddrs return a new set of url.URLs, in which all DNS hostnames
|
||||
// are resolved.
|
||||
func resolveTCPAddrs(ctx context.Context, urls [][]url.URL) ([][]url.URL, error) {
|
||||
newurls := make([][]url.URL, 0)
|
||||
for _, us := range urls {
|
||||
nus := make([]url.URL, len(us))
|
||||
for i, u := range us {
|
||||
nu, err := url.Parse(u.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nus[i] = *nu
|
||||
}
|
||||
for i, u := range nus {
|
||||
h, err := resolveURL(ctx, u)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if h != "" {
|
||||
nus[i].Host = h
|
||||
}
|
||||
}
|
||||
newurls = append(newurls, nus)
|
||||
}
|
||||
return newurls, nil
|
||||
}
|
||||
|
||||
func resolveURL(ctx context.Context, u url.URL) (string, error) {
|
||||
for ctx.Err() == nil {
|
||||
host, _, err := net.SplitHostPort(u.Host)
|
||||
if err != nil {
|
||||
plog.Errorf("could not parse url %s during tcp resolving", u.Host)
|
||||
return "", err
|
||||
}
|
||||
if host == "localhost" || net.ParseIP(host) != nil {
|
||||
return "", nil
|
||||
}
|
||||
tcpAddr, err := resolveTCPAddr("tcp", u.Host)
|
||||
if err == nil {
|
||||
plog.Infof("resolving %s to %s", u.Host, tcpAddr.String())
|
||||
return tcpAddr.String(), nil
|
||||
}
|
||||
plog.Warningf("failed resolving host %s (%v); retrying in %v", u.Host, err, retryInterval)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
plog.Errorf("could not resolve host %s", u.Host)
|
||||
return "", err
|
||||
case <-time.After(retryInterval):
|
||||
}
|
||||
}
|
||||
return "", ctx.Err()
|
||||
}
|
||||
|
||||
// urlsEqual checks equality of url.URLS between two arrays.
|
||||
// This check pass even if an URL is in hostname and opposite is in IP address.
|
||||
func urlsEqual(ctx context.Context, a []url.URL, b []url.URL) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
urls, err := resolveTCPAddrs(ctx, [][]url.URL{a, b})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
a, b = urls[0], urls[1]
|
||||
sort.Sort(types.URLs(a))
|
||||
sort.Sort(types.URLs(b))
|
||||
for i := range a {
|
||||
if !reflect.DeepEqual(a[i], b[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func URLStringsEqual(ctx context.Context, a []string, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
urlsA := make([]url.URL, 0)
|
||||
for _, str := range a {
|
||||
u, err := url.Parse(str)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
urlsA = append(urlsA, *u)
|
||||
}
|
||||
urlsB := make([]url.URL, 0)
|
||||
for _, str := range b {
|
||||
u, err := url.Parse(str)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
urlsB = append(urlsB, *u)
|
||||
}
|
||||
|
||||
return urlsEqual(ctx, urlsA, urlsB)
|
||||
}
|
||||
|
||||
func IsNetworkTimeoutError(err error) bool {
|
||||
nerr, ok := err.(net.Error)
|
||||
return ok && nerr.Timeout()
|
||||
}
|
||||
263
vendor/github.com/coreos/etcd/pkg/netutil/netutil_test.go
generated
vendored
Normal file
263
vendor/github.com/coreos/etcd/pkg/netutil/netutil_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestResolveTCPAddrs(t *testing.T) {
|
||||
defer func() { resolveTCPAddr = net.ResolveTCPAddr }()
|
||||
tests := []struct {
|
||||
urls [][]url.URL
|
||||
expected [][]url.URL
|
||||
hostMap map[string]string
|
||||
hasError bool
|
||||
}{
|
||||
{
|
||||
urls: [][]url.URL{
|
||||
{
|
||||
{Scheme: "http", Host: "127.0.0.1:4001"},
|
||||
{Scheme: "http", Host: "127.0.0.1:2379"},
|
||||
},
|
||||
{
|
||||
{Scheme: "http", Host: "127.0.0.1:7001"},
|
||||
{Scheme: "http", Host: "127.0.0.1:2380"},
|
||||
},
|
||||
},
|
||||
expected: [][]url.URL{
|
||||
{
|
||||
{Scheme: "http", Host: "127.0.0.1:4001"},
|
||||
{Scheme: "http", Host: "127.0.0.1:2379"},
|
||||
},
|
||||
{
|
||||
{Scheme: "http", Host: "127.0.0.1:7001"},
|
||||
{Scheme: "http", Host: "127.0.0.1:2380"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
urls: [][]url.URL{
|
||||
{
|
||||
{Scheme: "http", Host: "infra0.example.com:4001"},
|
||||
{Scheme: "http", Host: "infra0.example.com:2379"},
|
||||
},
|
||||
{
|
||||
{Scheme: "http", Host: "infra0.example.com:7001"},
|
||||
{Scheme: "http", Host: "infra0.example.com:2380"},
|
||||
},
|
||||
},
|
||||
expected: [][]url.URL{
|
||||
{
|
||||
{Scheme: "http", Host: "10.0.1.10:4001"},
|
||||
{Scheme: "http", Host: "10.0.1.10:2379"},
|
||||
},
|
||||
{
|
||||
{Scheme: "http", Host: "10.0.1.10:7001"},
|
||||
{Scheme: "http", Host: "10.0.1.10:2380"},
|
||||
},
|
||||
},
|
||||
hostMap: map[string]string{
|
||||
"infra0.example.com": "10.0.1.10",
|
||||
},
|
||||
hasError: false,
|
||||
},
|
||||
{
|
||||
urls: [][]url.URL{
|
||||
{
|
||||
{Scheme: "http", Host: "infra0.example.com:4001"},
|
||||
{Scheme: "http", Host: "infra0.example.com:2379"},
|
||||
},
|
||||
{
|
||||
{Scheme: "http", Host: "infra0.example.com:7001"},
|
||||
{Scheme: "http", Host: "infra0.example.com:2380"},
|
||||
},
|
||||
},
|
||||
hostMap: map[string]string{
|
||||
"infra0.example.com": "",
|
||||
},
|
||||
hasError: true,
|
||||
},
|
||||
{
|
||||
urls: [][]url.URL{
|
||||
{
|
||||
{Scheme: "http", Host: "ssh://infra0.example.com:4001"},
|
||||
{Scheme: "http", Host: "ssh://infra0.example.com:2379"},
|
||||
},
|
||||
{
|
||||
{Scheme: "http", Host: "ssh://infra0.example.com:7001"},
|
||||
{Scheme: "http", Host: "ssh://infra0.example.com:2380"},
|
||||
},
|
||||
},
|
||||
hasError: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
resolveTCPAddr = func(network, addr string) (*net.TCPAddr, error) {
|
||||
host, port, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tt.hostMap[host] == "" {
|
||||
return nil, errors.New("cannot resolve host.")
|
||||
}
|
||||
i, err := strconv.Atoi(port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &net.TCPAddr{IP: net.ParseIP(tt.hostMap[host]), Port: i, Zone: ""}, nil
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
|
||||
urls, err := resolveTCPAddrs(ctx, tt.urls)
|
||||
cancel()
|
||||
if tt.hasError {
|
||||
if err == nil {
|
||||
t.Errorf("expected error")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(urls, tt.expected) {
|
||||
t.Errorf("expected: %v, got %v", tt.expected, urls)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestURLsEqual(t *testing.T) {
|
||||
defer func() { resolveTCPAddr = net.ResolveTCPAddr }()
|
||||
hostm := map[string]string{
|
||||
"example.com": "10.0.10.1",
|
||||
"first.com": "10.0.11.1",
|
||||
"second.com": "10.0.11.2",
|
||||
}
|
||||
resolveTCPAddr = func(network, addr string) (*net.TCPAddr, error) {
|
||||
host, port, err := net.SplitHostPort(addr)
|
||||
if _, ok := hostm[host]; !ok {
|
||||
return nil, errors.New("cannot resolve host.")
|
||||
}
|
||||
i, err := strconv.Atoi(port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &net.TCPAddr{IP: net.ParseIP(hostm[host]), Port: i, Zone: ""}, nil
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
a []url.URL
|
||||
b []url.URL
|
||||
expect bool
|
||||
}{
|
||||
{
|
||||
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
|
||||
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}},
|
||||
b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||
b: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
a: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||
b: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
|
||||
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
a: []url.URL{{Scheme: "http", Host: "example.com:2380"}},
|
||||
b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
|
||||
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}},
|
||||
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
a: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
|
||||
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||
expect: false,
|
||||
},
|
||||
{
|
||||
a: []url.URL{{Scheme: "http", Host: "first.com:2379"}, {Scheme: "http", Host: "second.com:2380"}},
|
||||
b: []url.URL{{Scheme: "http", Host: "10.0.11.1:2379"}, {Scheme: "http", Host: "10.0.11.2:2380"}},
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
a: []url.URL{{Scheme: "http", Host: "second.com:2380"}, {Scheme: "http", Host: "first.com:2379"}},
|
||||
b: []url.URL{{Scheme: "http", Host: "10.0.11.1:2379"}, {Scheme: "http", Host: "10.0.11.2:2380"}},
|
||||
expect: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
result := urlsEqual(context.TODO(), test.a, test.b)
|
||||
if result != test.expect {
|
||||
t.Errorf("a:%v b:%v, expected %v but %v", test.a, test.b, test.expect, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestURLStringsEqual(t *testing.T) {
|
||||
result := URLStringsEqual(context.TODO(), []string{"http://127.0.0.1:8080"}, []string{"http://127.0.0.1:8080"})
|
||||
if !result {
|
||||
t.Errorf("unexpected result %v", result)
|
||||
}
|
||||
}
|
||||
33
vendor/github.com/coreos/etcd/pkg/netutil/routes.go
generated
vendored
Normal file
33
vendor/github.com/coreos/etcd/pkg/netutil/routes.go
generated
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !linux
|
||||
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// GetDefaultHost fetches the a resolvable name that corresponds
|
||||
// to the machine's default routable interface
|
||||
func GetDefaultHost() (string, error) {
|
||||
return "", fmt.Errorf("default host not supported on %s_%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
// GetDefaultInterfaces fetches the device name of default routable interface.
|
||||
func GetDefaultInterfaces() (map[string]uint8, error) {
|
||||
return nil, fmt.Errorf("default host not supported on %s_%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
250
vendor/github.com/coreos/etcd/pkg/netutil/routes_linux.go
generated
vendored
Normal file
250
vendor/github.com/coreos/etcd/pkg/netutil/routes_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build linux
|
||||
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"sort"
|
||||
"syscall"
|
||||
|
||||
"github.com/coreos/etcd/pkg/cpuutil"
|
||||
)
|
||||
|
||||
var errNoDefaultRoute = fmt.Errorf("could not find default route")
|
||||
var errNoDefaultHost = fmt.Errorf("could not find default host")
|
||||
var errNoDefaultInterface = fmt.Errorf("could not find default interface")
|
||||
|
||||
// GetDefaultHost obtains the first IP address of machine from the routing table and returns the IP address as string.
|
||||
// An IPv4 address is preferred to an IPv6 address for backward compatibility.
|
||||
func GetDefaultHost() (string, error) {
|
||||
rmsgs, rerr := getDefaultRoutes()
|
||||
if rerr != nil {
|
||||
return "", rerr
|
||||
}
|
||||
|
||||
// prioritize IPv4
|
||||
if rmsg, ok := rmsgs[syscall.AF_INET]; ok {
|
||||
if host, err := chooseHost(syscall.AF_INET, rmsg); host != "" || err != nil {
|
||||
return host, err
|
||||
}
|
||||
delete(rmsgs, syscall.AF_INET)
|
||||
}
|
||||
|
||||
// sort so choice is deterministic
|
||||
var families []int
|
||||
for family := range rmsgs {
|
||||
families = append(families, int(family))
|
||||
}
|
||||
sort.Ints(families)
|
||||
|
||||
for _, f := range families {
|
||||
family := uint8(f)
|
||||
if host, err := chooseHost(family, rmsgs[family]); host != "" || err != nil {
|
||||
return host, err
|
||||
}
|
||||
}
|
||||
|
||||
return "", errNoDefaultHost
|
||||
}
|
||||
|
||||
func chooseHost(family uint8, rmsg *syscall.NetlinkMessage) (string, error) {
|
||||
host, oif, err := parsePREFSRC(rmsg)
|
||||
if host != "" || err != nil {
|
||||
return host, err
|
||||
}
|
||||
|
||||
// prefsrc not detected, fall back to getting address from iface
|
||||
ifmsg, ierr := getIfaceAddr(oif, family)
|
||||
if ierr != nil {
|
||||
return "", ierr
|
||||
}
|
||||
|
||||
attrs, aerr := syscall.ParseNetlinkRouteAttr(ifmsg)
|
||||
if aerr != nil {
|
||||
return "", aerr
|
||||
}
|
||||
|
||||
for _, attr := range attrs {
|
||||
// search for RTA_DST because ipv6 doesn't have RTA_SRC
|
||||
if attr.Attr.Type == syscall.RTA_DST {
|
||||
return net.IP(attr.Value).String(), nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func getDefaultRoutes() (map[uint8]*syscall.NetlinkMessage, error) {
|
||||
dat, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_UNSPEC)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgs, msgErr := syscall.ParseNetlinkMessage(dat)
|
||||
if msgErr != nil {
|
||||
return nil, msgErr
|
||||
}
|
||||
|
||||
routes := make(map[uint8]*syscall.NetlinkMessage)
|
||||
rtmsg := syscall.RtMsg{}
|
||||
for _, m := range msgs {
|
||||
if m.Header.Type != syscall.RTM_NEWROUTE {
|
||||
continue
|
||||
}
|
||||
buf := bytes.NewBuffer(m.Data[:syscall.SizeofRtMsg])
|
||||
if rerr := binary.Read(buf, cpuutil.ByteOrder(), &rtmsg); rerr != nil {
|
||||
continue
|
||||
}
|
||||
if rtmsg.Dst_len == 0 && rtmsg.Table == syscall.RT_TABLE_MAIN {
|
||||
// zero-length Dst_len implies default route
|
||||
msg := m
|
||||
routes[rtmsg.Family] = &msg
|
||||
}
|
||||
}
|
||||
|
||||
if len(routes) > 0 {
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
return nil, errNoDefaultRoute
|
||||
}
|
||||
|
||||
// Used to get an address of interface.
|
||||
func getIfaceAddr(idx uint32, family uint8) (*syscall.NetlinkMessage, error) {
|
||||
dat, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, int(family))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgs, msgErr := syscall.ParseNetlinkMessage(dat)
|
||||
if msgErr != nil {
|
||||
return nil, msgErr
|
||||
}
|
||||
|
||||
ifaddrmsg := syscall.IfAddrmsg{}
|
||||
for _, m := range msgs {
|
||||
if m.Header.Type != syscall.RTM_NEWADDR {
|
||||
continue
|
||||
}
|
||||
buf := bytes.NewBuffer(m.Data[:syscall.SizeofIfAddrmsg])
|
||||
if rerr := binary.Read(buf, cpuutil.ByteOrder(), &ifaddrmsg); rerr != nil {
|
||||
continue
|
||||
}
|
||||
if ifaddrmsg.Index == idx {
|
||||
return &m, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("could not find address for interface index %v", idx)
|
||||
|
||||
}
|
||||
|
||||
// Used to get a name of interface.
|
||||
func getIfaceLink(idx uint32) (*syscall.NetlinkMessage, error) {
|
||||
dat, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msgs, msgErr := syscall.ParseNetlinkMessage(dat)
|
||||
if msgErr != nil {
|
||||
return nil, msgErr
|
||||
}
|
||||
|
||||
ifinfomsg := syscall.IfInfomsg{}
|
||||
for _, m := range msgs {
|
||||
if m.Header.Type != syscall.RTM_NEWLINK {
|
||||
continue
|
||||
}
|
||||
buf := bytes.NewBuffer(m.Data[:syscall.SizeofIfInfomsg])
|
||||
if rerr := binary.Read(buf, cpuutil.ByteOrder(), &ifinfomsg); rerr != nil {
|
||||
continue
|
||||
}
|
||||
if ifinfomsg.Index == int32(idx) {
|
||||
return &m, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("could not find link for interface index %v", idx)
|
||||
}
|
||||
|
||||
// GetDefaultInterfaces gets names of interfaces and returns a map[interface]families.
|
||||
func GetDefaultInterfaces() (map[string]uint8, error) {
|
||||
interfaces := make(map[string]uint8)
|
||||
rmsgs, rerr := getDefaultRoutes()
|
||||
if rerr != nil {
|
||||
return interfaces, rerr
|
||||
}
|
||||
|
||||
for family, rmsg := range rmsgs {
|
||||
_, oif, err := parsePREFSRC(rmsg)
|
||||
if err != nil {
|
||||
return interfaces, err
|
||||
}
|
||||
|
||||
ifmsg, ierr := getIfaceLink(oif)
|
||||
if ierr != nil {
|
||||
return interfaces, ierr
|
||||
}
|
||||
|
||||
attrs, aerr := syscall.ParseNetlinkRouteAttr(ifmsg)
|
||||
if aerr != nil {
|
||||
return interfaces, aerr
|
||||
}
|
||||
|
||||
for _, attr := range attrs {
|
||||
if attr.Attr.Type == syscall.IFLA_IFNAME {
|
||||
// key is an interface name
|
||||
// possible values: 2 - AF_INET, 10 - AF_INET6, 12 - dualstack
|
||||
interfaces[string(attr.Value[:len(attr.Value)-1])] += family
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(interfaces) > 0 {
|
||||
return interfaces, nil
|
||||
}
|
||||
return interfaces, errNoDefaultInterface
|
||||
}
|
||||
|
||||
// parsePREFSRC returns preferred source address and output interface index (RTA_OIF).
|
||||
func parsePREFSRC(m *syscall.NetlinkMessage) (host string, oif uint32, err error) {
|
||||
var attrs []syscall.NetlinkRouteAttr
|
||||
attrs, err = syscall.ParseNetlinkRouteAttr(m)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
|
||||
for _, attr := range attrs {
|
||||
if attr.Attr.Type == syscall.RTA_PREFSRC {
|
||||
host = net.IP(attr.Value).String()
|
||||
}
|
||||
if attr.Attr.Type == syscall.RTA_OIF {
|
||||
oif = cpuutil.ByteOrder().Uint32(attr.Value)
|
||||
}
|
||||
if host != "" && oif != uint32(0) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if oif == 0 {
|
||||
err = errNoDefaultRoute
|
||||
}
|
||||
return
|
||||
}
|
||||
35
vendor/github.com/coreos/etcd/pkg/netutil/routes_linux_test.go
generated
vendored
Normal file
35
vendor/github.com/coreos/etcd/pkg/netutil/routes_linux_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build linux
|
||||
|
||||
package netutil
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestGetDefaultInterface(t *testing.T) {
|
||||
ifc, err := GetDefaultInterfaces()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("default network interfaces: %+v\n", ifc)
|
||||
}
|
||||
|
||||
func TestGetDefaultHost(t *testing.T) {
|
||||
ip, err := GetDefaultHost()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("default ip: %v", ip)
|
||||
}
|
||||
79
vendor/github.com/coreos/etcd/pkg/osutil/interrupt_unix.go
generated
vendored
Normal file
79
vendor/github.com/coreos/etcd/pkg/osutil/interrupt_unix.go
generated
vendored
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !windows,!plan9
|
||||
|
||||
package osutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// InterruptHandler is a function that is called on receiving a
|
||||
// SIGTERM or SIGINT signal.
|
||||
type InterruptHandler func()
|
||||
|
||||
var (
|
||||
interruptRegisterMu, interruptExitMu sync.Mutex
|
||||
// interruptHandlers holds all registered InterruptHandlers in order
|
||||
// they will be executed.
|
||||
interruptHandlers = []InterruptHandler{}
|
||||
)
|
||||
|
||||
// RegisterInterruptHandler registers a new InterruptHandler. Handlers registered
|
||||
// after interrupt handing was initiated will not be executed.
|
||||
func RegisterInterruptHandler(h InterruptHandler) {
|
||||
interruptRegisterMu.Lock()
|
||||
defer interruptRegisterMu.Unlock()
|
||||
interruptHandlers = append(interruptHandlers, h)
|
||||
}
|
||||
|
||||
// HandleInterrupts calls the handler functions on receiving a SIGINT or SIGTERM.
|
||||
func HandleInterrupts() {
|
||||
notifier := make(chan os.Signal, 1)
|
||||
signal.Notify(notifier, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
go func() {
|
||||
sig := <-notifier
|
||||
|
||||
interruptRegisterMu.Lock()
|
||||
ihs := make([]InterruptHandler, len(interruptHandlers))
|
||||
copy(ihs, interruptHandlers)
|
||||
interruptRegisterMu.Unlock()
|
||||
|
||||
interruptExitMu.Lock()
|
||||
|
||||
plog.Noticef("received %v signal, shutting down...", sig)
|
||||
|
||||
for _, h := range ihs {
|
||||
h()
|
||||
}
|
||||
signal.Stop(notifier)
|
||||
pid := syscall.Getpid()
|
||||
// exit directly if it is the "init" process, since the kernel will not help to kill pid 1.
|
||||
if pid == 1 {
|
||||
os.Exit(0)
|
||||
}
|
||||
syscall.Kill(pid, sig.(syscall.Signal))
|
||||
}()
|
||||
}
|
||||
|
||||
// Exit relays to os.Exit if no interrupt handlers are running, blocks otherwise.
|
||||
func Exit(code int) {
|
||||
interruptExitMu.Lock()
|
||||
os.Exit(code)
|
||||
}
|
||||
32
vendor/github.com/coreos/etcd/pkg/osutil/interrupt_windows.go
generated
vendored
Normal file
32
vendor/github.com/coreos/etcd/pkg/osutil/interrupt_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build windows
|
||||
|
||||
package osutil
|
||||
|
||||
import "os"
|
||||
|
||||
type InterruptHandler func()
|
||||
|
||||
// RegisterInterruptHandler is a no-op on windows
|
||||
func RegisterInterruptHandler(h InterruptHandler) {}
|
||||
|
||||
// HandleInterrupts is a no-op on windows
|
||||
func HandleInterrupts() {}
|
||||
|
||||
// Exit calls os.Exit
|
||||
func Exit(code int) {
|
||||
os.Exit(code)
|
||||
}
|
||||
42
vendor/github.com/coreos/etcd/pkg/osutil/osutil.go
generated
vendored
Normal file
42
vendor/github.com/coreos/etcd/pkg/osutil/osutil.go
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package osutil implements operating system-related utility functions.
|
||||
package osutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/coreos/pkg/capnslog"
|
||||
)
|
||||
|
||||
var (
|
||||
plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "pkg/osutil")
|
||||
)
|
||||
|
||||
func Unsetenv(key string) error {
|
||||
envs := os.Environ()
|
||||
os.Clearenv()
|
||||
for _, e := range envs {
|
||||
strs := strings.SplitN(e, "=", 2)
|
||||
if strs[0] == key {
|
||||
continue
|
||||
}
|
||||
if err := os.Setenv(strs[0], strs[1]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
88
vendor/github.com/coreos/etcd/pkg/osutil/osutil_test.go
generated
vendored
Normal file
88
vendor/github.com/coreos/etcd/pkg/osutil/osutil_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package osutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"reflect"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestUnsetenv(t *testing.T) {
|
||||
tests := []string{
|
||||
"data",
|
||||
"space data",
|
||||
"equal=data",
|
||||
}
|
||||
for i, tt := range tests {
|
||||
key := "ETCD_UNSETENV_TEST"
|
||||
if os.Getenv(key) != "" {
|
||||
t.Fatalf("#%d: cannot get empty %s", i, key)
|
||||
}
|
||||
env := os.Environ()
|
||||
if err := os.Setenv(key, tt); err != nil {
|
||||
t.Fatalf("#%d: cannot set %s: %v", i, key, err)
|
||||
}
|
||||
if err := Unsetenv(key); err != nil {
|
||||
t.Errorf("#%d: unsetenv %s error: %v", i, key, err)
|
||||
}
|
||||
if g := os.Environ(); !reflect.DeepEqual(g, env) {
|
||||
t.Errorf("#%d: env = %+v, want %+v", i, g, env)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
|
||||
select {
|
||||
case s := <-c:
|
||||
if s != sig {
|
||||
t.Fatalf("signal was %v, want %v", s, sig)
|
||||
}
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatalf("timeout waiting for %v", sig)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleInterrupts(t *testing.T) {
|
||||
for _, sig := range []syscall.Signal{syscall.SIGINT, syscall.SIGTERM} {
|
||||
n := 1
|
||||
RegisterInterruptHandler(func() { n++ })
|
||||
RegisterInterruptHandler(func() { n *= 2 })
|
||||
|
||||
c := make(chan os.Signal, 2)
|
||||
signal.Notify(c, sig)
|
||||
|
||||
HandleInterrupts()
|
||||
syscall.Kill(syscall.Getpid(), sig)
|
||||
|
||||
// we should receive the signal once from our own kill and
|
||||
// a second time from HandleInterrupts
|
||||
waitSig(t, c, sig)
|
||||
waitSig(t, c, sig)
|
||||
|
||||
if n == 3 {
|
||||
t.Fatalf("interrupt handlers were called in wrong order")
|
||||
}
|
||||
if n != 4 {
|
||||
t.Fatalf("interrupt handlers were not called properly")
|
||||
}
|
||||
// reset interrupt handlers
|
||||
interruptHandlers = interruptHandlers[:0]
|
||||
interruptExitMu.Unlock()
|
||||
}
|
||||
}
|
||||
31
vendor/github.com/coreos/etcd/pkg/pathutil/path.go
generated
vendored
Normal file
31
vendor/github.com/coreos/etcd/pkg/pathutil/path.go
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2009 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 pathutil implements utility functions for handling slash-separated
|
||||
// paths.
|
||||
package pathutil
|
||||
|
||||
import "path"
|
||||
|
||||
// CanonicalURLPath returns the canonical url path for p, which follows the rules:
|
||||
// 1. the path always starts with "/"
|
||||
// 2. replace multiple slashes with a single slash
|
||||
// 3. replace each '.' '..' path name element with equivalent one
|
||||
// 4. keep the trailing slash
|
||||
// The function is borrowed from stdlib http.cleanPath in server.go.
|
||||
func CanonicalURLPath(p string) string {
|
||||
if p == "" {
|
||||
return "/"
|
||||
}
|
||||
if p[0] != '/' {
|
||||
p = "/" + p
|
||||
}
|
||||
np := path.Clean(p)
|
||||
// path.Clean removes trailing slash except for root,
|
||||
// put the trailing slash back if necessary.
|
||||
if p[len(p)-1] == '/' && np != "/" {
|
||||
np += "/"
|
||||
}
|
||||
return np
|
||||
}
|
||||
38
vendor/github.com/coreos/etcd/pkg/pathutil/path_test.go
generated
vendored
Normal file
38
vendor/github.com/coreos/etcd/pkg/pathutil/path_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package pathutil
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCanonicalURLPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
p string
|
||||
wp string
|
||||
}{
|
||||
{"/a", "/a"},
|
||||
{"", "/"},
|
||||
{"a", "/a"},
|
||||
{"//a", "/a"},
|
||||
{"/a/.", "/a"},
|
||||
{"/a/..", "/"},
|
||||
{"/a/", "/a/"},
|
||||
{"/a//", "/a/"},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
if g := CanonicalURLPath(tt.p); g != tt.wp {
|
||||
t.Errorf("#%d: canonical path = %s, want %s", i, g, tt.wp)
|
||||
}
|
||||
}
|
||||
}
|
||||
60
vendor/github.com/coreos/etcd/pkg/pbutil/pbutil.go
generated
vendored
Normal file
60
vendor/github.com/coreos/etcd/pkg/pbutil/pbutil.go
generated
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package pbutil defines interfaces for handling Protocol Buffer objects.
|
||||
package pbutil
|
||||
|
||||
import "github.com/coreos/pkg/capnslog"
|
||||
|
||||
var (
|
||||
plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "pkg/pbutil")
|
||||
)
|
||||
|
||||
type Marshaler interface {
|
||||
Marshal() (data []byte, err error)
|
||||
}
|
||||
|
||||
type Unmarshaler interface {
|
||||
Unmarshal(data []byte) error
|
||||
}
|
||||
|
||||
func MustMarshal(m Marshaler) []byte {
|
||||
d, err := m.Marshal()
|
||||
if err != nil {
|
||||
plog.Panicf("marshal should never fail (%v)", err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func MustUnmarshal(um Unmarshaler, data []byte) {
|
||||
if err := um.Unmarshal(data); err != nil {
|
||||
plog.Panicf("unmarshal should never fail (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func MaybeUnmarshal(um Unmarshaler, data []byte) bool {
|
||||
if err := um.Unmarshal(data); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func GetBool(v *bool) (vv bool, set bool) {
|
||||
if v == nil {
|
||||
return false, false
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
func Boolp(b bool) *bool { return &b }
|
||||
98
vendor/github.com/coreos/etcd/pkg/pbutil/pbutil_test.go
generated
vendored
Normal file
98
vendor/github.com/coreos/etcd/pkg/pbutil/pbutil_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package pbutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMarshaler(t *testing.T) {
|
||||
data := []byte("test data")
|
||||
m := &fakeMarshaler{data: data}
|
||||
if g := MustMarshal(m); !reflect.DeepEqual(g, data) {
|
||||
t.Errorf("data = %s, want %s", g, m)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalerPanic(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Errorf("recover = nil, want error")
|
||||
}
|
||||
}()
|
||||
m := &fakeMarshaler{err: errors.New("blah")}
|
||||
MustMarshal(m)
|
||||
}
|
||||
|
||||
func TestUnmarshaler(t *testing.T) {
|
||||
data := []byte("test data")
|
||||
m := &fakeUnmarshaler{}
|
||||
MustUnmarshal(m, data)
|
||||
if !reflect.DeepEqual(m.data, data) {
|
||||
t.Errorf("data = %s, want %s", m.data, m)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalerPanic(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Errorf("recover = nil, want error")
|
||||
}
|
||||
}()
|
||||
m := &fakeUnmarshaler{err: errors.New("blah")}
|
||||
MustUnmarshal(m, nil)
|
||||
}
|
||||
|
||||
func TestGetBool(t *testing.T) {
|
||||
tests := []struct {
|
||||
b *bool
|
||||
wb bool
|
||||
wset bool
|
||||
}{
|
||||
{nil, false, false},
|
||||
{Boolp(true), true, true},
|
||||
{Boolp(false), false, true},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
b, set := GetBool(tt.b)
|
||||
if b != tt.wb {
|
||||
t.Errorf("#%d: value = %v, want %v", i, b, tt.wb)
|
||||
}
|
||||
if set != tt.wset {
|
||||
t.Errorf("#%d: set = %v, want %v", i, set, tt.wset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type fakeMarshaler struct {
|
||||
data []byte
|
||||
err error
|
||||
}
|
||||
|
||||
func (m *fakeMarshaler) Marshal() ([]byte, error) {
|
||||
return m.data, m.err
|
||||
}
|
||||
|
||||
type fakeUnmarshaler struct {
|
||||
data []byte
|
||||
err error
|
||||
}
|
||||
|
||||
func (m *fakeUnmarshaler) Unmarshal(data []byte) error {
|
||||
m.data = data
|
||||
return m.err
|
||||
}
|
||||
16
vendor/github.com/coreos/etcd/pkg/report/doc.go
generated
vendored
Normal file
16
vendor/github.com/coreos/etcd/pkg/report/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package report generates human-readable benchmark reports.
|
||||
package report
|
||||
288
vendor/github.com/coreos/etcd/pkg/report/report.go
generated
vendored
Normal file
288
vendor/github.com/coreos/etcd/pkg/report/report.go
generated
vendored
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
// Copyright 2014 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// the file is borrowed from github.com/rakyll/boom/boomer/print.go
|
||||
|
||||
package report
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
barChar = "∎"
|
||||
)
|
||||
|
||||
// Result describes the timings for an operation.
|
||||
type Result struct {
|
||||
Start time.Time
|
||||
End time.Time
|
||||
Err error
|
||||
}
|
||||
|
||||
func (res *Result) Duration() time.Duration { return res.End.Sub(res.Start) }
|
||||
|
||||
type report struct {
|
||||
results chan Result
|
||||
precision string
|
||||
|
||||
avgTotal float64
|
||||
fastest float64
|
||||
slowest float64
|
||||
average float64
|
||||
stddev float64
|
||||
rps float64
|
||||
total time.Duration
|
||||
|
||||
errorDist map[string]int
|
||||
lats []float64
|
||||
|
||||
sps *secondPoints
|
||||
}
|
||||
|
||||
// Stats exposes results raw data.
|
||||
type Stats struct {
|
||||
AvgTotal float64
|
||||
Fastest float64
|
||||
Slowest float64
|
||||
Average float64
|
||||
Stddev float64
|
||||
RPS float64
|
||||
Total time.Duration
|
||||
ErrorDist map[string]int
|
||||
Lats []float64
|
||||
TimeSeries TimeSeries
|
||||
}
|
||||
|
||||
// Report processes a result stream until it is closed, then produces a
|
||||
// string with information about the consumed result data.
|
||||
type Report interface {
|
||||
Results() chan<- Result
|
||||
|
||||
// Run returns results in print-friendly format.
|
||||
Run() <-chan string
|
||||
|
||||
// Stats returns results in raw data.
|
||||
Stats() <-chan Stats
|
||||
}
|
||||
|
||||
func NewReport(precision string) Report {
|
||||
return &report{
|
||||
results: make(chan Result, 16),
|
||||
precision: precision,
|
||||
errorDist: make(map[string]int),
|
||||
}
|
||||
}
|
||||
|
||||
func NewReportSample(precision string) Report {
|
||||
r := NewReport(precision).(*report)
|
||||
r.sps = newSecondPoints()
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *report) Results() chan<- Result { return r.results }
|
||||
|
||||
func (r *report) Run() <-chan string {
|
||||
donec := make(chan string, 1)
|
||||
go func() {
|
||||
defer close(donec)
|
||||
r.processResults()
|
||||
donec <- r.String()
|
||||
}()
|
||||
return donec
|
||||
}
|
||||
|
||||
func (r *report) Stats() <-chan Stats {
|
||||
donec := make(chan Stats, 1)
|
||||
go func() {
|
||||
defer close(donec)
|
||||
r.processResults()
|
||||
var ts TimeSeries
|
||||
if r.sps != nil {
|
||||
ts = r.sps.getTimeSeries()
|
||||
}
|
||||
donec <- Stats{
|
||||
AvgTotal: r.avgTotal,
|
||||
Fastest: r.fastest,
|
||||
Slowest: r.slowest,
|
||||
Average: r.average,
|
||||
Stddev: r.stddev,
|
||||
RPS: r.rps,
|
||||
Total: r.total,
|
||||
ErrorDist: copyMap(r.errorDist),
|
||||
Lats: copyFloats(r.lats),
|
||||
TimeSeries: ts,
|
||||
}
|
||||
}()
|
||||
return donec
|
||||
}
|
||||
|
||||
func copyMap(m map[string]int) (c map[string]int) {
|
||||
c = make(map[string]int, len(m))
|
||||
for k, v := range m {
|
||||
c[k] = v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func copyFloats(s []float64) (c []float64) {
|
||||
c = make([]float64, len(s))
|
||||
copy(c, s)
|
||||
return
|
||||
}
|
||||
|
||||
func (r *report) String() (s string) {
|
||||
if len(r.lats) > 0 {
|
||||
s += fmt.Sprintf("\nSummary:\n")
|
||||
s += fmt.Sprintf(" Total:\t%s.\n", r.sec2str(r.total.Seconds()))
|
||||
s += fmt.Sprintf(" Slowest:\t%s.\n", r.sec2str(r.slowest))
|
||||
s += fmt.Sprintf(" Fastest:\t%s.\n", r.sec2str(r.fastest))
|
||||
s += fmt.Sprintf(" Average:\t%s.\n", r.sec2str(r.average))
|
||||
s += fmt.Sprintf(" Stddev:\t%s.\n", r.sec2str(r.stddev))
|
||||
s += fmt.Sprintf(" Requests/sec:\t"+r.precision+"\n", r.rps)
|
||||
s += r.histogram()
|
||||
s += r.sprintLatencies()
|
||||
if r.sps != nil {
|
||||
s += fmt.Sprintf("%v\n", r.sps.getTimeSeries())
|
||||
}
|
||||
}
|
||||
if len(r.errorDist) > 0 {
|
||||
s += r.errors()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *report) sec2str(sec float64) string { return fmt.Sprintf(r.precision+" secs", sec) }
|
||||
|
||||
type reportRate struct{ *report }
|
||||
|
||||
func NewReportRate(precision string) Report {
|
||||
return &reportRate{NewReport(precision).(*report)}
|
||||
}
|
||||
|
||||
func (r *reportRate) String() string {
|
||||
return fmt.Sprintf(" Requests/sec:\t"+r.precision+"\n", r.rps)
|
||||
}
|
||||
|
||||
func (r *report) processResult(res *Result) {
|
||||
if res.Err != nil {
|
||||
r.errorDist[res.Err.Error()]++
|
||||
return
|
||||
}
|
||||
dur := res.Duration()
|
||||
r.lats = append(r.lats, dur.Seconds())
|
||||
r.avgTotal += dur.Seconds()
|
||||
if r.sps != nil {
|
||||
r.sps.Add(res.Start, dur)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *report) processResults() {
|
||||
st := time.Now()
|
||||
for res := range r.results {
|
||||
r.processResult(&res)
|
||||
}
|
||||
r.total = time.Since(st)
|
||||
|
||||
r.rps = float64(len(r.lats)) / r.total.Seconds()
|
||||
r.average = r.avgTotal / float64(len(r.lats))
|
||||
for i := range r.lats {
|
||||
dev := r.lats[i] - r.average
|
||||
r.stddev += dev * dev
|
||||
}
|
||||
r.stddev = math.Sqrt(r.stddev / float64(len(r.lats)))
|
||||
sort.Float64s(r.lats)
|
||||
if len(r.lats) > 0 {
|
||||
r.fastest = r.lats[0]
|
||||
r.slowest = r.lats[len(r.lats)-1]
|
||||
}
|
||||
}
|
||||
|
||||
var pctls = []float64{10, 25, 50, 75, 90, 95, 99, 99.9}
|
||||
|
||||
// Percentiles returns percentile distribution of float64 slice.
|
||||
func Percentiles(nums []float64) (pcs []float64, data []float64) {
|
||||
return pctls, percentiles(nums)
|
||||
}
|
||||
|
||||
func percentiles(nums []float64) (data []float64) {
|
||||
data = make([]float64, len(pctls))
|
||||
j := 0
|
||||
n := len(nums)
|
||||
for i := 0; i < n && j < len(pctls); i++ {
|
||||
current := float64(i) * 100.0 / float64(n)
|
||||
if current >= pctls[j] {
|
||||
data[j] = nums[i]
|
||||
j++
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *report) sprintLatencies() string {
|
||||
data := percentiles(r.lats)
|
||||
s := fmt.Sprintf("\nLatency distribution:\n")
|
||||
for i := 0; i < len(pctls); i++ {
|
||||
if data[i] > 0 {
|
||||
s += fmt.Sprintf(" %v%% in %s.\n", pctls[i], r.sec2str(data[i]))
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *report) histogram() string {
|
||||
bc := 10
|
||||
buckets := make([]float64, bc+1)
|
||||
counts := make([]int, bc+1)
|
||||
bs := (r.slowest - r.fastest) / float64(bc)
|
||||
for i := 0; i < bc; i++ {
|
||||
buckets[i] = r.fastest + bs*float64(i)
|
||||
}
|
||||
buckets[bc] = r.slowest
|
||||
var bi int
|
||||
var max int
|
||||
for i := 0; i < len(r.lats); {
|
||||
if r.lats[i] <= buckets[bi] {
|
||||
i++
|
||||
counts[bi]++
|
||||
if max < counts[bi] {
|
||||
max = counts[bi]
|
||||
}
|
||||
} else if bi < len(buckets)-1 {
|
||||
bi++
|
||||
}
|
||||
}
|
||||
s := fmt.Sprintf("\nResponse time histogram:\n")
|
||||
for i := 0; i < len(buckets); i++ {
|
||||
// Normalize bar lengths.
|
||||
var barLen int
|
||||
if max > 0 {
|
||||
barLen = counts[i] * 40 / max
|
||||
}
|
||||
s += fmt.Sprintf(" "+r.precision+" [%v]\t|%v\n", buckets[i], counts[i], strings.Repeat(barChar, barLen))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *report) errors() string {
|
||||
s := fmt.Sprintf("\nError distribution:\n")
|
||||
for err, num := range r.errorDist {
|
||||
s += fmt.Sprintf(" [%d]\t%s\n", num, err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
33
vendor/github.com/coreos/etcd/pkg/report/report_test.go
generated
vendored
Normal file
33
vendor/github.com/coreos/etcd/pkg/report/report_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2017 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package report
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestPercentiles(t *testing.T) {
|
||||
nums := make([]float64, 100)
|
||||
nums[99] = 1 // 99-percentile (1 out of 100)
|
||||
data := percentiles(nums)
|
||||
if data[len(pctls)-2] != 1 {
|
||||
t.Fatalf("99-percentile expected 1, got %f", data[len(pctls)-2])
|
||||
}
|
||||
|
||||
nums = make([]float64, 1000)
|
||||
nums[999] = 1 // 99.9-percentile (1 out of 1000)
|
||||
data = percentiles(nums)
|
||||
if data[len(pctls)-1] != 1 {
|
||||
t.Fatalf("99.9-percentile expected 1, got %f", data[len(pctls)-1])
|
||||
}
|
||||
}
|
||||
134
vendor/github.com/coreos/etcd/pkg/report/timeseries.go
generated
vendored
Normal file
134
vendor/github.com/coreos/etcd/pkg/report/timeseries.go
generated
vendored
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package report
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DataPoint struct {
|
||||
Timestamp int64
|
||||
AvgLatency time.Duration
|
||||
ThroughPut int64
|
||||
}
|
||||
|
||||
type TimeSeries []DataPoint
|
||||
|
||||
func (t TimeSeries) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
|
||||
func (t TimeSeries) Len() int { return len(t) }
|
||||
func (t TimeSeries) Less(i, j int) bool { return t[i].Timestamp < t[j].Timestamp }
|
||||
|
||||
type secondPoint struct {
|
||||
totalLatency time.Duration
|
||||
count int64
|
||||
}
|
||||
|
||||
type secondPoints struct {
|
||||
mu sync.Mutex
|
||||
tm map[int64]secondPoint
|
||||
}
|
||||
|
||||
func newSecondPoints() *secondPoints {
|
||||
return &secondPoints{tm: make(map[int64]secondPoint)}
|
||||
}
|
||||
|
||||
func (sp *secondPoints) Add(ts time.Time, lat time.Duration) {
|
||||
sp.mu.Lock()
|
||||
defer sp.mu.Unlock()
|
||||
|
||||
tk := ts.Unix()
|
||||
if v, ok := sp.tm[tk]; !ok {
|
||||
sp.tm[tk] = secondPoint{totalLatency: lat, count: 1}
|
||||
} else {
|
||||
v.totalLatency += lat
|
||||
v.count += 1
|
||||
sp.tm[tk] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (sp *secondPoints) getTimeSeries() TimeSeries {
|
||||
sp.mu.Lock()
|
||||
defer sp.mu.Unlock()
|
||||
|
||||
var (
|
||||
minTs int64 = math.MaxInt64
|
||||
maxTs int64 = -1
|
||||
)
|
||||
for k := range sp.tm {
|
||||
if minTs > k {
|
||||
minTs = k
|
||||
}
|
||||
if maxTs < k {
|
||||
maxTs = k
|
||||
}
|
||||
}
|
||||
for ti := minTs; ti < maxTs; ti++ {
|
||||
if _, ok := sp.tm[ti]; !ok { // fill-in empties
|
||||
sp.tm[ti] = secondPoint{totalLatency: 0, count: 0}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
tslice = make(TimeSeries, len(sp.tm))
|
||||
i int
|
||||
)
|
||||
for k, v := range sp.tm {
|
||||
var lat time.Duration
|
||||
if v.count > 0 {
|
||||
lat = time.Duration(v.totalLatency) / time.Duration(v.count)
|
||||
}
|
||||
tslice[i] = DataPoint{
|
||||
Timestamp: k,
|
||||
AvgLatency: lat,
|
||||
ThroughPut: v.count,
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
sort.Sort(tslice)
|
||||
return tslice
|
||||
}
|
||||
|
||||
func (ts TimeSeries) String() string {
|
||||
buf := new(bytes.Buffer)
|
||||
wr := csv.NewWriter(buf)
|
||||
if err := wr.Write([]string{"UNIX-TS", "AVG-LATENCY-MS", "AVG-THROUGHPUT"}); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
rows := [][]string{}
|
||||
for i := range ts {
|
||||
row := []string{
|
||||
fmt.Sprintf("%d", ts[i].Timestamp),
|
||||
fmt.Sprintf("%s", ts[i].AvgLatency),
|
||||
fmt.Sprintf("%d", ts[i].ThroughPut),
|
||||
}
|
||||
rows = append(rows, row)
|
||||
}
|
||||
if err := wr.WriteAll(rows); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
wr.Flush()
|
||||
if err := wr.Error(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return fmt.Sprintf("\nSample in one second (unix latency throughput):\n%s", buf.String())
|
||||
}
|
||||
31
vendor/github.com/coreos/etcd/pkg/report/timeseries_test.go
generated
vendored
Normal file
31
vendor/github.com/coreos/etcd/pkg/report/timeseries_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package report
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestGetTimeseries(t *testing.T) {
|
||||
sp := newSecondPoints()
|
||||
now := time.Now()
|
||||
sp.Add(now, time.Second)
|
||||
sp.Add(now.Add(5*time.Second), time.Second)
|
||||
n := sp.getTimeSeries().Len()
|
||||
if n < 3 {
|
||||
t.Fatalf("expected at 6 points of time series, got %s", sp.getTimeSeries())
|
||||
}
|
||||
}
|
||||
37
vendor/github.com/coreos/etcd/pkg/runtime/fds_linux.go
generated
vendored
Normal file
37
vendor/github.com/coreos/etcd/pkg/runtime/fds_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package runtime implements utility functions for runtime systems.
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func FDLimit() (uint64, error) {
|
||||
var rlimit syscall.Rlimit
|
||||
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return rlimit.Cur, nil
|
||||
}
|
||||
|
||||
func FDUsage() (uint64, error) {
|
||||
fds, err := ioutil.ReadDir("/proc/self/fd")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint64(len(fds)), nil
|
||||
}
|
||||
30
vendor/github.com/coreos/etcd/pkg/runtime/fds_other.go
generated
vendored
Normal file
30
vendor/github.com/coreos/etcd/pkg/runtime/fds_other.go
generated
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !linux
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func FDLimit() (uint64, error) {
|
||||
return 0, fmt.Errorf("cannot get FDLimit on %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
func FDUsage() (uint64, error) {
|
||||
return 0, fmt.Errorf("cannot get FDUsage on %s", runtime.GOOS)
|
||||
}
|
||||
16
vendor/github.com/coreos/etcd/pkg/schedule/doc.go
generated
vendored
Normal file
16
vendor/github.com/coreos/etcd/pkg/schedule/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package schedule provides mechanisms and policies for scheduling units of work.
|
||||
package schedule
|
||||
168
vendor/github.com/coreos/etcd/pkg/schedule/schedule.go
generated
vendored
Normal file
168
vendor/github.com/coreos/etcd/pkg/schedule/schedule.go
generated
vendored
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package schedule
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type Job func(context.Context)
|
||||
|
||||
// Scheduler can schedule jobs.
|
||||
type Scheduler interface {
|
||||
// Schedule asks the scheduler to schedule a job defined by the given func.
|
||||
// Schedule to a stopped scheduler might panic.
|
||||
Schedule(j Job)
|
||||
|
||||
// Pending returns number of pending jobs
|
||||
Pending() int
|
||||
|
||||
// Scheduled returns the number of scheduled jobs (excluding pending jobs)
|
||||
Scheduled() int
|
||||
|
||||
// Finished returns the number of finished jobs
|
||||
Finished() int
|
||||
|
||||
// WaitFinish waits until at least n job are finished and all pending jobs are finished.
|
||||
WaitFinish(n int)
|
||||
|
||||
// Stop stops the scheduler.
|
||||
Stop()
|
||||
}
|
||||
|
||||
type fifo struct {
|
||||
mu sync.Mutex
|
||||
|
||||
resume chan struct{}
|
||||
scheduled int
|
||||
finished int
|
||||
pendings []Job
|
||||
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
|
||||
finishCond *sync.Cond
|
||||
donec chan struct{}
|
||||
}
|
||||
|
||||
// NewFIFOScheduler returns a Scheduler that schedules jobs in FIFO
|
||||
// order sequentially
|
||||
func NewFIFOScheduler() Scheduler {
|
||||
f := &fifo{
|
||||
resume: make(chan struct{}, 1),
|
||||
donec: make(chan struct{}, 1),
|
||||
}
|
||||
f.finishCond = sync.NewCond(&f.mu)
|
||||
f.ctx, f.cancel = context.WithCancel(context.Background())
|
||||
go f.run()
|
||||
return f
|
||||
}
|
||||
|
||||
// Schedule schedules a job that will be ran in FIFO order sequentially.
|
||||
func (f *fifo) Schedule(j Job) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
|
||||
if f.cancel == nil {
|
||||
panic("schedule: schedule to stopped scheduler")
|
||||
}
|
||||
|
||||
if len(f.pendings) == 0 {
|
||||
select {
|
||||
case f.resume <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
f.pendings = append(f.pendings, j)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (f *fifo) Pending() int {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return len(f.pendings)
|
||||
}
|
||||
|
||||
func (f *fifo) Scheduled() int {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.scheduled
|
||||
}
|
||||
|
||||
func (f *fifo) Finished() int {
|
||||
f.finishCond.L.Lock()
|
||||
defer f.finishCond.L.Unlock()
|
||||
return f.finished
|
||||
}
|
||||
|
||||
func (f *fifo) WaitFinish(n int) {
|
||||
f.finishCond.L.Lock()
|
||||
for f.finished < n || len(f.pendings) != 0 {
|
||||
f.finishCond.Wait()
|
||||
}
|
||||
f.finishCond.L.Unlock()
|
||||
}
|
||||
|
||||
// Stop stops the scheduler and cancels all pending jobs.
|
||||
func (f *fifo) Stop() {
|
||||
f.mu.Lock()
|
||||
f.cancel()
|
||||
f.cancel = nil
|
||||
f.mu.Unlock()
|
||||
<-f.donec
|
||||
}
|
||||
|
||||
func (f *fifo) run() {
|
||||
// TODO: recover from job panic?
|
||||
defer func() {
|
||||
close(f.donec)
|
||||
close(f.resume)
|
||||
}()
|
||||
|
||||
for {
|
||||
var todo Job
|
||||
f.mu.Lock()
|
||||
if len(f.pendings) != 0 {
|
||||
f.scheduled++
|
||||
todo = f.pendings[0]
|
||||
}
|
||||
f.mu.Unlock()
|
||||
if todo == nil {
|
||||
select {
|
||||
case <-f.resume:
|
||||
case <-f.ctx.Done():
|
||||
f.mu.Lock()
|
||||
pendings := f.pendings
|
||||
f.pendings = nil
|
||||
f.mu.Unlock()
|
||||
// clean up pending jobs
|
||||
for _, todo := range pendings {
|
||||
todo(f.ctx)
|
||||
}
|
||||
return
|
||||
}
|
||||
} else {
|
||||
todo(f.ctx)
|
||||
f.finishCond.L.Lock()
|
||||
f.finished++
|
||||
f.pendings = f.pendings[1:]
|
||||
f.finishCond.Broadcast()
|
||||
f.finishCond.L.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
50
vendor/github.com/coreos/etcd/pkg/schedule/schedule_test.go
generated
vendored
Normal file
50
vendor/github.com/coreos/etcd/pkg/schedule/schedule_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package schedule
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestFIFOSchedule(t *testing.T) {
|
||||
s := NewFIFOScheduler()
|
||||
defer s.Stop()
|
||||
|
||||
next := 0
|
||||
jobCreator := func(i int) Job {
|
||||
return func(ctx context.Context) {
|
||||
if next != i {
|
||||
t.Fatalf("job#%d: got %d, want %d", i, next, i)
|
||||
}
|
||||
next = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
var jobs []Job
|
||||
for i := 0; i < 100; i++ {
|
||||
jobs = append(jobs, jobCreator(i))
|
||||
}
|
||||
|
||||
for _, j := range jobs {
|
||||
s.Schedule(j)
|
||||
}
|
||||
|
||||
s.WaitFinish(100)
|
||||
if s.Scheduled() != 100 {
|
||||
t.Errorf("scheduled = %d, want %d", s.Scheduled(), 100)
|
||||
}
|
||||
}
|
||||
54
vendor/github.com/coreos/etcd/pkg/stringutil/stringutil.go
generated
vendored
Normal file
54
vendor/github.com/coreos/etcd/pkg/stringutil/stringutil.go
generated
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package stringutil
|
||||
|
||||
import "math/rand"
|
||||
|
||||
const (
|
||||
chars = "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||
)
|
||||
|
||||
// UniqueStrings retruns a slice of randomly generated unique strings.
|
||||
func UniqueStrings(maxlen uint, n int) []string {
|
||||
exist := make(map[string]bool)
|
||||
ss := make([]string, 0)
|
||||
|
||||
for len(ss) < n {
|
||||
s := randomString(maxlen)
|
||||
if !exist[s] {
|
||||
exist[s] = true
|
||||
ss = append(ss, s)
|
||||
}
|
||||
}
|
||||
|
||||
return ss
|
||||
}
|
||||
|
||||
// RandomStrings retruns a slice of randomly generated strings.
|
||||
func RandomStrings(maxlen uint, n int) []string {
|
||||
ss := make([]string, 0)
|
||||
for i := 0; i < n; i++ {
|
||||
ss = append(ss, randomString(maxlen))
|
||||
}
|
||||
return ss
|
||||
}
|
||||
|
||||
func randomString(l uint) string {
|
||||
s := make([]byte, l)
|
||||
for i := 0; i < int(l); i++ {
|
||||
s[i] = chars[rand.Intn(len(chars))]
|
||||
}
|
||||
return string(s)
|
||||
}
|
||||
125
vendor/github.com/coreos/etcd/pkg/testutil/leak.go
generated
vendored
Normal file
125
vendor/github.com/coreos/etcd/pkg/testutil/leak.go
generated
vendored
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
// Copyright 2013 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 testutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
CheckLeakedGoroutine verifies tests do not leave any leaky
|
||||
goroutines. It returns true when there are goroutines still
|
||||
running(leaking) after all tests.
|
||||
|
||||
import "github.com/coreos/etcd/pkg/testutil"
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
v := m.Run()
|
||||
if v == 0 && testutil.CheckLeakedGoroutine() {
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(v)
|
||||
}
|
||||
|
||||
func TestSample(t *testing.T) {
|
||||
defer testutil.AfterTest(t)
|
||||
...
|
||||
}
|
||||
|
||||
*/
|
||||
func CheckLeakedGoroutine() bool {
|
||||
if testing.Short() {
|
||||
// not counting goroutines for leakage in -short mode
|
||||
return false
|
||||
}
|
||||
gs := interestingGoroutines()
|
||||
if len(gs) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
stackCount := make(map[string]int)
|
||||
re := regexp.MustCompile(`\(0[0-9a-fx, ]*\)`)
|
||||
for _, g := range gs {
|
||||
// strip out pointer arguments in first function of stack dump
|
||||
normalized := string(re.ReplaceAll([]byte(g), []byte("(...)")))
|
||||
stackCount[normalized]++
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "Too many goroutines running after all test(s).\n")
|
||||
for stack, count := range stackCount {
|
||||
fmt.Fprintf(os.Stderr, "%d instances of:\n%s\n", count, stack)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func AfterTest(t *testing.T) {
|
||||
http.DefaultTransport.(*http.Transport).CloseIdleConnections()
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
var bad string
|
||||
badSubstring := map[string]string{
|
||||
").writeLoop(": "a Transport",
|
||||
"created by net/http/httptest.(*Server).Start": "an httptest.Server",
|
||||
"timeoutHandler": "a TimeoutHandler",
|
||||
"net.(*netFD).connect(": "a timing out dial",
|
||||
").noteClientGone(": "a closenotifier sender",
|
||||
").readLoop(": "a Transport",
|
||||
}
|
||||
|
||||
var stacks string
|
||||
for i := 0; i < 6; i++ {
|
||||
bad = ""
|
||||
stacks = strings.Join(interestingGoroutines(), "\n\n")
|
||||
for substr, what := range badSubstring {
|
||||
if strings.Contains(stacks, substr) {
|
||||
bad = what
|
||||
}
|
||||
}
|
||||
if bad == "" {
|
||||
return
|
||||
}
|
||||
// Bad stuff found, but goroutines might just still be
|
||||
// shutting down, so give it some time.
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
t.Errorf("Test appears to have leaked %s:\n%s", bad, stacks)
|
||||
}
|
||||
|
||||
func interestingGoroutines() (gs []string) {
|
||||
buf := make([]byte, 2<<20)
|
||||
buf = buf[:runtime.Stack(buf, true)]
|
||||
for _, g := range strings.Split(string(buf), "\n\n") {
|
||||
sl := strings.SplitN(g, "\n", 2)
|
||||
if len(sl) != 2 {
|
||||
continue
|
||||
}
|
||||
stack := strings.TrimSpace(sl[1])
|
||||
if stack == "" ||
|
||||
strings.Contains(stack, "created by os/signal.init") ||
|
||||
strings.Contains(stack, "runtime/panic.go") ||
|
||||
strings.Contains(stack, "created by testing.RunTests") ||
|
||||
strings.Contains(stack, "testing.Main(") ||
|
||||
strings.Contains(stack, "runtime.goexit") ||
|
||||
strings.Contains(stack, "github.com/coreos/etcd/pkg/testutil.interestingGoroutines") ||
|
||||
strings.Contains(stack, "github.com/coreos/etcd/pkg/logutil.(*MergeLogger).outputLoop") ||
|
||||
strings.Contains(stack, "github.com/golang/glog.(*loggingT).flushDaemon") ||
|
||||
strings.Contains(stack, "created by runtime.gc") ||
|
||||
strings.Contains(stack, "runtime.MHeap_Scavenger") {
|
||||
continue
|
||||
}
|
||||
gs = append(gs, stack)
|
||||
}
|
||||
sort.Strings(gs)
|
||||
return
|
||||
}
|
||||
44
vendor/github.com/coreos/etcd/pkg/testutil/leak_test.go
generated
vendored
Normal file
44
vendor/github.com/coreos/etcd/pkg/testutil/leak_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// so tests pass if given a -run that doesn't include TestSample
|
||||
var ranSample = false
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
m.Run()
|
||||
isLeaked := CheckLeakedGoroutine()
|
||||
if ranSample && !isLeaked {
|
||||
fmt.Fprintln(os.Stderr, "expected leaky goroutines but none is detected")
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func TestSample(t *testing.T) {
|
||||
defer AfterTest(t)
|
||||
ranSample = true
|
||||
for range make([]struct{}, 100) {
|
||||
go func() {
|
||||
select {}
|
||||
}()
|
||||
}
|
||||
}
|
||||
57
vendor/github.com/coreos/etcd/pkg/testutil/pauseable_handler.go
generated
vendored
Normal file
57
vendor/github.com/coreos/etcd/pkg/testutil/pauseable_handler.go
generated
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type PauseableHandler struct {
|
||||
Next http.Handler
|
||||
mu sync.Mutex
|
||||
paused bool
|
||||
}
|
||||
|
||||
func (ph *PauseableHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
ph.mu.Lock()
|
||||
paused := ph.paused
|
||||
ph.mu.Unlock()
|
||||
if !paused {
|
||||
ph.Next.ServeHTTP(w, r)
|
||||
} else {
|
||||
hj, ok := w.(http.Hijacker)
|
||||
if !ok {
|
||||
panic("webserver doesn't support hijacking")
|
||||
}
|
||||
conn, _, err := hj.Hijack()
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
conn.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (ph *PauseableHandler) Pause() {
|
||||
ph.mu.Lock()
|
||||
defer ph.mu.Unlock()
|
||||
ph.paused = true
|
||||
}
|
||||
|
||||
func (ph *PauseableHandler) Resume() {
|
||||
ph.mu.Lock()
|
||||
defer ph.mu.Unlock()
|
||||
ph.paused = false
|
||||
}
|
||||
132
vendor/github.com/coreos/etcd/pkg/testutil/recorder.go
generated
vendored
Normal file
132
vendor/github.com/coreos/etcd/pkg/testutil/recorder.go
generated
vendored
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Action struct {
|
||||
Name string
|
||||
Params []interface{}
|
||||
}
|
||||
|
||||
type Recorder interface {
|
||||
// Record publishes an Action (e.g., function call) which will
|
||||
// be reflected by Wait() or Chan()
|
||||
Record(a Action)
|
||||
// Wait waits until at least n Actions are available or returns with error
|
||||
Wait(n int) ([]Action, error)
|
||||
// Action returns immediately available Actions
|
||||
Action() []Action
|
||||
// Chan returns the channel for actions published by Record
|
||||
Chan() <-chan Action
|
||||
}
|
||||
|
||||
// RecorderBuffered appends all Actions to a slice
|
||||
type RecorderBuffered struct {
|
||||
sync.Mutex
|
||||
actions []Action
|
||||
}
|
||||
|
||||
func (r *RecorderBuffered) Record(a Action) {
|
||||
r.Lock()
|
||||
r.actions = append(r.actions, a)
|
||||
r.Unlock()
|
||||
}
|
||||
func (r *RecorderBuffered) Action() []Action {
|
||||
r.Lock()
|
||||
cpy := make([]Action, len(r.actions))
|
||||
copy(cpy, r.actions)
|
||||
r.Unlock()
|
||||
return cpy
|
||||
}
|
||||
func (r *RecorderBuffered) Wait(n int) (acts []Action, err error) {
|
||||
// legacy racey behavior
|
||||
WaitSchedule()
|
||||
acts = r.Action()
|
||||
if len(acts) < n {
|
||||
err = newLenErr(n, len(acts))
|
||||
}
|
||||
return acts, err
|
||||
}
|
||||
|
||||
func (r *RecorderBuffered) Chan() <-chan Action {
|
||||
ch := make(chan Action)
|
||||
go func() {
|
||||
acts := r.Action()
|
||||
for i := range acts {
|
||||
ch <- acts[i]
|
||||
}
|
||||
close(ch)
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
// RecorderStream writes all Actions to an unbuffered channel
|
||||
type recorderStream struct {
|
||||
ch chan Action
|
||||
}
|
||||
|
||||
func NewRecorderStream() Recorder {
|
||||
return &recorderStream{ch: make(chan Action)}
|
||||
}
|
||||
|
||||
func (r *recorderStream) Record(a Action) {
|
||||
r.ch <- a
|
||||
}
|
||||
|
||||
func (r *recorderStream) Action() (acts []Action) {
|
||||
for {
|
||||
select {
|
||||
case act := <-r.ch:
|
||||
acts = append(acts, act)
|
||||
default:
|
||||
return acts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *recorderStream) Chan() <-chan Action {
|
||||
return r.ch
|
||||
}
|
||||
|
||||
func (r *recorderStream) Wait(n int) ([]Action, error) {
|
||||
acts := make([]Action, n)
|
||||
timeoutC := time.After(5 * time.Second)
|
||||
for i := 0; i < n; i++ {
|
||||
select {
|
||||
case acts[i] = <-r.ch:
|
||||
case <-timeoutC:
|
||||
acts = acts[:i]
|
||||
return acts, newLenErr(n, i)
|
||||
}
|
||||
}
|
||||
// extra wait to catch any Action spew
|
||||
select {
|
||||
case act := <-r.ch:
|
||||
acts = append(acts, act)
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
}
|
||||
return acts, nil
|
||||
}
|
||||
|
||||
func newLenErr(expected int, actual int) error {
|
||||
s := fmt.Sprintf("len(actions) = %d, expected >= %d", actual, expected)
|
||||
return errors.New(s)
|
||||
}
|
||||
57
vendor/github.com/coreos/etcd/pkg/testutil/testutil.go
generated
vendored
Normal file
57
vendor/github.com/coreos/etcd/pkg/testutil/testutil.go
generated
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package testutil provides test utility functions.
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// WaitSchedule briefly sleeps in order to invoke the go scheduler.
|
||||
// TODO: improve this when we are able to know the schedule or status of target go-routine.
|
||||
func WaitSchedule() {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
func MustNewURLs(t *testing.T, urls []string) []url.URL {
|
||||
if urls == nil {
|
||||
return nil
|
||||
}
|
||||
var us []url.URL
|
||||
for _, url := range urls {
|
||||
u := MustNewURL(t, url)
|
||||
us = append(us, *u)
|
||||
}
|
||||
return us
|
||||
}
|
||||
|
||||
func MustNewURL(t *testing.T, s string) *url.URL {
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
t.Fatalf("parse %v error: %v", s, err)
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
// FatalStack helps to fatal the test and print out the stacks of all running goroutines.
|
||||
func FatalStack(t *testing.T, s string) {
|
||||
stackTrace := make([]byte, 1024*1024)
|
||||
n := runtime.Stack(stackTrace, true)
|
||||
t.Error(string(stackTrace[:n]))
|
||||
t.Fatalf(s)
|
||||
}
|
||||
16
vendor/github.com/coreos/etcd/pkg/tlsutil/doc.go
generated
vendored
Normal file
16
vendor/github.com/coreos/etcd/pkg/tlsutil/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package tlsutil provides utility functions for handling TLS.
|
||||
package tlsutil
|
||||
72
vendor/github.com/coreos/etcd/pkg/tlsutil/tlsutil.go
generated
vendored
Normal file
72
vendor/github.com/coreos/etcd/pkg/tlsutil/tlsutil.go
generated
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tlsutil
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// NewCertPool creates x509 certPool with provided CA files.
|
||||
func NewCertPool(CAFiles []string) (*x509.CertPool, error) {
|
||||
certPool := x509.NewCertPool()
|
||||
|
||||
for _, CAFile := range CAFiles {
|
||||
pemByte, err := ioutil.ReadFile(CAFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for {
|
||||
var block *pem.Block
|
||||
block, pemByte = pem.Decode(pemByte)
|
||||
if block == nil {
|
||||
break
|
||||
}
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certPool.AddCert(cert)
|
||||
}
|
||||
}
|
||||
|
||||
return certPool, nil
|
||||
}
|
||||
|
||||
// NewCert generates TLS cert by using the given cert,key and parse function.
|
||||
func NewCert(certfile, keyfile string, parseFunc func([]byte, []byte) (tls.Certificate, error)) (*tls.Certificate, error) {
|
||||
cert, err := ioutil.ReadFile(certfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := ioutil.ReadFile(keyfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if parseFunc == nil {
|
||||
parseFunc = tls.X509KeyPair
|
||||
}
|
||||
|
||||
tlsCert, err := parseFunc(cert, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tlsCert, nil
|
||||
}
|
||||
17
vendor/github.com/coreos/etcd/pkg/transport/doc.go
generated
vendored
Normal file
17
vendor/github.com/coreos/etcd/pkg/transport/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package transport implements various HTTP transport utilities based on Go
|
||||
// net package.
|
||||
package transport
|
||||
94
vendor/github.com/coreos/etcd/pkg/transport/keepalive_listener.go
generated
vendored
Normal file
94
vendor/github.com/coreos/etcd/pkg/transport/keepalive_listener.go
generated
vendored
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package transport
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type keepAliveConn interface {
|
||||
SetKeepAlive(bool) error
|
||||
SetKeepAlivePeriod(d time.Duration) error
|
||||
}
|
||||
|
||||
// NewKeepAliveListener returns a listener that listens on the given address.
|
||||
// Be careful when wrap around KeepAliveListener with another Listener if TLSInfo is not nil.
|
||||
// Some pkgs (like go/http) might expect Listener to return TLSConn type to start TLS handshake.
|
||||
// http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html
|
||||
func NewKeepAliveListener(l net.Listener, scheme string, tlscfg *tls.Config) (net.Listener, error) {
|
||||
if scheme == "https" {
|
||||
if tlscfg == nil {
|
||||
return nil, fmt.Errorf("cannot listen on TLS for given listener: KeyFile and CertFile are not presented")
|
||||
}
|
||||
return newTLSKeepaliveListener(l, tlscfg), nil
|
||||
}
|
||||
|
||||
return &keepaliveListener{
|
||||
Listener: l,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type keepaliveListener struct{ net.Listener }
|
||||
|
||||
func (kln *keepaliveListener) Accept() (net.Conn, error) {
|
||||
c, err := kln.Listener.Accept()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kac := c.(keepAliveConn)
|
||||
// detection time: tcp_keepalive_time + tcp_keepalive_probes + tcp_keepalive_intvl
|
||||
// default on linux: 30 + 8 * 30
|
||||
// default on osx: 30 + 8 * 75
|
||||
kac.SetKeepAlive(true)
|
||||
kac.SetKeepAlivePeriod(30 * time.Second)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// A tlsKeepaliveListener implements a network listener (net.Listener) for TLS connections.
|
||||
type tlsKeepaliveListener struct {
|
||||
net.Listener
|
||||
config *tls.Config
|
||||
}
|
||||
|
||||
// Accept waits for and returns the next incoming TLS connection.
|
||||
// The returned connection c is a *tls.Conn.
|
||||
func (l *tlsKeepaliveListener) Accept() (c net.Conn, err error) {
|
||||
c, err = l.Listener.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
kac := c.(keepAliveConn)
|
||||
// detection time: tcp_keepalive_time + tcp_keepalive_probes + tcp_keepalive_intvl
|
||||
// default on linux: 30 + 8 * 30
|
||||
// default on osx: 30 + 8 * 75
|
||||
kac.SetKeepAlive(true)
|
||||
kac.SetKeepAlivePeriod(30 * time.Second)
|
||||
c = tls.Server(c, l.config)
|
||||
return
|
||||
}
|
||||
|
||||
// NewListener creates a Listener which accepts connections from an inner
|
||||
// Listener and wraps each connection with Server.
|
||||
// The configuration config must be non-nil and must have
|
||||
// at least one certificate.
|
||||
func newTLSKeepaliveListener(inner net.Listener, config *tls.Config) net.Listener {
|
||||
l := &tlsKeepaliveListener{}
|
||||
l.Listener = inner
|
||||
l.config = config
|
||||
return l
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue