index_test.go 7.6 KB

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