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/*======
5This file is part of PerconaFT.
6
7
8Copyright (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
46DBT *toku_init_dbt(DBT *dbt) {
47 memset(dbt, 0, sizeof(*dbt));
48 return dbt;
49}
50
51DBT toku_empty_dbt(void) {
52 static const DBT empty_dbt = { .data = 0, .size = 0, .ulen = 0, .flags = 0 };
53 return empty_dbt;
54}
55
56DBT *toku_init_dbt_flags(DBT *dbt, uint32_t flags) {
57 toku_init_dbt(dbt);
58 dbt->flags = flags;
59 return dbt;
60}
61
62DBT_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
75void 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
103void toku_dbt_array_destroy_shallow(DBT_ARRAY *dbts) {
104 toku_free(dbts->dbts);
105 ZERO_STRUCT(*dbts);
106}
107
108void 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
117void 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
127DBT *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
134DBT *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
141DBT *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
149DBT *toku_clone_dbt(DBT *dst, const DBT &src) {
150 return toku_memdup_dbt(dst, src.data, src.size);
151}
152
153void
154toku_sdbt_cleanup(struct simple_dbt *sdbt) {
155 if (sdbt->data) toku_free(sdbt->data);
156 memset(sdbt, 0, sizeof(*sdbt));
157}
158
159static 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
171static 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.
185int 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
249const DBT *toku_dbt_positive_infinity(void) {
250 static DBT positive_infinity_dbt = {};
251 return &positive_infinity_dbt;
252}
253
254const DBT *toku_dbt_negative_infinity(void) {
255 static DBT negative_infinity_dbt = {};
256 return &negative_infinity_dbt;
257}
258
259bool toku_dbt_is_infinite(const DBT *dbt) {
260 return dbt == toku_dbt_positive_infinity() || dbt == toku_dbt_negative_infinity();
261}
262
263bool 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
269int 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
284bool 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