1/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2#ident "$Id$"
3/*======
4This file is part of PerconaFT.
5
6
7Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
8
9 PerconaFT is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License, version 2,
11 as published by the Free Software Foundation.
12
13 PerconaFT is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>.
20
21----------------------------------------
22
23 PerconaFT is free software: you can redistribute it and/or modify
24 it under the terms of the GNU Affero General Public License, version 3,
25 as published by the Free Software Foundation.
26
27 PerconaFT is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU Affero General Public License for more details.
31
32 You should have received a copy of the GNU Affero General Public License
33 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>.
34======= */
35
36#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
37
38#pragma once
39
40#include <algorithm>
41#include <cstdlib>
42#include <memory>
43
44namespace ftcxx {
45
46 /**
47 * Buffer implements a flat memory buffer intended for FIFO usage
48 * where allocations are piecemeal but consumption is total. That is,
49 * we repeatedly fill up the buffer with small allocations, and
50 * periodically consume all entries and clear the buffer.
51 *
52 * For now, the implementation uses a doubling array strategy,
53 * starting at 1kB growing to a maximum advised capacity of 256kB,
54 * never shrinking the buffer.
55 *
56 * However, we hope to find a better strategy.
57 *
58 * Facebook's FBVector claims that a reallocation growth factor of 1.5
59 * rather than 2 hits their sweet spot, and they claim to have
60 * additional improvements by integrating with jemalloc (which we use
61 * as well).
62 *
63 * Additionally, it may be advantageous to use some memarena-style
64 * tricks like allocating a separate overflow buffer to avoid
65 * memcpying when we're close to our intended maximum capacity, and
66 * also to avoid wasting extra memory if we overflow our maximum
67 * capacity once but never do so again.
68 */
69 class Buffer {
70 public:
71
72 Buffer();
73
74 explicit Buffer(size_t capacity);
75
76 Buffer(const Buffer &) = delete;
77 Buffer& operator=(const Buffer &) = delete;
78
79 Buffer(Buffer&& other)
80 : _cur(0),
81 _end(0),
82 _capacity(0),
83 _buf(nullptr, &std::free)
84 {
85 std::swap(_cur, other._cur);
86 std::swap(_end, other._end);
87 std::swap(_capacity, other._capacity);
88 std::swap(_buf, other._buf);
89 }
90
91 Buffer& operator=(Buffer&& other) {
92 std::swap(_cur, other._cur);
93 std::swap(_end, other._end);
94 std::swap(_capacity, other._capacity);
95 std::swap(_buf, other._buf);
96 return *this;
97 }
98
99 // Producer API:
100
101 /**
102 * Allocate room for sz more bytes at the end, and return a
103 * pointer to the allocated space. This causes at most one
104 * realloc and memcpy of existing data.
105 */
106 char *alloc(size_t sz);
107
108 /**
109 * Returns true if we're close to our maximum capacity. If so,
110 * the producer should stop and allow the consumer to clear the
111 * buffer.
112 */
113 bool full() const;
114
115 // Consumer API:
116
117 /**
118 * Returns true if there are more unconsumed bytes in the buffer.
119 */
120 bool more() const;
121
122 /**
123 * Returns a pointer to the next unconsumed byte in the buffer.
124 */
125 char *current() const;
126
127 /**
128 * Advances the unconsumed position pointer by sz bytes.
129 */
130 void advance(size_t sz);
131
132 /**
133 * Free all allocated space.
134 */
135 void clear();
136
137 private:
138
139 size_t _cur;
140 size_t _end;
141 size_t _capacity;
142 std::unique_ptr<char, void (*)(void*)> _buf;
143
144 static const size_t INITIAL_CAPACITY;
145 static const size_t MAXIMUM_CAPACITY;
146 static const double FULLNESS_RATIO;
147
148 void init();
149
150 static size_t next_alloc_size(size_t sz);
151
152 void grow(size_t sz);
153
154 char *raw(size_t i=0) const {
155 return &(_buf.get()[i]);
156 }
157 };
158
159} // namespace ftcxx
160