21846: applied select to context menu open
[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 keepstore
6
7 import (
8         "time"
9
10         "git.arvados.org/arvados.git/sdk/go/ctxlog"
11         "github.com/prometheus/client_golang/prometheus"
12         . "gopkg.in/check.v1"
13 )
14
15 var _ = Suite(&BufferPoolSuite{})
16
17 var bufferPoolTestSize = 10
18
19 type BufferPoolSuite struct{}
20
21 func (s *BufferPoolSuite) SetUpTest(c *C) {
22         bufferPoolBlockSize = bufferPoolTestSize
23 }
24
25 func (s *BufferPoolSuite) TearDownTest(c *C) {
26         bufferPoolBlockSize = BlockSize
27 }
28
29 func (s *BufferPoolSuite) TestBufferPoolBufSize(c *C) {
30         bufs := newBufferPool(ctxlog.TestLogger(c), 2, prometheus.NewRegistry())
31         b1 := bufs.Get()
32         bufs.Get()
33         bufs.Put(b1)
34         b3 := bufs.Get()
35         c.Check(len(b3), Equals, bufferPoolTestSize)
36 }
37
38 func (s *BufferPoolSuite) TestBufferPoolUnderLimit(c *C) {
39         bufs := newBufferPool(ctxlog.TestLogger(c), 3, prometheus.NewRegistry())
40         b1 := bufs.Get()
41         bufs.Get()
42         testBufferPoolRace(c, bufs, b1, "Get")
43 }
44
45 func (s *BufferPoolSuite) TestBufferPoolAtLimit(c *C) {
46         bufs := newBufferPool(ctxlog.TestLogger(c), 2, prometheus.NewRegistry())
47         b1 := bufs.Get()
48         bufs.Get()
49         testBufferPoolRace(c, bufs, b1, "Put")
50 }
51
52 func testBufferPoolRace(c *C, bufs *bufferPool, unused []byte, expectWin string) {
53         race := make(chan string)
54         go func() {
55                 bufs.Get()
56                 time.Sleep(time.Millisecond)
57                 race <- "Get"
58         }()
59         go func() {
60                 time.Sleep(10 * time.Millisecond)
61                 bufs.Put(unused)
62                 race <- "Put"
63         }()
64         c.Check(<-race, Equals, expectWin)
65         c.Check(<-race, Not(Equals), expectWin)
66         close(race)
67 }
68
69 func (s *BufferPoolSuite) TestBufferPoolReuse(c *C) {
70         bufs := newBufferPool(ctxlog.TestLogger(c), 2, prometheus.NewRegistry())
71         bufs.Get()
72         last := bufs.Get()
73         // The buffer pool is allowed to throw away unused buffers
74         // (e.g., during sync.Pool's garbage collection hook, in the
75         // the current implementation). However, if unused buffers are
76         // getting thrown away and reallocated more than {arbitrary
77         // frequency threshold} during a busy loop, it's not acting
78         // much like a buffer pool.
79         allocs := 1000
80         reuses := 0
81         for i := 0; i < allocs; i++ {
82                 bufs.Put(last)
83                 next := bufs.Get()
84                 copy(last, []byte("last"))
85                 copy(next, []byte("next"))
86                 if last[0] == 'n' {
87                         reuses++
88                 }
89                 last = next
90         }
91         c.Check(reuses > allocs*95/100, Equals, true)
92 }