OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / syndtr / goleveldb / leveldb / cache / cache_test.go
1 // Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
2 // All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
6
7 package cache
8
9 import (
10         "math/rand"
11         "runtime"
12         "sync"
13         "sync/atomic"
14         "testing"
15         "time"
16         "unsafe"
17 )
18
19 type int32o int32
20
21 func (o *int32o) acquire() {
22         if atomic.AddInt32((*int32)(o), 1) != 1 {
23                 panic("BUG: invalid ref")
24         }
25 }
26
27 func (o *int32o) Release() {
28         if atomic.AddInt32((*int32)(o), -1) != 0 {
29                 panic("BUG: invalid ref")
30         }
31 }
32
33 type releaserFunc struct {
34         fn    func()
35         value Value
36 }
37
38 func (r releaserFunc) Release() {
39         if r.fn != nil {
40                 r.fn()
41         }
42 }
43
44 func set(c *Cache, ns, key uint64, value Value, charge int, relf func()) *Handle {
45         return c.Get(ns, key, func() (int, Value) {
46                 if relf != nil {
47                         return charge, releaserFunc{relf, value}
48                 }
49                 return charge, value
50         })
51 }
52
53 type cacheMapTestParams struct {
54         nobjects, nhandles, concurrent, repeat int
55 }
56
57 func TestCacheMap(t *testing.T) {
58         runtime.GOMAXPROCS(runtime.NumCPU())
59
60         var params []cacheMapTestParams
61         if testing.Short() {
62                 params = []cacheMapTestParams{
63                         {1000, 100, 20, 3},
64                         {10000, 300, 50, 10},
65                 }
66         } else {
67                 params = []cacheMapTestParams{
68                         {10000, 400, 50, 3},
69                         {100000, 1000, 100, 10},
70                 }
71         }
72
73         var (
74                 objects [][]int32o
75                 handles [][]unsafe.Pointer
76         )
77
78         for _, x := range params {
79                 objects = append(objects, make([]int32o, x.nobjects))
80                 handles = append(handles, make([]unsafe.Pointer, x.nhandles))
81         }
82
83         c := NewCache(nil)
84
85         wg := new(sync.WaitGroup)
86         var done int32
87
88         for ns, x := range params {
89                 for i := 0; i < x.concurrent; i++ {
90                         wg.Add(1)
91                         go func(ns, i, repeat int, objects []int32o, handles []unsafe.Pointer) {
92                                 defer wg.Done()
93                                 r := rand.New(rand.NewSource(time.Now().UnixNano()))
94
95                                 for j := len(objects) * repeat; j >= 0; j-- {
96                                         key := uint64(r.Intn(len(objects)))
97                                         h := c.Get(uint64(ns), key, func() (int, Value) {
98                                                 o := &objects[key]
99                                                 o.acquire()
100                                                 return 1, o
101                                         })
102                                         if v := h.Value().(*int32o); v != &objects[key] {
103                                                 t.Fatalf("#%d invalid value: want=%p got=%p", ns, &objects[key], v)
104                                         }
105                                         if objects[key] != 1 {
106                                                 t.Fatalf("#%d invalid object %d: %d", ns, key, objects[key])
107                                         }
108                                         if !atomic.CompareAndSwapPointer(&handles[r.Intn(len(handles))], nil, unsafe.Pointer(h)) {
109                                                 h.Release()
110                                         }
111                                 }
112                         }(ns, i, x.repeat, objects[ns], handles[ns])
113                 }
114
115                 go func(handles []unsafe.Pointer) {
116                         r := rand.New(rand.NewSource(time.Now().UnixNano()))
117
118                         for atomic.LoadInt32(&done) == 0 {
119                                 i := r.Intn(len(handles))
120                                 h := (*Handle)(atomic.LoadPointer(&handles[i]))
121                                 if h != nil && atomic.CompareAndSwapPointer(&handles[i], unsafe.Pointer(h), nil) {
122                                         h.Release()
123                                 }
124                                 time.Sleep(time.Millisecond)
125                         }
126                 }(handles[ns])
127         }
128
129         go func() {
130                 handles := make([]*Handle, 100000)
131                 for atomic.LoadInt32(&done) == 0 {
132                         for i := range handles {
133                                 handles[i] = c.Get(999999999, uint64(i), func() (int, Value) {
134                                         return 1, 1
135                                 })
136                         }
137                         for _, h := range handles {
138                                 h.Release()
139                         }
140                 }
141         }()
142
143         wg.Wait()
144
145         atomic.StoreInt32(&done, 1)
146
147         for _, handles0 := range handles {
148                 for i := range handles0 {
149                         h := (*Handle)(atomic.LoadPointer(&handles0[i]))
150                         if h != nil && atomic.CompareAndSwapPointer(&handles0[i], unsafe.Pointer(h), nil) {
151                                 h.Release()
152                         }
153                 }
154         }
155
156         for ns, objects0 := range objects {
157                 for i, o := range objects0 {
158                         if o != 0 {
159                                 t.Fatalf("invalid object #%d.%d: ref=%d", ns, i, o)
160                         }
161                 }
162         }
163 }
164
165 func TestCacheMap_NodesAndSize(t *testing.T) {
166         c := NewCache(nil)
167         if c.Nodes() != 0 {
168                 t.Errorf("invalid nodes counter: want=%d got=%d", 0, c.Nodes())
169         }
170         if c.Size() != 0 {
171                 t.Errorf("invalid size counter: want=%d got=%d", 0, c.Size())
172         }
173         set(c, 0, 1, 1, 1, nil)
174         set(c, 0, 2, 2, 2, nil)
175         set(c, 1, 1, 3, 3, nil)
176         set(c, 2, 1, 4, 1, nil)
177         if c.Nodes() != 4 {
178                 t.Errorf("invalid nodes counter: want=%d got=%d", 4, c.Nodes())
179         }
180         if c.Size() != 7 {
181                 t.Errorf("invalid size counter: want=%d got=%d", 4, c.Size())
182         }
183 }
184
185 func TestLRUCache_Capacity(t *testing.T) {
186         c := NewCache(NewLRU(10))
187         if c.Capacity() != 10 {
188                 t.Errorf("invalid capacity: want=%d got=%d", 10, c.Capacity())
189         }
190         set(c, 0, 1, 1, 1, nil).Release()
191         set(c, 0, 2, 2, 2, nil).Release()
192         set(c, 1, 1, 3, 3, nil).Release()
193         set(c, 2, 1, 4, 1, nil).Release()
194         set(c, 2, 2, 5, 1, nil).Release()
195         set(c, 2, 3, 6, 1, nil).Release()
196         set(c, 2, 4, 7, 1, nil).Release()
197         set(c, 2, 5, 8, 1, nil).Release()
198         if c.Nodes() != 7 {
199                 t.Errorf("invalid nodes counter: want=%d got=%d", 7, c.Nodes())
200         }
201         if c.Size() != 10 {
202                 t.Errorf("invalid size counter: want=%d got=%d", 10, c.Size())
203         }
204         c.SetCapacity(9)
205         if c.Capacity() != 9 {
206                 t.Errorf("invalid capacity: want=%d got=%d", 9, c.Capacity())
207         }
208         if c.Nodes() != 6 {
209                 t.Errorf("invalid nodes counter: want=%d got=%d", 6, c.Nodes())
210         }
211         if c.Size() != 8 {
212                 t.Errorf("invalid size counter: want=%d got=%d", 8, c.Size())
213         }
214 }
215
216 func TestCacheMap_NilValue(t *testing.T) {
217         c := NewCache(NewLRU(10))
218         h := c.Get(0, 0, func() (size int, value Value) {
219                 return 1, nil
220         })
221         if h != nil {
222                 t.Error("cache handle is non-nil")
223         }
224         if c.Nodes() != 0 {
225                 t.Errorf("invalid nodes counter: want=%d got=%d", 0, c.Nodes())
226         }
227         if c.Size() != 0 {
228                 t.Errorf("invalid size counter: want=%d got=%d", 0, c.Size())
229         }
230 }
231
232 func TestLRUCache_GetLatency(t *testing.T) {
233         runtime.GOMAXPROCS(runtime.NumCPU())
234
235         const (
236                 concurrentSet = 30
237                 concurrentGet = 3
238                 duration      = 3 * time.Second
239                 delay         = 3 * time.Millisecond
240                 maxkey        = 100000
241         )
242
243         var (
244                 set, getHit, getAll        int32
245                 getMaxLatency, getDuration int64
246         )
247
248         c := NewCache(NewLRU(5000))
249         wg := &sync.WaitGroup{}
250         until := time.Now().Add(duration)
251         for i := 0; i < concurrentSet; i++ {
252                 wg.Add(1)
253                 go func(i int) {
254                         defer wg.Done()
255                         r := rand.New(rand.NewSource(time.Now().UnixNano()))
256                         for time.Now().Before(until) {
257                                 c.Get(0, uint64(r.Intn(maxkey)), func() (int, Value) {
258                                         time.Sleep(delay)
259                                         atomic.AddInt32(&set, 1)
260                                         return 1, 1
261                                 }).Release()
262                         }
263                 }(i)
264         }
265         for i := 0; i < concurrentGet; i++ {
266                 wg.Add(1)
267                 go func(i int) {
268                         defer wg.Done()
269                         r := rand.New(rand.NewSource(time.Now().UnixNano()))
270                         for {
271                                 mark := time.Now()
272                                 if mark.Before(until) {
273                                         h := c.Get(0, uint64(r.Intn(maxkey)), nil)
274                                         latency := int64(time.Now().Sub(mark))
275                                         m := atomic.LoadInt64(&getMaxLatency)
276                                         if latency > m {
277                                                 atomic.CompareAndSwapInt64(&getMaxLatency, m, latency)
278                                         }
279                                         atomic.AddInt64(&getDuration, latency)
280                                         if h != nil {
281                                                 atomic.AddInt32(&getHit, 1)
282                                                 h.Release()
283                                         }
284                                         atomic.AddInt32(&getAll, 1)
285                                 } else {
286                                         break
287                                 }
288                         }
289                 }(i)
290         }
291
292         wg.Wait()
293         getAvglatency := time.Duration(getDuration) / time.Duration(getAll)
294         t.Logf("set=%d getHit=%d getAll=%d getMaxLatency=%v getAvgLatency=%v",
295                 set, getHit, getAll, time.Duration(getMaxLatency), getAvglatency)
296
297         if getAvglatency > delay/3 {
298                 t.Errorf("get avg latency > %v: got=%v", delay/3, getAvglatency)
299         }
300 }
301
302 func TestLRUCache_HitMiss(t *testing.T) {
303         cases := []struct {
304                 key   uint64
305                 value string
306         }{
307                 {1, "vvvvvvvvv"},
308                 {100, "v1"},
309                 {0, "v2"},
310                 {12346, "v3"},
311                 {777, "v4"},
312                 {999, "v5"},
313                 {7654, "v6"},
314                 {2, "v7"},
315                 {3, "v8"},
316                 {9, "v9"},
317         }
318
319         setfin := 0
320         c := NewCache(NewLRU(1000))
321         for i, x := range cases {
322                 set(c, 0, x.key, x.value, len(x.value), func() {
323                         setfin++
324                 }).Release()
325                 for j, y := range cases {
326                         h := c.Get(0, y.key, nil)
327                         if j <= i {
328                                 // should hit
329                                 if h == nil {
330                                         t.Errorf("case '%d' iteration '%d' is miss", i, j)
331                                 } else {
332                                         if x := h.Value().(releaserFunc).value.(string); x != y.value {
333                                                 t.Errorf("case '%d' iteration '%d' has invalid value got '%s', want '%s'", i, j, x, y.value)
334                                         }
335                                 }
336                         } else {
337                                 // should miss
338                                 if h != nil {
339                                         t.Errorf("case '%d' iteration '%d' is hit , value '%s'", i, j, h.Value().(releaserFunc).value.(string))
340                                 }
341                         }
342                         if h != nil {
343                                 h.Release()
344                         }
345                 }
346         }
347
348         for i, x := range cases {
349                 finalizerOk := false
350                 c.Delete(0, x.key, func() {
351                         finalizerOk = true
352                 })
353
354                 if !finalizerOk {
355                         t.Errorf("case %d delete finalizer not executed", i)
356                 }
357
358                 for j, y := range cases {
359                         h := c.Get(0, y.key, nil)
360                         if j > i {
361                                 // should hit
362                                 if h == nil {
363                                         t.Errorf("case '%d' iteration '%d' is miss", i, j)
364                                 } else {
365                                         if x := h.Value().(releaserFunc).value.(string); x != y.value {
366                                                 t.Errorf("case '%d' iteration '%d' has invalid value got '%s', want '%s'", i, j, x, y.value)
367                                         }
368                                 }
369                         } else {
370                                 // should miss
371                                 if h != nil {
372                                         t.Errorf("case '%d' iteration '%d' is hit, value '%s'", i, j, h.Value().(releaserFunc).value.(string))
373                                 }
374                         }
375                         if h != nil {
376                                 h.Release()
377                         }
378                 }
379         }
380
381         if setfin != len(cases) {
382                 t.Errorf("some set finalizer may not be executed, want=%d got=%d", len(cases), setfin)
383         }
384 }
385
386 func TestLRUCache_Eviction(t *testing.T) {
387         c := NewCache(NewLRU(12))
388         o1 := set(c, 0, 1, 1, 1, nil)
389         set(c, 0, 2, 2, 1, nil).Release()
390         set(c, 0, 3, 3, 1, nil).Release()
391         set(c, 0, 4, 4, 1, nil).Release()
392         set(c, 0, 5, 5, 1, nil).Release()
393         if h := c.Get(0, 2, nil); h != nil { // 1,3,4,5,2
394                 h.Release()
395         }
396         set(c, 0, 9, 9, 10, nil).Release() // 5,2,9
397
398         for _, key := range []uint64{9, 2, 5, 1} {
399                 h := c.Get(0, key, nil)
400                 if h == nil {
401                         t.Errorf("miss for key '%d'", key)
402                 } else {
403                         if x := h.Value().(int); x != int(key) {
404                                 t.Errorf("invalid value for key '%d' want '%d', got '%d'", key, key, x)
405                         }
406                         h.Release()
407                 }
408         }
409         o1.Release()
410         for _, key := range []uint64{1, 2, 5} {
411                 h := c.Get(0, key, nil)
412                 if h == nil {
413                         t.Errorf("miss for key '%d'", key)
414                 } else {
415                         if x := h.Value().(int); x != int(key) {
416                                 t.Errorf("invalid value for key '%d' want '%d', got '%d'", key, key, x)
417                         }
418                         h.Release()
419                 }
420         }
421         for _, key := range []uint64{3, 4, 9} {
422                 h := c.Get(0, key, nil)
423                 if h != nil {
424                         t.Errorf("hit for key '%d'", key)
425                         if x := h.Value().(int); x != int(key) {
426                                 t.Errorf("invalid value for key '%d' want '%d', got '%d'", key, key, x)
427                         }
428                         h.Release()
429                 }
430         }
431 }
432
433 func TestLRUCache_Evict(t *testing.T) {
434         c := NewCache(NewLRU(6))
435         set(c, 0, 1, 1, 1, nil).Release()
436         set(c, 0, 2, 2, 1, nil).Release()
437         set(c, 1, 1, 4, 1, nil).Release()
438         set(c, 1, 2, 5, 1, nil).Release()
439         set(c, 2, 1, 6, 1, nil).Release()
440         set(c, 2, 2, 7, 1, nil).Release()
441
442         for ns := 0; ns < 3; ns++ {
443                 for key := 1; key < 3; key++ {
444                         if h := c.Get(uint64(ns), uint64(key), nil); h != nil {
445                                 h.Release()
446                         } else {
447                                 t.Errorf("Cache.Get on #%d.%d return nil", ns, key)
448                         }
449                 }
450         }
451
452         if ok := c.Evict(0, 1); !ok {
453                 t.Error("first Cache.Evict on #0.1 return false")
454         }
455         if ok := c.Evict(0, 1); ok {
456                 t.Error("second Cache.Evict on #0.1 return true")
457         }
458         if h := c.Get(0, 1, nil); h != nil {
459                 t.Errorf("Cache.Get on #0.1 return non-nil: %v", h.Value())
460         }
461
462         c.EvictNS(1)
463         if h := c.Get(1, 1, nil); h != nil {
464                 t.Errorf("Cache.Get on #1.1 return non-nil: %v", h.Value())
465         }
466         if h := c.Get(1, 2, nil); h != nil {
467                 t.Errorf("Cache.Get on #1.2 return non-nil: %v", h.Value())
468         }
469
470         c.EvictAll()
471         for ns := 0; ns < 3; ns++ {
472                 for key := 1; key < 3; key++ {
473                         if h := c.Get(uint64(ns), uint64(key), nil); h != nil {
474                                 t.Errorf("Cache.Get on #%d.%d return non-nil: %v", ns, key, h.Value())
475                         }
476                 }
477         }
478 }
479
480 func TestLRUCache_Delete(t *testing.T) {
481         delFuncCalled := 0
482         delFunc := func() {
483                 delFuncCalled++
484         }
485
486         c := NewCache(NewLRU(2))
487         set(c, 0, 1, 1, 1, nil).Release()
488         set(c, 0, 2, 2, 1, nil).Release()
489
490         if ok := c.Delete(0, 1, delFunc); !ok {
491                 t.Error("Cache.Delete on #1 return false")
492         }
493         if h := c.Get(0, 1, nil); h != nil {
494                 t.Errorf("Cache.Get on #1 return non-nil: %v", h.Value())
495         }
496         if ok := c.Delete(0, 1, delFunc); ok {
497                 t.Error("Cache.Delete on #1 return true")
498         }
499
500         h2 := c.Get(0, 2, nil)
501         if h2 == nil {
502                 t.Error("Cache.Get on #2 return nil")
503         }
504         if ok := c.Delete(0, 2, delFunc); !ok {
505                 t.Error("(1) Cache.Delete on #2 return false")
506         }
507         if ok := c.Delete(0, 2, delFunc); !ok {
508                 t.Error("(2) Cache.Delete on #2 return false")
509         }
510
511         set(c, 0, 3, 3, 1, nil).Release()
512         set(c, 0, 4, 4, 1, nil).Release()
513         c.Get(0, 2, nil).Release()
514
515         for key := 2; key <= 4; key++ {
516                 if h := c.Get(0, uint64(key), nil); h != nil {
517                         h.Release()
518                 } else {
519                         t.Errorf("Cache.Get on #%d return nil", key)
520                 }
521         }
522
523         h2.Release()
524         if h := c.Get(0, 2, nil); h != nil {
525                 t.Errorf("Cache.Get on #2 return non-nil: %v", h.Value())
526         }
527
528         if delFuncCalled != 4 {
529                 t.Errorf("delFunc isn't called 4 times: got=%d", delFuncCalled)
530         }
531 }
532
533 func TestLRUCache_Close(t *testing.T) {
534         relFuncCalled := 0
535         relFunc := func() {
536                 relFuncCalled++
537         }
538         delFuncCalled := 0
539         delFunc := func() {
540                 delFuncCalled++
541         }
542
543         c := NewCache(NewLRU(2))
544         set(c, 0, 1, 1, 1, relFunc).Release()
545         set(c, 0, 2, 2, 1, relFunc).Release()
546
547         h3 := set(c, 0, 3, 3, 1, relFunc)
548         if h3 == nil {
549                 t.Error("Cache.Get on #3 return nil")
550         }
551         if ok := c.Delete(0, 3, delFunc); !ok {
552                 t.Error("Cache.Delete on #3 return false")
553         }
554
555         c.Close()
556
557         if relFuncCalled != 3 {
558                 t.Errorf("relFunc isn't called 3 times: got=%d", relFuncCalled)
559         }
560         if delFuncCalled != 1 {
561                 t.Errorf("delFunc isn't called 1 times: got=%d", delFuncCalled)
562         }
563 }