1 | /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
2 | #ident "$Id$" |
3 | /*====== |
4 | This file is part of PerconaFT. |
5 | |
6 | |
7 | Copyright (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 | |
44 | namespace 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 | |