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