1 /*
2 * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2.0,
6 * as published by the Free Software Foundation.
7 *
8 * This program is also distributed with certain software (including
9 * but not limited to OpenSSL) that is licensed under separate terms,
10 * as designated in a particular file or component or in included license
11 * documentation. The authors of MySQL hereby grant you an additional
12 * permission to link the program and your derivative works with the
13 * separately licensed software that they have included with MySQL.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License, version 2.0, for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301 USA
24 */
25
26 #include "ngs/protocol/output_buffer.h"
27
28 #include "my_byteorder.h"
29
30
31 namespace ngs {
32
Output_buffer(Page_pool & page_pool)33 Output_buffer::Output_buffer(Page_pool& page_pool)
34 : Buffer(page_pool) {
35 }
36
37
add_int32(int32_t i)38 bool Output_buffer::add_int32(int32_t i) {
39 const uint32 raw_data_size = sizeof(int32_t);
40 uchar raw_data[raw_data_size];
41 int4store(raw_data, i);
42
43 add_bytes(reinterpret_cast<char*>(raw_data),
44 raw_data_size);
45
46 return true;
47 }
48
add_int8(int8_t i)49 bool Output_buffer::add_int8(int8_t i) {
50 void *ptr;
51 int size;
52
53 do {
54 if (!Next(&ptr, &size))
55 return false;
56 }
57 while (size < 1);
58
59 *(int8_t*)ptr = i;
60
61 if (size > 1) // return leftover
62 BackUp(size-1);
63
64 return true;
65 }
66
67
add_bytes(const char * data,size_t length)68 bool Output_buffer::add_bytes(const char *data, size_t length) {
69 void *ptr;
70 int size;
71
72 do {
73 if (!Next(&ptr, &size) || size < 0)
74 return false;
75
76 if ((size_t)size >= length) {
77 memcpy(ptr, data, length);
78 BackUp(static_cast<int>(size - length));
79 length = 0;
80 }
81 else {
82 memcpy(ptr, data, size);
83 data += size;
84 length -= size;
85 }
86 }
87 while (length > 0);
88
89 return true;
90 }
91
92
Next(void ** data,int * size)93 bool Output_buffer::Next(void** data, int* size) {
94 // point *data to the beginning of the next page
95 // point size to the data left in that page
96 // only up to m_artificial_length must be passed
97
98 // first, check if there are pages left with free space
99 for (Page_list::const_iterator p = m_pages.begin();
100 p != m_pages.end();
101 ++p) {
102 if ((*p)->length < (*p)->capacity) {
103 // ensure that the next page is empty
104 Page_list::const_iterator next = p;
105 ++next;
106 if (next == m_pages.end() || (*next)->length == 0) {
107 *data = (*p)->data + (*p)->length;
108 *size = (*p)->capacity - (*p)->length;
109 (*p)->length = (*p)->capacity;
110 m_length += *size;
111 return true;
112 }
113 }
114 }
115
116 // no more space left, just add new pages
117 if (Memory_allocated == add_pages(1)) {
118 Buffer_page &p = m_pages.back();
119
120 *data = p->data;
121 *size = p->capacity;
122 p->length = p->capacity;
123 m_length += *size;
124 return true;
125 }
126 return false;
127 }
128
129
BackUp(int count)130 void Output_buffer::BackUp(int count) {
131 // return unused bytes from the last Next() call
132 for (Page_list::const_reverse_iterator p = m_pages.rbegin();
133 p != m_pages.rend() && count > 0; ++p)
134 {
135 if ((*p)->length > 0)
136 {
137 if (count > 0 && (size_t)count < (*p)->length)
138 {
139 (*p)->length -= count;
140 m_length -= count;
141 count = 0;
142 }
143 else
144 {
145 count -= (*p)->length;
146 m_length -= (*p)->length;
147 (*p)->length = 0;
148 }
149 }
150 }
151 }
152
153
ByteCount() const154 int64_t Output_buffer::ByteCount() const {
155 size_t count = 0;
156 for (Page_list::const_iterator p = m_pages.begin();
157 p != m_pages.end(); ++p)
158 count += (*p)->length;
159 return count;
160 }
161
162
get_buffers()163 Const_buffer_sequence Output_buffer::get_buffers() {
164 Const_buffer_sequence buffers;
165 buffers.reserve(m_pages.size());
166
167 for (Page_list::const_iterator p = m_pages.begin();
168 p != m_pages.end() && (*p)->length > 0;++p) {
169 buffers.push_back(std::make_pair((*p)->data, (*p)->length));
170 }
171 return buffers;
172 }
173
save_state()174 void Output_buffer::save_state() {
175 m_saved_length = m_length;
176 Page_list::iterator it = m_pages.begin();
177
178 for (; it != m_pages.end(); ++it) {
179 (*it)->save_state();
180 }
181 }
182
rollback()183 void Output_buffer::rollback() {
184 m_length = m_saved_length;
185 Page_list::iterator it = m_pages.begin();
186
187 for (; it != m_pages.end(); ++it) {
188 (*it)->rollback();
189 }
190 }
191
192 } // namespace ngs
193