1// Copyright 2015 The etcd Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package mvcc 16 17import ( 18 "os" 19 "reflect" 20 "testing" 21 "time" 22 23 "github.com/coreos/etcd/lease" 24 "github.com/coreos/etcd/mvcc/backend" 25) 26 27func TestScheduleCompaction(t *testing.T) { 28 revs := []revision{{1, 0}, {2, 0}, {3, 0}} 29 30 tests := []struct { 31 rev int64 32 keep map[revision]struct{} 33 wrevs []revision 34 }{ 35 // compact at 1 and discard all history 36 { 37 1, 38 nil, 39 revs[1:], 40 }, 41 // compact at 3 and discard all history 42 { 43 3, 44 nil, 45 nil, 46 }, 47 // compact at 1 and keeps history one step earlier 48 { 49 1, 50 map[revision]struct{}{ 51 {main: 1}: {}, 52 }, 53 revs, 54 }, 55 // compact at 1 and keeps history two steps earlier 56 { 57 3, 58 map[revision]struct{}{ 59 {main: 2}: {}, 60 {main: 3}: {}, 61 }, 62 revs[1:], 63 }, 64 } 65 for i, tt := range tests { 66 b, tmpPath := backend.NewDefaultTmpBackend() 67 s := NewStore(b, &lease.FakeLessor{}, nil) 68 tx := s.b.BatchTx() 69 70 tx.Lock() 71 ibytes := newRevBytes() 72 for _, rev := range revs { 73 revToBytes(rev, ibytes) 74 tx.UnsafePut(keyBucketName, ibytes, []byte("bar")) 75 } 76 tx.Unlock() 77 78 s.scheduleCompaction(tt.rev, tt.keep) 79 80 tx.Lock() 81 for _, rev := range tt.wrevs { 82 revToBytes(rev, ibytes) 83 keys, _ := tx.UnsafeRange(keyBucketName, ibytes, nil, 0) 84 if len(keys) != 1 { 85 t.Errorf("#%d: range on %v = %d, want 1", i, rev, len(keys)) 86 } 87 } 88 _, vals := tx.UnsafeRange(metaBucketName, finishedCompactKeyName, nil, 0) 89 revToBytes(revision{main: tt.rev}, ibytes) 90 if w := [][]byte{ibytes}; !reflect.DeepEqual(vals, w) { 91 t.Errorf("#%d: vals on %v = %+v, want %+v", i, finishedCompactKeyName, vals, w) 92 } 93 tx.Unlock() 94 95 cleanup(s, b, tmpPath) 96 } 97} 98 99func TestCompactAllAndRestore(t *testing.T) { 100 b, tmpPath := backend.NewDefaultTmpBackend() 101 s0 := NewStore(b, &lease.FakeLessor{}, nil) 102 defer os.Remove(tmpPath) 103 104 s0.Put([]byte("foo"), []byte("bar"), lease.NoLease) 105 s0.Put([]byte("foo"), []byte("bar1"), lease.NoLease) 106 s0.Put([]byte("foo"), []byte("bar2"), lease.NoLease) 107 s0.DeleteRange([]byte("foo"), nil) 108 109 rev := s0.Rev() 110 // compact all keys 111 done, err := s0.Compact(rev) 112 if err != nil { 113 t.Fatal(err) 114 } 115 116 select { 117 case <-done: 118 case <-time.After(10 * time.Second): 119 t.Fatal("timeout waiting for compaction to finish") 120 } 121 122 err = s0.Close() 123 if err != nil { 124 t.Fatal(err) 125 } 126 127 s1 := NewStore(b, &lease.FakeLessor{}, nil) 128 if s1.Rev() != rev { 129 t.Errorf("rev = %v, want %v", s1.Rev(), rev) 130 } 131 _, err = s1.Range([]byte("foo"), nil, RangeOptions{}) 132 if err != nil { 133 t.Errorf("unexpect range error %v", err) 134 } 135} 136