diff options
Diffstat (limited to 'storage/tokudb/tokudb_buffer.h')
-rw-r--r-- | storage/tokudb/tokudb_buffer.h | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/storage/tokudb/tokudb_buffer.h b/storage/tokudb/tokudb_buffer.h new file mode 100644 index 00000000..1605543c --- /dev/null +++ b/storage/tokudb/tokudb_buffer.h @@ -0,0 +1,187 @@ +/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4: +#ident "$Id$" +/*====== +This file is part of TokuDB + + +Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. + + TokuDBis is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2, + as published by the Free Software Foundation. + + TokuDB is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TokuDB. If not, see <http://www.gnu.org/licenses/>. + +======= */ + +#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." + +#ifndef _TOKUDB_BUFFER_H +#define _TOKUDB_BUFFER_H + +#include "hatoku_defines.h" +#include "tokudb_debug.h" +#include "tokudb_thread.h" +#include "tokudb_vlq.h" + +namespace tokudb { + +// A Buffer manages a contiguous chunk of memory and supports appending new +// data to the end of the buffer, and consuming chunks from the beginning of +// the buffer. The buffer will reallocate memory when appending new data to +// a full buffer. + +class buffer { +public: + inline buffer( + void* the_data, + size_t s, + size_t l) : + m_data(the_data), + m_size(s), + m_limit(l), + m_is_static(true) { + } + inline buffer() : + m_data(NULL), + m_size(0), + m_limit(0), + m_is_static(false) { + } + virtual ~buffer() { + if (!m_is_static) + free(m_data); + } + + // Return a pointer to the end of the buffer suitable for appending a + // fixed number of bytes. + void* append_ptr(size_t s) { + maybe_realloc(s); + void* p = (char*)m_data + m_size; + m_size += s; + return p; + } + + // Append bytes to the buffer + void append(void* p, size_t s) { + memcpy(append_ptr(s), p, s); + } + + // Append an unsigned int to the buffer. + // Returns the number of bytes used to encode the number. + // Returns 0 if the number could not be encoded. + template<class T> size_t append_ui(T n) { + maybe_realloc(10); // 10 bytes is big enough for up to 64 bit number + size_t s = tokudb::vlq_encode_ui<T>(n, (char *) m_data + m_size, 10); + m_size += s; + return s; + } + + // Return a pointer to the next location in the buffer where bytes are + // consumed from. + void* consume_ptr(size_t s) { + if (m_size + s > m_limit) + return NULL; + void* p = (char*)m_data + m_size; + m_size += s; + return p; + } + + // Consume bytes from the buffer. + void consume(void* p, size_t s) { + memcpy(p, consume_ptr(s), s); + } + + // Consume an unsigned int from the buffer. + // Returns 0 if the unsigned int could not be decoded, probably because + // the buffer is too short. + // Otherwise return the number of bytes consumed, and stuffs the decoded + // number in *p. + template<class T> size_t consume_ui(T* p) { + size_t s = tokudb::vlq_decode_ui<T>( + p, + (char*)m_data + m_size, + m_limit - m_size); + m_size += s; + return s; + } + + // Write p_length bytes at an offset in the buffer + void write(void* p, size_t p_length, size_t offset) { + assert_always(offset + p_length <= m_size); + memcpy((char*)m_data + offset, p, p_length); + } + + // Read p_length bytes at an offset in the buffer + void read(void* p, size_t p_length, size_t offset) { + assert_always(offset + p_length <= m_size); + memcpy(p, (char*)m_data + offset, p_length); + } + + // Replace a field in the buffer with new data. If the new data size is + // different, then readjust the size of the buffer and move things around. + void replace(size_t offset, size_t old_s, void* new_p, size_t new_s) { + assert_always(offset + old_s <= m_size); + if (new_s > old_s) + maybe_realloc(new_s - old_s); + char* data_offset = (char*)m_data + offset; + if (new_s != old_s) { + size_t n = m_size - (offset + old_s); + assert_always(offset + new_s + n <= m_limit); + assert_always(offset + old_s + n <= m_limit); + memmove(data_offset + new_s, data_offset + old_s, n); + if (new_s > old_s) + m_size += new_s - old_s; + else + m_size -= old_s - new_s; + assert_always(m_size <= m_limit); + } + memcpy(data_offset, new_p, new_s); + } + + // Return a pointer to the data in the buffer + void* data() const { + return m_data; + } + + // Return the size of the data in the buffer + size_t size() const { + return m_size; + } + + // Return the size of the underlying memory in the buffer + size_t limit() const { + return m_limit; + } + +private: + // Maybe reallocate the buffer when it becomes full by doubling its size. + void maybe_realloc(size_t s) { + if (m_size + s > m_limit) { + size_t new_limit = m_limit * 2; + if (new_limit < m_size + s) + new_limit = m_size + s; + assert_always(!m_is_static); + void *new_data = realloc(m_data, new_limit); + assert_always(new_data != NULL); + m_data = new_data; + m_limit = new_limit; + } + } +private: + void* m_data; + size_t m_size; + size_t m_limit; + bool m_is_static; +}; + +}; + +#endif |