go.etcd.io/etcd@v3.3.27+incompatible/mvcc/index_test.go (about)

     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  
    15  package mvcc
    16  
    17  import (
    18  	"reflect"
    19  	"testing"
    20  
    21  	"github.com/google/btree"
    22  )
    23  
    24  func TestIndexGet(t *testing.T) {
    25  	ti := newTreeIndex()
    26  	ti.Put([]byte("foo"), revision{main: 2})
    27  	ti.Put([]byte("foo"), revision{main: 4})
    28  	ti.Tombstone([]byte("foo"), revision{main: 6})
    29  
    30  	tests := []struct {
    31  		rev int64
    32  
    33  		wrev     revision
    34  		wcreated revision
    35  		wver     int64
    36  		werr     error
    37  	}{
    38  		{0, revision{}, revision{}, 0, ErrRevisionNotFound},
    39  		{1, revision{}, revision{}, 0, ErrRevisionNotFound},
    40  		{2, revision{main: 2}, revision{main: 2}, 1, nil},
    41  		{3, revision{main: 2}, revision{main: 2}, 1, nil},
    42  		{4, revision{main: 4}, revision{main: 2}, 2, nil},
    43  		{5, revision{main: 4}, revision{main: 2}, 2, nil},
    44  		{6, revision{}, revision{}, 0, ErrRevisionNotFound},
    45  	}
    46  	for i, tt := range tests {
    47  		rev, created, ver, err := ti.Get([]byte("foo"), tt.rev)
    48  		if err != tt.werr {
    49  			t.Errorf("#%d: err = %v, want %v", i, err, tt.werr)
    50  		}
    51  		if rev != tt.wrev {
    52  			t.Errorf("#%d: rev = %+v, want %+v", i, rev, tt.wrev)
    53  		}
    54  		if created != tt.wcreated {
    55  			t.Errorf("#%d: created = %+v, want %+v", i, created, tt.wcreated)
    56  		}
    57  		if ver != tt.wver {
    58  			t.Errorf("#%d: ver = %d, want %d", i, ver, tt.wver)
    59  		}
    60  	}
    61  }
    62  
    63  func TestIndexRange(t *testing.T) {
    64  	allKeys := [][]byte{[]byte("foo"), []byte("foo1"), []byte("foo2")}
    65  	allRevs := []revision{{main: 1}, {main: 2}, {main: 3}}
    66  
    67  	ti := newTreeIndex()
    68  	for i := range allKeys {
    69  		ti.Put(allKeys[i], allRevs[i])
    70  	}
    71  
    72  	atRev := int64(3)
    73  	tests := []struct {
    74  		key, end []byte
    75  		wkeys    [][]byte
    76  		wrevs    []revision
    77  	}{
    78  		// single key that not found
    79  		{
    80  			[]byte("bar"), nil, nil, nil,
    81  		},
    82  		// single key that found
    83  		{
    84  			[]byte("foo"), nil, allKeys[:1], allRevs[:1],
    85  		},
    86  		// range keys, return first member
    87  		{
    88  			[]byte("foo"), []byte("foo1"), allKeys[:1], allRevs[:1],
    89  		},
    90  		// range keys, return first two members
    91  		{
    92  			[]byte("foo"), []byte("foo2"), allKeys[:2], allRevs[:2],
    93  		},
    94  		// range keys, return all members
    95  		{
    96  			[]byte("foo"), []byte("fop"), allKeys, allRevs,
    97  		},
    98  		// range keys, return last two members
    99  		{
   100  			[]byte("foo1"), []byte("fop"), allKeys[1:], allRevs[1:],
   101  		},
   102  		// range keys, return last member
   103  		{
   104  			[]byte("foo2"), []byte("fop"), allKeys[2:], allRevs[2:],
   105  		},
   106  		// range keys, return nothing
   107  		{
   108  			[]byte("foo3"), []byte("fop"), nil, nil,
   109  		},
   110  	}
   111  	for i, tt := range tests {
   112  		keys, revs := ti.Range(tt.key, tt.end, atRev)
   113  		if !reflect.DeepEqual(keys, tt.wkeys) {
   114  			t.Errorf("#%d: keys = %+v, want %+v", i, keys, tt.wkeys)
   115  		}
   116  		if !reflect.DeepEqual(revs, tt.wrevs) {
   117  			t.Errorf("#%d: revs = %+v, want %+v", i, revs, tt.wrevs)
   118  		}
   119  	}
   120  }
   121  
   122  func TestIndexTombstone(t *testing.T) {
   123  	ti := newTreeIndex()
   124  	ti.Put([]byte("foo"), revision{main: 1})
   125  
   126  	err := ti.Tombstone([]byte("foo"), revision{main: 2})
   127  	if err != nil {
   128  		t.Errorf("tombstone error = %v, want nil", err)
   129  	}
   130  
   131  	_, _, _, err = ti.Get([]byte("foo"), 2)
   132  	if err != ErrRevisionNotFound {
   133  		t.Errorf("get error = %v, want nil", err)
   134  	}
   135  	err = ti.Tombstone([]byte("foo"), revision{main: 3})
   136  	if err != ErrRevisionNotFound {
   137  		t.Errorf("tombstone error = %v, want %v", err, ErrRevisionNotFound)
   138  	}
   139  }
   140  
   141  func TestIndexRangeSince(t *testing.T) {
   142  	allKeys := [][]byte{[]byte("foo"), []byte("foo1"), []byte("foo2"), []byte("foo2"), []byte("foo1"), []byte("foo")}
   143  	allRevs := []revision{{main: 1}, {main: 2}, {main: 3}, {main: 4}, {main: 5}, {main: 6}}
   144  
   145  	ti := newTreeIndex()
   146  	for i := range allKeys {
   147  		ti.Put(allKeys[i], allRevs[i])
   148  	}
   149  
   150  	atRev := int64(1)
   151  	tests := []struct {
   152  		key, end []byte
   153  		wrevs    []revision
   154  	}{
   155  		// single key that not found
   156  		{
   157  			[]byte("bar"), nil, nil,
   158  		},
   159  		// single key that found
   160  		{
   161  			[]byte("foo"), nil, []revision{{main: 1}, {main: 6}},
   162  		},
   163  		// range keys, return first member
   164  		{
   165  			[]byte("foo"), []byte("foo1"), []revision{{main: 1}, {main: 6}},
   166  		},
   167  		// range keys, return first two members
   168  		{
   169  			[]byte("foo"), []byte("foo2"), []revision{{main: 1}, {main: 2}, {main: 5}, {main: 6}},
   170  		},
   171  		// range keys, return all members
   172  		{
   173  			[]byte("foo"), []byte("fop"), allRevs,
   174  		},
   175  		// range keys, return last two members
   176  		{
   177  			[]byte("foo1"), []byte("fop"), []revision{{main: 2}, {main: 3}, {main: 4}, {main: 5}},
   178  		},
   179  		// range keys, return last member
   180  		{
   181  			[]byte("foo2"), []byte("fop"), []revision{{main: 3}, {main: 4}},
   182  		},
   183  		// range keys, return nothing
   184  		{
   185  			[]byte("foo3"), []byte("fop"), nil,
   186  		},
   187  	}
   188  	for i, tt := range tests {
   189  		revs := ti.RangeSince(tt.key, tt.end, atRev)
   190  		if !reflect.DeepEqual(revs, tt.wrevs) {
   191  			t.Errorf("#%d: revs = %+v, want %+v", i, revs, tt.wrevs)
   192  		}
   193  	}
   194  }
   195  
   196  func TestIndexCompactAndKeep(t *testing.T) {
   197  	maxRev := int64(20)
   198  	tests := []struct {
   199  		key     []byte
   200  		remove  bool
   201  		rev     revision
   202  		created revision
   203  		ver     int64
   204  	}{
   205  		{[]byte("foo"), false, revision{main: 1}, revision{main: 1}, 1},
   206  		{[]byte("foo1"), false, revision{main: 2}, revision{main: 2}, 1},
   207  		{[]byte("foo2"), false, revision{main: 3}, revision{main: 3}, 1},
   208  		{[]byte("foo2"), false, revision{main: 4}, revision{main: 3}, 2},
   209  		{[]byte("foo"), false, revision{main: 5}, revision{main: 1}, 2},
   210  		{[]byte("foo1"), false, revision{main: 6}, revision{main: 2}, 2},
   211  		{[]byte("foo1"), true, revision{main: 7}, revision{}, 0},
   212  		{[]byte("foo2"), true, revision{main: 8}, revision{}, 0},
   213  		{[]byte("foo"), true, revision{main: 9}, revision{}, 0},
   214  		{[]byte("foo"), false, revision{10, 0}, revision{10, 0}, 1},
   215  		{[]byte("foo1"), false, revision{10, 1}, revision{10, 1}, 1},
   216  	}
   217  
   218  	// Continuous Compact and Keep
   219  	ti := newTreeIndex()
   220  	for _, tt := range tests {
   221  		if tt.remove {
   222  			ti.Tombstone(tt.key, tt.rev)
   223  		} else {
   224  			ti.Put(tt.key, tt.rev)
   225  		}
   226  	}
   227  	for i := int64(1); i < maxRev; i++ {
   228  		am := ti.Compact(i)
   229  		keep := ti.Keep(i)
   230  		if !(reflect.DeepEqual(am, keep)) {
   231  			t.Errorf("#%d: compact keep %v != Keep keep %v", i, am, keep)
   232  		}
   233  		wti := &treeIndex{tree: btree.New(32)}
   234  		for _, tt := range tests {
   235  			if _, ok := am[tt.rev]; ok || tt.rev.GreaterThan(revision{main: i}) {
   236  				if tt.remove {
   237  					wti.Tombstone(tt.key, tt.rev)
   238  				} else {
   239  					restore(wti, tt.key, tt.created, tt.rev, tt.ver)
   240  				}
   241  			}
   242  		}
   243  		if !ti.Equal(wti) {
   244  			t.Errorf("#%d: not equal ti", i)
   245  		}
   246  	}
   247  
   248  	// Once Compact and Keep
   249  	for i := int64(1); i < maxRev; i++ {
   250  		ti := newTreeIndex()
   251  		for _, tt := range tests {
   252  			if tt.remove {
   253  				ti.Tombstone(tt.key, tt.rev)
   254  			} else {
   255  				ti.Put(tt.key, tt.rev)
   256  			}
   257  		}
   258  		am := ti.Compact(i)
   259  		keep := ti.Keep(i)
   260  		if !(reflect.DeepEqual(am, keep)) {
   261  			t.Errorf("#%d: compact keep %v != Keep keep %v", i, am, keep)
   262  		}
   263  		wti := &treeIndex{tree: btree.New(32)}
   264  		for _, tt := range tests {
   265  			if _, ok := am[tt.rev]; ok || tt.rev.GreaterThan(revision{main: i}) {
   266  				if tt.remove {
   267  					wti.Tombstone(tt.key, tt.rev)
   268  				} else {
   269  					restore(wti, tt.key, tt.created, tt.rev, tt.ver)
   270  				}
   271  			}
   272  		}
   273  		if !ti.Equal(wti) {
   274  			t.Errorf("#%d: not equal ti", i)
   275  		}
   276  	}
   277  }
   278  
   279  func restore(ti *treeIndex, key []byte, created, modified revision, ver int64) {
   280  	keyi := &keyIndex{key: key}
   281  
   282  	ti.Lock()
   283  	defer ti.Unlock()
   284  	item := ti.tree.Get(keyi)
   285  	if item == nil {
   286  		keyi.restore(created, modified, ver)
   287  		ti.tree.ReplaceOrInsert(keyi)
   288  		return
   289  	}
   290  	okeyi := item.(*keyIndex)
   291  	okeyi.put(modified.main, modified.sub)
   292  }