Merge branch '8784-dir-listings'
[arvados.git] / services / keepstore / bufferpool_test.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package main
6
7 import (
8         . "gopkg.in/check.v1"
9         "time"
10 )
11
12 var _ = Suite(&BufferPoolSuite{})
13
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(theConfig.MaxBuffers, BlockSize)
20 }
21
22 // Restore sane default after bufferpool's own tests
23 func (s *BufferPoolSuite) TearDownTest(c *C) {
24         bufs = newBufferPool(theConfig.MaxBuffers, BlockSize)
25 }
26
27 func (s *BufferPoolSuite) TestBufferPoolBufSize(c *C) {
28         bufs := newBufferPool(2, 10)
29         b1 := bufs.Get(1)
30         bufs.Get(2)
31         bufs.Put(b1)
32         b3 := bufs.Get(3)
33         c.Check(len(b3), Equals, 3)
34 }
35
36 func (s *BufferPoolSuite) TestBufferPoolUnderLimit(c *C) {
37         bufs := newBufferPool(3, 10)
38         b1 := bufs.Get(10)
39         bufs.Get(10)
40         testBufferPoolRace(c, bufs, b1, "Get")
41 }
42
43 func (s *BufferPoolSuite) TestBufferPoolAtLimit(c *C) {
44         bufs := newBufferPool(2, 10)
45         b1 := bufs.Get(10)
46         bufs.Get(10)
47         testBufferPoolRace(c, bufs, b1, "Put")
48 }
49
50 func testBufferPoolRace(c *C, bufs *bufferPool, unused []byte, expectWin string) {
51         race := make(chan string)
52         go func() {
53                 bufs.Get(10)
54                 time.Sleep(time.Millisecond)
55                 race <- "Get"
56         }()
57         go func() {
58                 time.Sleep(10 * time.Millisecond)
59                 bufs.Put(unused)
60                 race <- "Put"
61         }()
62         c.Check(<-race, Equals, expectWin)
63         c.Check(<-race, Not(Equals), expectWin)
64         close(race)
65 }
66
67 func (s *BufferPoolSuite) TestBufferPoolReuse(c *C) {
68         bufs := newBufferPool(2, 10)
69         bufs.Get(10)
70         last := bufs.Get(10)
71         // The buffer pool is allowed to throw away unused buffers
72         // (e.g., during sync.Pool's garbage collection hook, in the
73         // the current implementation). However, if unused buffers are
74         // getting thrown away and reallocated more than {arbitrary
75         // frequency threshold} during a busy loop, it's not acting
76         // much like a buffer pool.
77         allocs := 1000
78         reuses := 0
79         for i := 0; i < allocs; i++ {
80                 bufs.Put(last)
81                 next := bufs.Get(10)
82                 copy(last, []byte("last"))
83                 copy(next, []byte("next"))
84                 if last[0] == 'n' {
85                         reuses++
86                 }
87                 last = next
88         }
89         c.Check(reuses > allocs*95/100, Equals, true)
90 }