Merge branch 'master' into 5682-download-file-error
[arvados.git] / services / keepstore / bufferpool_test.go
1 package main
2
3 import (
4         . "gopkg.in/check.v1"
5         "testing"
6         "time"
7 )
8
9 // Gocheck boilerplate
10 func TestBufferPool(t *testing.T) {
11         TestingT(t)
12 }
13 var _ = Suite(&BufferPoolSuite{})
14 type BufferPoolSuite struct {}
15
16 // Initialize a default-sized buffer pool for the benefit of test
17 // suites that don't run main().
18 func init() {
19         bufs = newBufferPool(maxBuffers, BLOCKSIZE)
20 }
21
22 func (s *BufferPoolSuite) TestBufferPoolBufSize(c *C) {
23         bufs := newBufferPool(2, 10)
24         b1 := bufs.Get(1)
25         bufs.Get(2)
26         bufs.Put(b1)
27         b3 := bufs.Get(3)
28         c.Check(len(b3), Equals, 3)
29 }
30
31 func (s *BufferPoolSuite) TestBufferPoolUnderLimit(c *C) {
32         bufs := newBufferPool(3, 10)
33         b1 := bufs.Get(10)
34         bufs.Get(10)
35         testBufferPoolRace(c, bufs, b1, "Get")
36 }
37
38 func (s *BufferPoolSuite) TestBufferPoolAtLimit(c *C) {
39         bufs := newBufferPool(2, 10)
40         b1 := bufs.Get(10)
41         bufs.Get(10)
42         testBufferPoolRace(c, bufs, b1, "Put")
43 }
44
45 func testBufferPoolRace(c *C, bufs *bufferPool, unused []byte, expectWin string) {
46         race := make(chan string)
47         go func() {
48                 bufs.Get(10)
49                 time.Sleep(time.Millisecond)
50                 race <- "Get"
51         }()
52         go func() {
53                 time.Sleep(10*time.Millisecond)
54                 bufs.Put(unused)
55                 race <- "Put"
56         }()
57         c.Check(<-race, Equals, expectWin)
58         c.Check(<-race, Not(Equals), expectWin)
59         close(race)
60 }
61
62 func (s *BufferPoolSuite) TestBufferPoolReuse(c *C) {
63         bufs := newBufferPool(2, 10)
64         bufs.Get(10)
65         last := bufs.Get(10)
66         // The buffer pool is allowed to throw away unused buffers
67         // (e.g., during sync.Pool's garbage collection hook, in the
68         // the current implementation). However, if unused buffers are
69         // getting thrown away and reallocated more than {arbitrary
70         // frequency threshold} during a busy loop, it's not acting
71         // much like a buffer pool.
72         allocs := 1000
73         reuses := 0
74         for i := 0; i < allocs; i++ {
75                 bufs.Put(last)
76                 next := bufs.Get(10)
77                 copy(last, []byte("last"))
78                 copy(next, []byte("next"))
79                 if last[0] == 'n' {
80                         reuses++
81                 }
82                 last = next
83         }
84         c.Check(reuses > allocs * 95/100, Equals, true)
85 }