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 PerconaFT. |
6 | |
7 | |
8 | Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. |
9 | |
10 | PerconaFT 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 | PerconaFT 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 PerconaFT. If not, see <http://www.gnu.org/licenses/>. |
21 | |
22 | ---------------------------------------- |
23 | |
24 | PerconaFT is free software: you can redistribute it and/or modify |
25 | it under the terms of the GNU Affero General Public License, version 3, |
26 | as published by the Free Software Foundation. |
27 | |
28 | PerconaFT is distributed in the hope that it will be useful, |
29 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
31 | GNU Affero General Public License for more details. |
32 | |
33 | You should have received a copy of the GNU Affero General Public License |
34 | along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. |
35 | ======= */ |
36 | |
37 | #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." |
38 | |
39 | #include <db.h> |
40 | #include <string.h> |
41 | |
42 | #include "portability/memory.h" |
43 | |
44 | #include "util/dbt.h" |
45 | |
46 | DBT *toku_init_dbt(DBT *dbt) { |
47 | memset(dbt, 0, sizeof(*dbt)); |
48 | return dbt; |
49 | } |
50 | |
51 | DBT toku_empty_dbt(void) { |
52 | static const DBT empty_dbt = { .data = 0, .size = 0, .ulen = 0, .flags = 0 }; |
53 | return empty_dbt; |
54 | } |
55 | |
56 | DBT *toku_init_dbt_flags(DBT *dbt, uint32_t flags) { |
57 | toku_init_dbt(dbt); |
58 | dbt->flags = flags; |
59 | return dbt; |
60 | } |
61 | |
62 | DBT_ARRAY *toku_dbt_array_init(DBT_ARRAY *dbts, uint32_t size) { |
63 | uint32_t capacity = 1; |
64 | while (capacity < size) { capacity *= 2; } |
65 | |
66 | XMALLOC_N(capacity, dbts->dbts); |
67 | for (uint32_t i = 0; i < capacity; i++) { |
68 | toku_init_dbt_flags(&dbts->dbts[i], DB_DBT_REALLOC); |
69 | } |
70 | dbts->size = size; |
71 | dbts->capacity = capacity; |
72 | return dbts; |
73 | } |
74 | |
75 | void toku_dbt_array_resize(DBT_ARRAY *dbts, uint32_t size) { |
76 | if (size != dbts->size) { |
77 | if (size > dbts->capacity) { |
78 | const uint32_t old_capacity = dbts->capacity; |
79 | uint32_t new_capacity = dbts->capacity; |
80 | while (new_capacity < size) { |
81 | new_capacity *= 2; |
82 | } |
83 | dbts->capacity = new_capacity; |
84 | XREALLOC_N(new_capacity, dbts->dbts); |
85 | for (uint32_t i = old_capacity; i < new_capacity; i++) { |
86 | toku_init_dbt_flags(&dbts->dbts[i], DB_DBT_REALLOC); |
87 | } |
88 | } else if (size < dbts->size) { |
89 | if (dbts->capacity >= 8 && size < dbts->capacity / 4) { |
90 | const int old_capacity = dbts->capacity; |
91 | const int new_capacity = dbts->capacity / 2; |
92 | for (int i = new_capacity; i < old_capacity; i++) { |
93 | toku_destroy_dbt(&dbts->dbts[i]); |
94 | } |
95 | XREALLOC_N(new_capacity, dbts->dbts); |
96 | dbts->capacity = new_capacity; |
97 | } |
98 | } |
99 | dbts->size = size; |
100 | } |
101 | } |
102 | |
103 | void toku_dbt_array_destroy_shallow(DBT_ARRAY *dbts) { |
104 | toku_free(dbts->dbts); |
105 | ZERO_STRUCT(*dbts); |
106 | } |
107 | |
108 | void toku_dbt_array_destroy(DBT_ARRAY *dbts) { |
109 | for (uint32_t i = 0; i < dbts->capacity; i++) { |
110 | toku_destroy_dbt(&dbts->dbts[i]); |
111 | } |
112 | toku_dbt_array_destroy_shallow(dbts); |
113 | } |
114 | |
115 | |
116 | |
117 | void toku_destroy_dbt(DBT *dbt) { |
118 | switch (dbt->flags) { |
119 | case DB_DBT_MALLOC: |
120 | case DB_DBT_REALLOC: |
121 | toku_free(dbt->data); |
122 | toku_init_dbt(dbt); |
123 | break; |
124 | } |
125 | } |
126 | |
127 | DBT *toku_fill_dbt(DBT *dbt, const void *k, uint32_t len) { |
128 | toku_init_dbt(dbt); |
129 | dbt->size=len; |
130 | dbt->data=(char*)k; |
131 | return dbt; |
132 | } |
133 | |
134 | DBT *toku_memdup_dbt(DBT *dbt, const void *k, size_t len) { |
135 | toku_init_dbt_flags(dbt, DB_DBT_MALLOC); |
136 | dbt->size = len; |
137 | dbt->data = toku_xmemdup(k, len); |
138 | return dbt; |
139 | } |
140 | |
141 | DBT *toku_copyref_dbt(DBT *dst, const DBT src) { |
142 | dst->flags = 0; |
143 | dst->ulen = 0; |
144 | dst->size = src.size; |
145 | dst->data = src.data; |
146 | return dst; |
147 | } |
148 | |
149 | DBT *toku_clone_dbt(DBT *dst, const DBT &src) { |
150 | return toku_memdup_dbt(dst, src.data, src.size); |
151 | } |
152 | |
153 | void |
154 | toku_sdbt_cleanup(struct simple_dbt *sdbt) { |
155 | if (sdbt->data) toku_free(sdbt->data); |
156 | memset(sdbt, 0, sizeof(*sdbt)); |
157 | } |
158 | |
159 | static inline int sdbt_realloc(struct simple_dbt *sdbt) { |
160 | void *new_data = toku_realloc(sdbt->data, sdbt->len); |
161 | int r; |
162 | if (new_data == NULL) { |
163 | r = get_error_errno(); |
164 | } else { |
165 | sdbt->data = new_data; |
166 | r = 0; |
167 | } |
168 | return r; |
169 | } |
170 | |
171 | static inline int dbt_realloc(DBT *dbt) { |
172 | void *new_data = toku_realloc(dbt->data, dbt->ulen); |
173 | int r; |
174 | if (new_data == NULL) { |
175 | r = get_error_errno(); |
176 | } else { |
177 | dbt->data = new_data; |
178 | r = 0; |
179 | } |
180 | return r; |
181 | } |
182 | |
183 | // sdbt is the static value used when flags==0 |
184 | // Otherwise malloc or use the user-supplied memory, as according to the flags in d->flags. |
185 | int toku_dbt_set(uint32_t len, const void *val, DBT *d, struct simple_dbt *sdbt) { |
186 | int r; |
187 | if (d == nullptr) { |
188 | r = 0; |
189 | } else { |
190 | switch (d->flags) { |
191 | case (DB_DBT_USERMEM): |
192 | d->size = len; |
193 | if (d->ulen<len) r = DB_BUFFER_SMALL; |
194 | else { |
195 | memcpy(d->data, val, len); |
196 | r = 0; |
197 | } |
198 | break; |
199 | case (DB_DBT_MALLOC): |
200 | d->data = NULL; |
201 | d->ulen = 0; |
202 | // fallthrough |
203 | // to DB_DBT_REALLOC |
204 | case (DB_DBT_REALLOC): |
205 | if (d->ulen < len) { |
206 | d->ulen = len*2; |
207 | r = dbt_realloc(d); |
208 | } |
209 | else if (d->ulen > 16 && d->ulen > len*4) { |
210 | d->ulen = len*2 < 16 ? 16 : len*2; |
211 | r = dbt_realloc(d); |
212 | } |
213 | else if (d->data==NULL) { |
214 | d->ulen = len; |
215 | r = dbt_realloc(d); |
216 | } |
217 | else r=0; |
218 | |
219 | if (r==0) { |
220 | memcpy(d->data, val, len); |
221 | d->size = len; |
222 | } |
223 | break; |
224 | case (0): |
225 | if (sdbt->len < len) { |
226 | sdbt->len = len*2; |
227 | r = sdbt_realloc(sdbt); |
228 | } |
229 | else if (sdbt->len > 16 && sdbt->len > len*4) { |
230 | sdbt->len = len*2 < 16 ? 16 : len*2; |
231 | r = sdbt_realloc(sdbt); |
232 | } |
233 | else r=0; |
234 | |
235 | if (r==0) { |
236 | memcpy(sdbt->data, val, len); |
237 | d->data = sdbt->data; |
238 | d->size = len; |
239 | } |
240 | break; |
241 | default: |
242 | r = EINVAL; |
243 | break; |
244 | } |
245 | } |
246 | return r; |
247 | } |
248 | |
249 | const DBT *toku_dbt_positive_infinity(void) { |
250 | static DBT positive_infinity_dbt = {}; |
251 | return &positive_infinity_dbt; |
252 | } |
253 | |
254 | const DBT *toku_dbt_negative_infinity(void) { |
255 | static DBT negative_infinity_dbt = {}; |
256 | return &negative_infinity_dbt; |
257 | } |
258 | |
259 | bool toku_dbt_is_infinite(const DBT *dbt) { |
260 | return dbt == toku_dbt_positive_infinity() || dbt == toku_dbt_negative_infinity(); |
261 | } |
262 | |
263 | bool toku_dbt_is_empty(const DBT *dbt) { |
264 | // can't have a null data field with a non-zero size |
265 | paranoid_invariant(dbt->data != nullptr || dbt->size == 0); |
266 | return dbt->data == nullptr; |
267 | } |
268 | |
269 | int toku_dbt_infinite_compare(const DBT *a, const DBT *b) { |
270 | if (a == b) { |
271 | return 0; |
272 | } else if (a == toku_dbt_positive_infinity()) { |
273 | return 1; |
274 | } else if (b == toku_dbt_positive_infinity()) { |
275 | return -1; |
276 | } else if (a == toku_dbt_negative_infinity()) { |
277 | return -1; |
278 | } else { |
279 | invariant(b == toku_dbt_negative_infinity()); |
280 | return 1; |
281 | } |
282 | } |
283 | |
284 | bool toku_dbt_equals(const DBT *a, const DBT *b) { |
285 | if (!toku_dbt_is_infinite(a) && !toku_dbt_is_infinite(b)) { |
286 | return a->data == b->data && a->size == b->size; |
287 | } else { |
288 | // a or b is infinite, so they're equal if they are the same infinite |
289 | return a == b ? true : false; |
290 | } |
291 | } |
292 | |