*: init for on disk snap support

This commit is contained in:
Xiang Li
2014-09-16 18:18:45 -07:00
parent f17391a72b
commit ab61a8aa9a
11 changed files with 359 additions and 104 deletions

View File

@ -162,11 +162,11 @@ func testServer(t *testing.T, ns int64) {
tk := time.NewTicker(10 * time.Millisecond)
defer tk.Stop()
srv := &EtcdServer{
Node: n,
Store: store.New(),
Send: send,
Save: func(_ raftpb.HardState, _ []raftpb.Entry) {},
Ticker: tk.C,
Node: n,
Store: store.New(),
Send: send,
Storage: &storageRecorder{},
Ticker: tk.C,
}
srv.Start()
// TODO(xiangli): randomize election timeout
@ -231,11 +231,11 @@ func TestDoProposal(t *testing.T) {
// this makes <-tk always successful, which accelerates internal clock
close(tk)
srv := &EtcdServer{
Node: n,
Store: st,
Send: func(_ []raftpb.Message) {},
Save: func(_ raftpb.HardState, _ []raftpb.Entry) {},
Ticker: tk,
Node: n,
Store: st,
Send: func(_ []raftpb.Message) {},
Storage: &storageRecorder{},
Ticker: tk,
}
srv.Start()
resp, err := srv.Do(ctx, tt)
@ -299,11 +299,11 @@ func TestDoProposalStopped(t *testing.T) {
close(tk)
srv := &EtcdServer{
// TODO: use fake node for better testability
Node: n,
Store: st,
Send: func(_ []raftpb.Message) {},
Save: func(_ raftpb.HardState, _ []raftpb.Entry) {},
Ticker: tk,
Node: n,
Store: st,
Send: func(_ []raftpb.Message) {},
Storage: &storageRecorder{},
Ticker: tk,
}
srv.Start()
@ -417,7 +417,7 @@ func TestSyncTriggerDeleteExpriedKeys(t *testing.T) {
Node: n,
Store: st,
Send: func(_ []raftpb.Message) {},
Save: func(_ raftpb.HardState, _ []raftpb.Entry) {},
Storage: &storageRecorder{},
SyncTicker: syncTicker.C,
}
srv.Start()
@ -435,6 +435,73 @@ func TestSyncTriggerDeleteExpriedKeys(t *testing.T) {
}
}
// snapshot should snapshot the store and cut the persistent
// TODO: node.Compact is called... we need to make the node an interface
func TestSnapshot(t *testing.T) {
n := raft.Start(0xBAD0, []int64{0xBAD0}, 10, 1)
defer n.Stop()
st := &storeRecorder{}
p := &storageRecorder{}
s := &EtcdServer{
Store: st,
Storage: p,
Node: n,
}
s.snapshot()
action := st.Action()
if len(action) != 1 {
t.Fatalf("len(action) = %d, want 1", len(action))
}
if action[0] != "Save" {
t.Errorf("action = %s, want Save", action[0])
}
action = p.Action()
if len(action) != 1 {
t.Fatalf("len(action) = %d, want 1", len(action))
}
if action[0] != "Cut" {
t.Errorf("action = %s, want Cut", action[0])
}
}
// Applied > SnapCount should trigger a SaveSnap event
// TODO: receive a snapshot from raft leader should also be able
// to trigger snapSave and also trigger a store.Recover.
// We need fake node!
func TestTriggerSnap(t *testing.T) {
ctx := context.Background()
n := raft.Start(0xBAD0, []int64{0xBAD0}, 10, 1)
n.Campaign(ctx)
st := &storeRecorder{}
p := &storageRecorder{}
s := &EtcdServer{
Store: st,
Send: func(_ []raftpb.Message) {},
Storage: p,
Node: n,
SnapCount: 10,
}
s.Start()
for i := 0; int64(i) < s.SnapCount; i++ {
s.Do(ctx, pb.Request{Method: "PUT", Id: 1})
}
time.Sleep(time.Millisecond)
s.Stop()
action := p.Action()
// each operation is recorded as a Save
// Nop + SnapCount * Puts + Cut + SaveSnap = Save + SnapCount * Save + Cut + SaveSnap
if len(action) != 3+int(s.SnapCount) {
t.Fatalf("len(action) = %d, want %d", len(action), 3+int(s.SnapCount))
}
if action[12] != "SaveSnap" {
t.Errorf("action = %s, want SaveSnap", action[12])
}
}
// TODO: test wait trigger correctness in multi-server case
func TestGetBool(t *testing.T) {
@ -458,23 +525,28 @@ func TestGetBool(t *testing.T) {
}
}
type storeRecorder struct {
type recorder struct {
sync.Mutex
action []string
}
func (s *storeRecorder) record(action string) {
s.Lock()
s.action = append(s.action, action)
s.Unlock()
func (r *recorder) record(action string) {
r.Lock()
r.action = append(r.action, action)
r.Unlock()
}
func (s *storeRecorder) Action() []string {
s.Lock()
cpy := make([]string, len(s.action))
copy(cpy, s.action)
s.Unlock()
func (r *recorder) Action() []string {
r.Lock()
cpy := make([]string, len(r.action))
copy(cpy, r.action)
r.Unlock()
return cpy
}
type storeRecorder struct {
recorder
}
func (s *storeRecorder) Version() int { return 0 }
func (s *storeRecorder) Index() uint64 { return 0 }
func (s *storeRecorder) Get(_ string, _, _ bool) (*store.Event, error) {
@ -509,7 +581,10 @@ func (s *storeRecorder) Watch(_ string, _, _ bool, _ uint64) (store.Watcher, err
s.record("Watch")
return &stubWatcher{}, nil
}
func (s *storeRecorder) Save() ([]byte, error) { return nil, nil }
func (s *storeRecorder) Save() ([]byte, error) {
s.record("Save")
return nil, nil
}
func (s *storeRecorder) Recovery(b []byte) error { return nil }
func (s *storeRecorder) TotalTransactions() uint64 { return 0 }
func (s *storeRecorder) JsonStats() []byte { return nil }
@ -537,3 +612,21 @@ func (w *waitRecorder) Trigger(id int64, x interface{}) {
func boolp(b bool) *bool { return &b }
func stringp(s string) *string { return &s }
type storageRecorder struct {
recorder
}
func (p *storageRecorder) Save(st raftpb.HardState, ents []raftpb.Entry) {
p.record("Save")
}
func (p *storageRecorder) Cut() error {
p.record("Cut")
return nil
}
func (p *storageRecorder) SaveSnap(st raftpb.Snapshot) {
if raft.IsEmptySnap(st) {
return
}
p.record("SaveSnap")
}