Compare commits
6 Commits
client/pkg
...
v2.0.5
Author | SHA1 | Date | |
---|---|---|---|
9481945228 | |||
e13b09e4d9 | |||
78e0149f41 | |||
4c86ab4868 | |||
59327bab47 | |||
62ed1ebf03 |
@ -30,7 +30,7 @@ ETCD_INITIAL_CLUSTER_STATE=new
|
|||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
-initial-cluster infra0=http://10.0.1.10:2380,http://10.0.1.11:2380,infra2=http://10.0.1.12:2380 \
|
-initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380 \
|
||||||
-initial-cluster-state new
|
-initial-cluster-state new
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -31,7 +31,10 @@ func NewListener(addr string, scheme string, info TLSInfo) (net.Listener, error)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !info.Empty() && scheme == "https" {
|
if scheme == "https" {
|
||||||
|
if info.Empty() {
|
||||||
|
return nil, fmt.Errorf("cannot listen on TLS for %s: KeyFile and CertFile are not presented", scheme+"://"+addr)
|
||||||
|
}
|
||||||
cfg, err := info.ServerConfig()
|
cfg, err := info.ServerConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -70,6 +70,13 @@ func TestNewListenerTLSInfo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewListenerTLSEmptyInfo(t *testing.T) {
|
||||||
|
_, err := NewListener("127.0.0.1:0", "https", TLSInfo{})
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("err = nil, want not presented error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewListenerTLSInfoNonexist(t *testing.T) {
|
func TestNewListenerTLSInfoNonexist(t *testing.T) {
|
||||||
tlsInfo := TLSInfo{CertFile: "@badname", KeyFile: "@badname"}
|
tlsInfo := TLSInfo{CertFile: "@badname", KeyFile: "@badname"}
|
||||||
_, err := NewListener("127.0.0.1:0", "https", tlsInfo)
|
_, err := NewListener("127.0.0.1:0", "https", tlsInfo)
|
||||||
|
@ -28,6 +28,9 @@ func NewTimeoutTransport(info TLSInfo, rdtimeoutd, wtimeoutd time.Duration) (*ht
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// the timeouted connection will tiemout soon after it is idle.
|
||||||
|
// it should not be put back to http transport as an idle connection for future usage.
|
||||||
|
tr.MaxIdleConnsPerHost = -1
|
||||||
tr.Dial = (&rwTimeoutDialer{
|
tr.Dial = (&rwTimeoutDialer{
|
||||||
Dialer: net.Dialer{
|
Dialer: net.Dialer{
|
||||||
Timeout: 30 * time.Second,
|
Timeout: 30 * time.Second,
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
package transport
|
package transport
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
@ -28,7 +30,12 @@ func TestNewTimeoutTransport(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected NewTimeoutTransport error: %v", err)
|
t.Fatalf("unexpected NewTimeoutTransport error: %v", err)
|
||||||
}
|
}
|
||||||
srv := httptest.NewServer(http.NotFoundHandler())
|
|
||||||
|
remoteAddr := func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte(r.RemoteAddr))
|
||||||
|
}
|
||||||
|
srv := httptest.NewServer(http.HandlerFunc(remoteAddr))
|
||||||
|
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
conn, err := tr.Dial("tcp", srv.Listener.Addr().String())
|
conn, err := tr.Dial("tcp", srv.Listener.Addr().String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -46,4 +53,33 @@ func TestNewTimeoutTransport(t *testing.T) {
|
|||||||
if tconn.wtimeoutd != time.Hour {
|
if tconn.wtimeoutd != time.Hour {
|
||||||
t.Errorf("write timeout = %s, want %s", tconn.wtimeoutd, time.Hour)
|
t.Errorf("write timeout = %s, want %s", tconn.wtimeoutd, time.Hour)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure not reuse timeout connection
|
||||||
|
req, err := http.NewRequest("GET", srv.URL, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err %v", err)
|
||||||
|
}
|
||||||
|
resp, err := tr.RoundTrip(req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err %v", err)
|
||||||
|
}
|
||||||
|
addr0, err := ioutil.ReadAll(resp.Body)
|
||||||
|
resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = tr.RoundTrip(req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err %v", err)
|
||||||
|
}
|
||||||
|
addr1, err := ioutil.ReadAll(resp.Body)
|
||||||
|
resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytes.Equal(addr0, addr1) {
|
||||||
|
t.Errorf("addr0 = %s addr1= %s, want not equal", string(addr0), string(addr1))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,7 +304,7 @@ func TestNodeStart(t *testing.T) {
|
|||||||
wants := []Ready{
|
wants := []Ready{
|
||||||
{
|
{
|
||||||
SoftState: &SoftState{Lead: 1, RaftState: StateLeader},
|
SoftState: &SoftState{Lead: 1, RaftState: StateLeader},
|
||||||
HardState: raftpb.HardState{Term: 2, Commit: 2},
|
HardState: raftpb.HardState{Term: 2, Commit: 2, Vote: 1},
|
||||||
Entries: []raftpb.Entry{
|
Entries: []raftpb.Entry{
|
||||||
{Type: raftpb.EntryConfChange, Term: 1, Index: 1, Data: ccdata},
|
{Type: raftpb.EntryConfChange, Term: 1, Index: 1, Data: ccdata},
|
||||||
{Term: 2, Index: 2},
|
{Term: 2, Index: 2},
|
||||||
@ -315,7 +315,7 @@ func TestNodeStart(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
HardState: raftpb.HardState{Term: 2, Commit: 3},
|
HardState: raftpb.HardState{Term: 2, Commit: 3, Vote: 1},
|
||||||
Entries: []raftpb.Entry{{Term: 2, Index: 3, Data: []byte("foo")}},
|
Entries: []raftpb.Entry{{Term: 2, Index: 3, Data: []byte("foo")}},
|
||||||
CommittedEntries: []raftpb.Entry{{Term: 2, Index: 3, Data: []byte("foo")}},
|
CommittedEntries: []raftpb.Entry{{Term: 2, Index: 3, Data: []byte("foo")}},
|
||||||
},
|
},
|
||||||
|
@ -306,9 +306,11 @@ func (r *raft) maybeCommit() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *raft) reset(term uint64) {
|
func (r *raft) reset(term uint64) {
|
||||||
r.Term = term
|
if r.Term != term {
|
||||||
|
r.Term = term
|
||||||
|
r.Vote = None
|
||||||
|
}
|
||||||
r.lead = None
|
r.lead = None
|
||||||
r.Vote = None
|
|
||||||
r.elapsed = 0
|
r.elapsed = 0
|
||||||
r.votes = make(map[uint64]bool)
|
r.votes = make(map[uint64]bool)
|
||||||
for i := range r.prs {
|
for i := range r.prs {
|
||||||
|
@ -15,6 +15,6 @@
|
|||||||
package version
|
package version
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Version = "2.0.4+git"
|
Version = "2.0.5"
|
||||||
InternalVersion = "2"
|
InternalVersion = "2"
|
||||||
)
|
)
|
||||||
|
37
wal/wal.go
37
wal/wal.go
@ -320,27 +320,34 @@ func (w *WAL) sync() error {
|
|||||||
return w.f.Sync()
|
return w.f.Sync()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReleaseLockTo releases the locks w is holding, which
|
// ReleaseLockTo releases the locks, which has smaller index than the given index
|
||||||
// have index smaller or equal to the given index.
|
// except the largest one among them.
|
||||||
|
// For example, if WAL is holding lock 1,2,3,4,5,6, ReleaseLockTo(4) will release
|
||||||
|
// lock 1,2 but keep 3. ReleaseLockTo(5) will release 1,2,3 but keep 4.
|
||||||
func (w *WAL) ReleaseLockTo(index uint64) error {
|
func (w *WAL) ReleaseLockTo(index uint64) error {
|
||||||
for _, l := range w.locks {
|
var smaller int
|
||||||
_, i, err := parseWalName(path.Base(l.Name()))
|
|
||||||
|
for i, l := range w.locks {
|
||||||
|
_, lockIndex, err := parseWalName(path.Base(l.Name()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if i > index {
|
if lockIndex >= index {
|
||||||
return nil
|
smaller = i - 1
|
||||||
|
break
|
||||||
}
|
}
|
||||||
err = l.Unlock()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = l.Destroy()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.locks = w.locks[1:]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if smaller <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < smaller; i++ {
|
||||||
|
w.locks[i].Unlock()
|
||||||
|
w.locks[i].Destroy()
|
||||||
|
}
|
||||||
|
w.locks = w.locks[smaller:]
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,6 +435,7 @@ func TestOpenNotInUse(t *testing.T) {
|
|||||||
unlockIndex := uint64(5)
|
unlockIndex := uint64(5)
|
||||||
w.ReleaseLockTo(unlockIndex)
|
w.ReleaseLockTo(unlockIndex)
|
||||||
|
|
||||||
|
// 1,2,3 are avaliable.
|
||||||
w2, err := OpenNotInUse(p, walpb.Snapshot{})
|
w2, err := OpenNotInUse(p, walpb.Snapshot{})
|
||||||
defer w2.Close()
|
defer w2.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -444,8 +445,8 @@ func TestOpenNotInUse(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err = %v, want nil", err)
|
t.Fatalf("err = %v, want nil", err)
|
||||||
}
|
}
|
||||||
if g := ents[len(ents)-1].Index; g != unlockIndex {
|
if g := ents[len(ents)-1].Index; g != unlockIndex-2 {
|
||||||
t.Errorf("last index read = %d, want %d", g, unlockIndex)
|
t.Errorf("last index read = %d, want %d", g, unlockIndex-2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,3 +463,45 @@ func TestSaveEmpty(t *testing.T) {
|
|||||||
t.Errorf("buf.Bytes = %d, want 0", len(buf.Bytes()))
|
t.Errorf("buf.Bytes = %d, want 0", len(buf.Bytes()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReleaseLockTo(t *testing.T) {
|
||||||
|
p, err := ioutil.TempDir(os.TempDir(), "waltest")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(p)
|
||||||
|
// create WAL
|
||||||
|
w, err := Create(p, nil)
|
||||||
|
defer w.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// make 10 seperate files
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
es := []raftpb.Entry{{Index: uint64(i)}}
|
||||||
|
if err = w.Save(raftpb.HardState{}, es); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err = w.Cut(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// release the lock to 5
|
||||||
|
unlockIndex := uint64(5)
|
||||||
|
w.ReleaseLockTo(unlockIndex)
|
||||||
|
|
||||||
|
// expected remaining are 4,5,6,7,8,9,10
|
||||||
|
if len(w.locks) != 7 {
|
||||||
|
t.Errorf("len(w.locks) = %d, want %d", len(w.locks), 7)
|
||||||
|
}
|
||||||
|
for i, l := range w.locks {
|
||||||
|
_, lockIndex, err := parseWalName(path.Base(l.Name()))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if lockIndex != uint64(i+4) {
|
||||||
|
t.Errorf("#%d: lockindex = %d, want %d", i, lockIndex, uint64(i+4))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user