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