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: buffer(void * the_data,size_t s,size_t l)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 } buffer()52 inline buffer() : 53 m_data(NULL), 54 m_size(0), 55 m_limit(0), 56 m_is_static(false) { 57 } ~buffer()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. append_ptr(size_t s)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 append(void * p,size_t s)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. append_ui(T n)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. consume_ptr(size_t s)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. consume(void * p,size_t s)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. consume_ui(T * 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 write(void * p,size_t p_length,size_t offset)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 read(void * p,size_t p_length,size_t offset)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. replace(size_t offset,size_t old_s,void * new_p,size_t new_s)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(offset + new_s + n <= m_limit); 138 assert_always(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 data()150 void* data() const { 151 return m_data; 152 } 153 154 // Return the size of the data in the buffer size()155 size_t size() const { 156 return m_size; 157 } 158 159 // Return the size of the underlying memory in the buffer limit()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. maybe_realloc(size_t s)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