index_test.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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 TestIndexCompact(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
  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. wti := &treeIndex{tree: btree.New(32)}
  213. for _, tt := range tests {
  214. if _, ok := am[tt.rev]; ok || tt.rev.GreaterThan(revision{main: i}) {
  215. if tt.remove {
  216. wti.Tombstone(tt.key, tt.rev)
  217. } else {
  218. restore(wti, tt.key, tt.created, tt.rev, tt.ver)
  219. }
  220. }
  221. }
  222. if !ti.Equal(wti) {
  223. t.Errorf("#%d: not equal ti", i)
  224. }
  225. }
  226. // Once Compact
  227. for i := int64(1); i < maxRev; i++ {
  228. ti := newTreeIndex()
  229. for _, tt := range tests {
  230. if tt.remove {
  231. ti.Tombstone(tt.key, tt.rev)
  232. } else {
  233. ti.Put(tt.key, tt.rev)
  234. }
  235. }
  236. am := ti.Compact(i)
  237. wti := &treeIndex{tree: btree.New(32)}
  238. for _, tt := range tests {
  239. if _, ok := am[tt.rev]; ok || tt.rev.GreaterThan(revision{main: i}) {
  240. if tt.remove {
  241. wti.Tombstone(tt.key, tt.rev)
  242. } else {
  243. restore(wti, tt.key, tt.created, tt.rev, tt.ver)
  244. }
  245. }
  246. }
  247. if !ti.Equal(wti) {
  248. t.Errorf("#%d: not equal ti", i)
  249. }
  250. }
  251. }
  252. func restore(ti *treeIndex, key []byte, created, modified revision, ver int64) {
  253. keyi := &keyIndex{key: key}
  254. ti.Lock()
  255. defer ti.Unlock()
  256. item := ti.tree.Get(keyi)
  257. if item == nil {
  258. keyi.restore(created, modified, ver)
  259. ti.tree.ReplaceOrInsert(keyi)
  260. return
  261. }
  262. okeyi := item.(*keyIndex)
  263. okeyi.put(modified.main, modified.sub)
  264. }