| 1 | /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
| 2 | // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4: |
| 3 | #ident "$Id$" |
| 4 | /*====== |
| 5 | This file is part of TokuDB |
| 6 | |
| 7 | |
| 8 | Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. |
| 9 | |
| 10 | TokuDBis is free software: you can redistribute it and/or modify |
| 11 | it under the terms of the GNU General Public License, version 2, |
| 12 | as published by the Free Software Foundation. |
| 13 | |
| 14 | TokuDB is distributed in the hope that it will be useful, |
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | GNU General Public License for more details. |
| 18 | |
| 19 | You should have received a copy of the GNU General Public License |
| 20 | along with TokuDB. If not, see <http://www.gnu.org/licenses/>. |
| 21 | |
| 22 | ======= */ |
| 23 | |
| 24 | #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." |
| 25 | |
| 26 | #ifndef _TOKUDB_BUFFER_H |
| 27 | #define _TOKUDB_BUFFER_H |
| 28 | |
| 29 | #include "hatoku_defines.h" |
| 30 | #include "tokudb_debug.h" |
| 31 | #include "tokudb_thread.h" |
| 32 | #include "tokudb_vlq.h" |
| 33 | |
| 34 | namespace tokudb { |
| 35 | |
| 36 | // A Buffer manages a contiguous chunk of memory and supports appending new |
| 37 | // data to the end of the buffer, and consuming chunks from the beginning of |
| 38 | // the buffer. The buffer will reallocate memory when appending new data to |
| 39 | // a full buffer. |
| 40 | |
| 41 | class buffer { |
| 42 | public: |
| 43 | inline buffer( |
| 44 | void* the_data, |
| 45 | size_t s, |
| 46 | size_t l) : |
| 47 | m_data(the_data), |
| 48 | m_size(s), |
| 49 | m_limit(l), |
| 50 | m_is_static(true) { |
| 51 | } |
| 52 | inline buffer() : |
| 53 | m_data(NULL), |
| 54 | m_size(0), |
| 55 | m_limit(0), |
| 56 | m_is_static(false) { |
| 57 | } |
| 58 | virtual ~buffer() { |
| 59 | if (!m_is_static) |
| 60 | free(m_data); |
| 61 | } |
| 62 | |
| 63 | // Return a pointer to the end of the buffer suitable for appending a |
| 64 | // fixed number of bytes. |
| 65 | void* append_ptr(size_t s) { |
| 66 | maybe_realloc(s); |
| 67 | void* p = (char*)m_data + m_size; |
| 68 | m_size += s; |
| 69 | return p; |
| 70 | } |
| 71 | |
| 72 | // Append bytes to the buffer |
| 73 | void append(void* p, size_t s) { |
| 74 | memcpy(append_ptr(s), p, s); |
| 75 | } |
| 76 | |
| 77 | // Append an unsigned int to the buffer. |
| 78 | // Returns the number of bytes used to encode the number. |
| 79 | // Returns 0 if the number could not be encoded. |
| 80 | template<class T> size_t append_ui(T n) { |
| 81 | maybe_realloc(10); // 10 bytes is big enough for up to 64 bit number |
| 82 | size_t s = tokudb::vlq_encode_ui<T>(n, (char *) m_data + m_size, 10); |
| 83 | m_size += s; |
| 84 | return s; |
| 85 | } |
| 86 | |
| 87 | // Return a pointer to the next location in the buffer where bytes are |
| 88 | // consumed from. |
| 89 | void* consume_ptr(size_t s) { |
| 90 | if (m_size + s > m_limit) |
| 91 | return NULL; |
| 92 | void* p = (char*)m_data + m_size; |
| 93 | m_size += s; |
| 94 | return p; |
| 95 | } |
| 96 | |
| 97 | // Consume bytes from the buffer. |
| 98 | void consume(void* p, size_t s) { |
| 99 | memcpy(p, consume_ptr(s), s); |
| 100 | } |
| 101 | |
| 102 | // Consume an unsigned int from the buffer. |
| 103 | // Returns 0 if the unsigned int could not be decoded, probably because |
| 104 | // the buffer is too short. |
| 105 | // Otherwise return the number of bytes consumed, and stuffs the decoded |
| 106 | // number in *p. |
| 107 | template<class T> size_t consume_ui(T* p) { |
| 108 | size_t s = tokudb::vlq_decode_ui<T>( |
| 109 | p, |
| 110 | (char*)m_data + m_size, |
| 111 | m_limit - m_size); |
| 112 | m_size += s; |
| 113 | return s; |
| 114 | } |
| 115 | |
| 116 | // Write p_length bytes at an offset in the buffer |
| 117 | void write(void* p, size_t p_length, size_t offset) { |
| 118 | assert_always(offset + p_length <= m_size); |
| 119 | memcpy((char*)m_data + offset, p, p_length); |
| 120 | } |
| 121 | |
| 122 | // Read p_length bytes at an offset in the buffer |
| 123 | void read(void* p, size_t p_length, size_t offset) { |
| 124 | assert_always(offset + p_length <= m_size); |
| 125 | memcpy(p, (char*)m_data + offset, p_length); |
| 126 | } |
| 127 | |
| 128 | // Replace a field in the buffer with new data. If the new data size is |
| 129 | // different, then readjust the size of the buffer and move things around. |
| 130 | void replace(size_t offset, size_t old_s, void* new_p, size_t new_s) { |
| 131 | assert_always(offset + old_s <= m_size); |
| 132 | if (new_s > old_s) |
| 133 | maybe_realloc(new_s - old_s); |
| 134 | char* data_offset = (char*)m_data + offset; |
| 135 | if (new_s != old_s) { |
| 136 | size_t n = m_size - (offset + old_s); |
| 137 | assert_always( |
| 138 | offset + new_s + n <= m_limit && offset + old_s + n <= m_limit); |
| 139 | memmove(data_offset + new_s, data_offset + old_s, n); |
| 140 | if (new_s > old_s) |
| 141 | m_size += new_s - old_s; |
| 142 | else |
| 143 | m_size -= old_s - new_s; |
| 144 | assert_always(m_size <= m_limit); |
| 145 | } |
| 146 | memcpy(data_offset, new_p, new_s); |
| 147 | } |
| 148 | |
| 149 | // Return a pointer to the data in the buffer |
| 150 | void* data() const { |
| 151 | return m_data; |
| 152 | } |
| 153 | |
| 154 | // Return the size of the data in the buffer |
| 155 | size_t size() const { |
| 156 | return m_size; |
| 157 | } |
| 158 | |
| 159 | // Return the size of the underlying memory in the buffer |
| 160 | size_t limit() const { |
| 161 | return m_limit; |
| 162 | } |
| 163 | |
| 164 | private: |
| 165 | // Maybe reallocate the buffer when it becomes full by doubling its size. |
| 166 | void maybe_realloc(size_t s) { |
| 167 | if (m_size + s > m_limit) { |
| 168 | size_t new_limit = m_limit * 2; |
| 169 | if (new_limit < m_size + s) |
| 170 | new_limit = m_size + s; |
| 171 | assert_always(!m_is_static); |
| 172 | void *new_data = realloc(m_data, new_limit); |
| 173 | assert_always(new_data != NULL); |
| 174 | m_data = new_data; |
| 175 | m_limit = new_limit; |
| 176 | } |
| 177 | } |
| 178 | private: |
| 179 | void* m_data; |
| 180 | size_t m_size; |
| 181 | size_t m_limit; |
| 182 | bool m_is_static; |
| 183 | }; |
| 184 | |
| 185 | }; |
| 186 | |
| 187 | #endif |
| 188 | |