MySQL  8.0.12
Source Code Documentation
dyn0buf.h
Go to the documentation of this file.
1 /*
2  Copyright (c) 2013, 2018, Oracle and/or its affiliates. All Rights Reserved.
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24  The lines above are intentionally left blank
25 */
26 
27 /** @file include/dyn0buf.h
28  The dynamically allocated buffer implementation
29 
30  Created 2013-03-16 Sunny Bains
31  *******************************************************/
32 
33 #ifndef dyn0buf_h
34 #define dyn0buf_h
35 
36 #include "dyn0types.h"
37 #include "mem0mem.h"
38 #include "univ.i"
39 #include "ut0lst.h"
40 
41 /** Class that manages dynamic buffers. It uses a UT_LIST of
42 dyn_buf_t::block_t instances. We don't use STL containers in
43 order to avoid the overhead of heap calls. Using a custom memory
44 allocator doesn't solve the problem either because we have to get
45 the memory from somewhere. We can't use the block_t::m_data as the
46 backend for the custom allocator because we would like the data in
47 the blocks to be contiguous. */
48 template <size_t SIZE = DYN_ARRAY_DATA_SIZE>
49 class dyn_buf_t {
50  public:
51  class block_t;
52 
53  typedef UT_LIST_NODE_T(block_t) block_node_t;
54  typedef UT_LIST_BASE_NODE_T(block_t) block_list_t;
55 
56  class block_t {
57  public:
58  block_t() {
59  ut_ad(MAX_DATA_SIZE <= (2 << 15));
60  init();
61  }
62 
63  ~block_t() {}
64 
65  /**
66  Gets the number of used bytes in a block.
67  @return number of bytes used */
68  ulint used() const MY_ATTRIBUTE((warn_unused_result)) {
69  return (static_cast<ulint>(m_used & ~DYN_BLOCK_FULL_FLAG));
70  }
71 
72  /**
73  Gets pointer to the start of data.
74  @return pointer to data */
75  byte *start() MY_ATTRIBUTE((warn_unused_result)) { return (m_data); }
76 
77  /**
78  @return start of data - non const version */
79  byte *begin() MY_ATTRIBUTE((warn_unused_result)) { return (m_data); }
80 
81  /**
82  @return end of used data - non const version */
83  byte *end() MY_ATTRIBUTE((warn_unused_result)) {
84  return (begin() + m_used);
85  }
86 
87  /**
88  @return start of data - const version */
89  const byte *begin() const MY_ATTRIBUTE((warn_unused_result)) {
90  return (m_data);
91  }
92 
93  /**
94  @return end of used data - const version */
95  const byte *end() const MY_ATTRIBUTE((warn_unused_result)) {
96  return (begin() + m_used);
97  }
98 
99  private:
100  /**
101  @return pointer to start of reserved space */
102  template <typename Type>
103  Type push(ib_uint32_t size) {
104  Type ptr = reinterpret_cast<Type>(end());
105 
106  m_used += size;
107  ut_ad(m_used <= static_cast<ib_uint32_t>(MAX_DATA_SIZE));
108 
109  return (ptr);
110  }
111 
112  /**
113  Grow the stack. */
114  void close(const byte *ptr) {
115  /* Check that it is within bounds */
116  ut_ad(ptr >= begin());
117  ut_ad(ptr <= begin() + m_buf_end);
118 
119  /* We have done the boundary check above */
120  m_used = static_cast<ib_uint32_t>(ptr - begin());
121 
123  ut_d(m_buf_end = 0);
124  }
125 
126  /**
127  Initialise the block */
128  void init() {
129  m_used = 0;
130  ut_d(m_buf_end = 0);
132  }
133 
134  private:
135 #ifdef UNIV_DEBUG
136  /** If opened then this is the buffer end offset, else 0 */
137  ulint m_buf_end;
138 
139  /** Magic number (DYN_BLOCK_MAGIC_N) */
140  ulint m_magic_n;
141 #endif /* UNIV_DEBUG */
142 
143  /** SIZE - sizeof(m_node) + sizeof(m_used) */
144  enum { MAX_DATA_SIZE = SIZE - sizeof(block_node_t) + sizeof(ib_uint32_t) };
145 
146  /** Storage */
148 
149  /** Doubly linked list node. */
150  block_node_t m_node;
151 
152  /** number of data bytes used in this block;
153  DYN_BLOCK_FULL_FLAG is set when the block becomes full */
154  ib_uint32_t m_used;
155 
156  friend class dyn_buf_t;
157  };
158 
160 
161  /** Default constructor */
165  }
166 
167  /** Destructor */
168  ~dyn_buf_t() { erase(); }
169 
170  /** Reset the buffer vector */
171  void erase() {
172  if (m_heap != NULL) {
174  m_heap = NULL;
175 
176  /* Initialise the list and add the first block. */
179  } else {
182  }
183 
184  m_size = 0;
185  }
186 
187  /**
188  Makes room on top and returns a pointer to a buffer in it. After
189  copying the elements, the caller must close the buffer using close().
190  @param size in bytes of the buffer; MUST be <= MAX_DATA_SIZE!
191  @return pointer to the buffer */
192  byte *open(ulint size) MY_ATTRIBUTE((warn_unused_result)) {
193  ut_ad(size > 0);
195 
196  block_t *block;
197 
198  block = has_space(size) ? back() : add_block();
199 
200  ut_ad(block->m_used <= MAX_DATA_SIZE);
201  ut_d(block->m_buf_end = block->m_used + size);
202 
203  return (block->end());
204  }
205 
206  /**
207  Closes the buffer returned by open.
208  @param ptr end of used space */
209  void close(const byte *ptr) {
211  block_t *block = back();
212 
213  m_size -= block->used();
214 
215  block->close(ptr);
216 
217  m_size += block->used();
218  }
219 
220  /**
221  Makes room on top and returns a pointer to the added element.
222  The caller must copy the element to the pointer returned.
223  @param size in bytes of the element
224  @return pointer to the element */
225  template <typename Type>
226  Type push(ib_uint32_t size) {
227  ut_ad(size > 0);
228  ut_ad(size <= MAX_DATA_SIZE);
229 
230  block_t *block;
231 
232  block = has_space(size) ? back() : add_block();
233 
234  m_size += size;
235 
236  /* See ISO C++03 14.2/4 for why "template" is required. */
237 
238  return (block->template push<Type>(size));
239  }
240 
241  /**
242  Pushes n bytes.
243  @param ptr string to write
244  @param len string length */
245  void push(const byte *ptr, ib_uint32_t len) {
246  while (len > 0) {
247  ib_uint32_t n_copied;
248 
249  if (len >= MAX_DATA_SIZE) {
250  n_copied = MAX_DATA_SIZE;
251  } else {
252  n_copied = len;
253  }
254 
255  ::memmove(push<byte *>(n_copied), ptr, n_copied);
256 
257  ptr += n_copied;
258  len -= n_copied;
259  }
260  }
261 
262  /**
263  Returns a pointer to an element in the buffer. const version.
264  @param pos position of element in bytes from start
265  @return pointer to element */
266  template <typename Type>
267  const Type at(ulint pos) const {
268  block_t *block =
269  const_cast<block_t *>(const_cast<dyn_buf_t *>(this)->find(pos));
270 
271  return (reinterpret_cast<Type>(block->begin() + pos));
272  }
273 
274  /**
275  Returns a pointer to an element in the buffer. non const version.
276  @param pos position of element in bytes from start
277  @return pointer to element */
278  template <typename Type>
279  Type at(ulint pos) {
280  block_t *block = const_cast<block_t *>(find(pos));
281 
282  return (reinterpret_cast<Type>(block->begin() + pos));
283  }
284 
285  /**
286  Returns the size of the total stored data.
287  @return data size in bytes */
288  ulint size() const MY_ATTRIBUTE((warn_unused_result)) {
289 #ifdef UNIV_DEBUG
290  ulint total_size = 0;
291 
292  for (const block_t *block = UT_LIST_GET_FIRST(m_list); block != NULL;
293  block = UT_LIST_GET_NEXT(m_node, block)) {
294  total_size += block->used();
295  }
296 
297  ut_ad(total_size == m_size);
298 #endif /* UNIV_DEBUG */
299  return (m_size);
300  }
301 
302  /**
303  Iterate over each block and call the functor.
304  @return false if iteration was terminated. */
305  template <typename Functor>
306  bool for_each_block(Functor &functor) const {
307  for (const block_t *block = UT_LIST_GET_FIRST(m_list); block != NULL;
308  block = UT_LIST_GET_NEXT(m_node, block)) {
309  if (!functor(block)) {
310  return (false);
311  }
312  }
313 
314  return (true);
315  }
316 
317  /**
318  Iterate over all the blocks in reverse and call the iterator
319  @return false if iteration was terminated. */
320  template <typename Functor>
321  bool for_each_block_in_reverse(Functor &functor) const {
322  for (block_t *block = UT_LIST_GET_LAST(m_list); block != NULL;
323  block = UT_LIST_GET_PREV(m_node, block)) {
324  if (!functor(block)) {
325  return (false);
326  }
327  }
328 
329  return (true);
330  }
331 
332  /**
333  @return the first block */
334  block_t *front() MY_ATTRIBUTE((warn_unused_result)) {
336  return (UT_LIST_GET_FIRST(m_list));
337  }
338 
339  /**
340  @return true if m_first_block block was not filled fully */
341  bool is_small() const MY_ATTRIBUTE((warn_unused_result)) {
342  return (m_heap == NULL);
343  }
344 
345  private:
346  // Disable copying
347  dyn_buf_t(const dyn_buf_t &);
348  dyn_buf_t &operator=(const dyn_buf_t &);
349 
350  /**
351  Add the block to the end of the list*/
352  void push_back(block_t *block) {
353  block->init();
354 
355  UT_LIST_ADD_LAST(m_list, block);
356  }
357 
358  /** @return the last block in the list */
360 
361  /*
362  @return true if request can be fullfilled */
363  bool has_space(ulint size) const {
364  return (back()->m_used + size <= MAX_DATA_SIZE);
365  }
366 
367  /*
368  @return true if request can be fullfilled */
369  bool has_space(ulint size) {
370  return (back()->m_used + size <= MAX_DATA_SIZE);
371  }
372 
373  /** Find the block that contains the pos.
374  @param pos absolute offset, it is updated to make it relative
375  to the block
376  @return the block containing the pos. */
377  block_t *find(ulint &pos) {
378  block_t *block;
379 
381 
382  for (block = UT_LIST_GET_FIRST(m_list); block != NULL;
383  block = UT_LIST_GET_NEXT(m_node, block)) {
384  if (pos < block->used()) {
385  break;
386  }
387 
388  pos -= block->used();
389  }
390 
391  ut_ad(block != NULL);
392  ut_ad(block->used() >= pos);
393 
394  return (block);
395  }
396 
397  /**
398  Allocate and add a new block to m_list */
400  block_t *block;
401 
402  if (m_heap == NULL) {
403  m_heap = mem_heap_create(sizeof(*block));
404  }
405 
406  block = reinterpret_cast<block_t *>(mem_heap_alloc(m_heap, sizeof(*block)));
407 
408  push_back(block);
409 
410  return (block);
411  }
412 
413  private:
414  /** Heap to use for memory allocation */
416 
417  /** Allocated blocks */
418  block_list_t m_list;
419 
420  /** Total size used by all blocks */
421  ulint m_size;
422 
423  /** The default block, should always be the first element. This
424  is for backwards compatibility and to avoid an extra heap allocation
425  for small REDO log records */
427 };
428 
430 
431 /** mtr_buf_t copier */
433  /** The copied buffer */
434  mtr_buf_t m_buf;
435 
436  /** Append a block to the redo log buffer.
437  @return whether the appending should continue (always true here) */
438  bool operator()(const mtr_buf_t::block_t *block) {
439  byte *buf = m_buf.open(block->used());
440  memcpy(buf, block->begin(), block->used());
441  m_buf.close(buf + block->used());
442  return (true);
443  }
444 };
445 
446 #endif /* dyn0buf_h */
The dynamically allocated buffer types and constants.
unsigned char byte
Blob class.
Definition: common.h:159
void close(const byte *ptr)
Closes the buffer returned by open.
Definition: dyn0buf.h:209
ib_uint32_t m_used
number of data bytes used in this block; DYN_BLOCK_FULL_FLAG is set when the block becomes full ...
Definition: dyn0buf.h:154
t pos
Definition: dbug_analyze.cc:148
List utilities.
Class that manages dynamic buffers.
Definition: dyn0buf.h:49
ulint used() const
Gets the number of used bytes in a block.
Definition: dyn0buf.h:68
mtr_buf_t m_buf
The copied buffer.
Definition: dyn0buf.h:434
friend class dyn_buf_t
Definition: dyn0buf.h:156
block_t m_first_block
The default block, should always be the first element.
Definition: dyn0buf.h:426
block_t * back()
Definition: dyn0buf.h:359
#define UT_LIST_GET_FIRST(BASE)
Definition: innodb_utility.h:115
dyn_buf_t()
Default constructor.
Definition: dyn0buf.h:162
#define UT_LIST_INIT(BASE)
Some Macros to manipulate the list, extracted from "ut0lst.h".
Definition: innodb_utility.h:55
#define DYN_BLOCK_MAGIC_N
Value of dyn_block_t::magic_n.
Definition: dyn0types.h:37
#define UT_LIST_GET_NEXT(NAME, N)
Definition: innodb_utility.h:111
bool for_each_block_in_reverse(Functor &functor) const
Iterate over all the blocks in reverse and call the iterator.
Definition: dyn0buf.h:321
Sergei Dialog Client Authentication NULL
Definition: dialog.cc:352
const byte * begin() const
Definition: dyn0buf.h:89
mtr_buf_t copier
Definition: dyn0buf.h:432
void close(const byte *ptr)
Grow the stack.
Definition: dyn0buf.h:114
#define ut_d(EXPR)
Debug statement.
Definition: ut0dbg.h:62
The info structure stored at the beginning of a heap block.
Definition: mem0mem.h:343
block_t * add_block()
Allocate and add a new block to m_list.
Definition: dyn0buf.h:399
dyn_buf_t< DYN_ARRAY_DATA_SIZE > mtr_buf_t
Definition: dyn0buf.h:429
Definition: dyn0buf.h:56
~block_t()
Definition: dyn0buf.h:63
byte * end()
Definition: dyn0buf.h:83
bool has_space(ulint size)
Definition: dyn0buf.h:369
Type at(ulint pos)
Returns a pointer to an element in the buffer.
Definition: dyn0buf.h:279
bool has_space(ulint size) const
Definition: dyn0buf.h:363
Type push(ib_uint32_t size)
Definition: dyn0buf.h:103
block_list_t m_list
Allocated blocks.
Definition: dyn0buf.h:418
typedef UT_LIST_BASE_NODE_T(block_t) block_list_t
const Type at(ulint pos) const
Returns a pointer to an element in the buffer.
Definition: dyn0buf.h:267
unsigned int len
Definition: dbug_analyze.cc:216
bool for_each_block(Functor &functor) const
Iterate over each block and call the functor.
Definition: dyn0buf.h:306
void init()
Initialise the block.
Definition: dyn0buf.h:128
byte * open(ulint size)
Makes room on top and returns a pointer to a buffer in it.
Definition: dyn0buf.h:192
Type
Definition: resource_group_basic_types.h:32
UNIV_INLINE void * mem_heap_alloc(mem_heap_t *heap, ulint n)
Allocates n bytes of memory from a memory heap.
#define UT_LIST_GET_PREV(NAME, N)
Gets the previous node in a two-way list.
Definition: ut0lst.h:319
typedef UT_LIST_NODE_T(block_t) block_node_t
byte m_data[MAX_DATA_SIZE]
Storage.
Definition: dyn0buf.h:147
#define DYN_BLOCK_FULL_FLAG
Flag for dyn_block_t::used that indicates a full block.
Definition: dyn0types.h:44
ulint m_buf_end
If opened then this is the buffer end offset, else 0.
Definition: dyn0buf.h:137
~dyn_buf_t()
Destructor.
Definition: dyn0buf.h:168
The memory management.
block_t * find(ulint &pos)
Find the block that contains the pos.
Definition: dyn0buf.h:377
#define ut_ad(EXPR)
Debug assertion.
Definition: ut0dbg.h:60
ulint m_size
Total size used by all blocks.
Definition: dyn0buf.h:421
bool is_small() const
Definition: dyn0buf.h:341
byte * begin()
Definition: dyn0buf.h:79
block_t()
Definition: dyn0buf.h:58
UNIV_INLINE void mem_heap_free(mem_heap_t *heap)
Frees the space occupied by a memory heap.
mem_heap_t * m_heap
Heap to use for memory allocation.
Definition: dyn0buf.h:415
void erase()
Reset the buffer vector.
Definition: dyn0buf.h:171
void push_back(block_t *block)
Add the block to the end of the list.
Definition: dyn0buf.h:352
const byte * end() const
Definition: dyn0buf.h:95
block_node_t m_node
Doubly linked list node.
Definition: dyn0buf.h:150
Definition: dyn0buf.h:144
bool operator()(const mtr_buf_t::block_t *block)
Append a block to the redo log buffer.
Definition: dyn0buf.h:438
#define mem_heap_create(size)
Macro for memory heap creation.
Definition: mem0mem.h:120
block_t * front()
Definition: dyn0buf.h:334
void push(const byte *ptr, ib_uint32_t len)
Pushes n bytes.
Definition: dyn0buf.h:245
byte * start()
Gets pointer to the start of data.
Definition: dyn0buf.h:75
dyn_buf_t & operator=(const dyn_buf_t &)
ulint m_magic_n
Magic number (DYN_BLOCK_MAGIC_N)
Definition: dyn0buf.h:140
#define UT_LIST_GET_LAST(BASE)
Gets the last node in a two-way list.
Definition: ut0lst.h:335
#define UT_LIST_ADD_LAST(NAME, BASE, N)
Definition: innodb_utility.h:62
#define UT_LIST_GET_LEN(BASE)
Definition: innodb_utility.h:113
ulint size() const
Returns the size of the total stored data.
Definition: dyn0buf.h:288
Type push(ib_uint32_t size)
Makes room on top and returns a pointer to the added element.
Definition: dyn0buf.h:226