liberasurecode 1.8.0
Erasure Code API library
Loading...
Searching...
No Matches
erasurecode_preprocessing.c
Go to the documentation of this file.
1/*
2 * Copyright 2014 Tushar Gohad, Kevin M Greenan, Eric Lambert, Mark Storer
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice, this
11 * list of conditions and the following disclaimer in the documentation and/or
12 * other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY
13 * THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
14 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
17 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
20 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
21 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * liberasurecode proprocssing helpers implementation
25 *
26 * vi: set noai tw=79 ts=4 sw=4:
27 */
28
29#include "erasurecode_backend.h"
30#include "erasurecode_helpers.h"
31#include "erasurecode_helpers_ext.h"
32#include "erasurecode_log.h"
33#include "erasurecode_preprocessing.h"
34#include "erasurecode_stdinc.h"
35
36__attribute__ ((visibility ("internal")))
37int prepare_fragments_for_encode(ec_backend_t instance,
38 int k, int m,
39 const char *orig_data, uint64_t orig_data_size, /* input */
40 char **encoded_data, char **encoded_parity, /* output */
41 int *blocksize)
42{
43 int i, ret = 0;
44 int data_len; /* data len to write to fragment headers */
45 int aligned_data_len; /* EC algorithm compatible data length */
46 int buffer_size, payload_size = 0;
47 int metadata_size, data_offset = 0;
48
49 /* Calculate data sizes, aligned_data_len guaranteed to be divisible by k*/
50 data_len = orig_data_size;
51 aligned_data_len = get_aligned_data_size(instance, orig_data_size);
52 *blocksize = payload_size = (aligned_data_len / k);
53 metadata_size = instance->common.ops->get_backend_metadata_size(
54 instance->desc.backend_desc,
55 *blocksize);
56 data_offset = instance->common.ops->get_encode_offset(
57 instance->desc.backend_desc,
58 metadata_size);
59 buffer_size = payload_size + metadata_size;
60
61 for (i = 0; i < k; i++) {
62 int copy_size = data_len > payload_size ? payload_size : data_len;
63 char *fragment = (char *) alloc_fragment_buffer(buffer_size);
64 if (NULL == fragment) {
65 ret = -ENOMEM;
66 goto out_error;
67 }
68
69 /* Copy existing data into clean, zero'd out buffer */
70 encoded_data[i] = get_data_ptr_from_fragment(fragment);
71
72 if (data_len > 0) {
73 memcpy(encoded_data[i] + data_offset, orig_data, copy_size);
74 }
75
76 orig_data += copy_size;
77 data_len -= copy_size;
78 }
79
80 for (i = 0; i < m; i++) {
81 char *fragment = (char *) alloc_fragment_buffer(buffer_size);
82 if (NULL == fragment) {
83 ret = -ENOMEM;
84 goto out_error;
85 }
86
87 encoded_parity[i] = get_data_ptr_from_fragment(fragment);
88 }
89
90out:
91 return ret;
92
93out_error:
94 printf ("ERROR in encode\n");
95 if (encoded_data) {
96 for (i = 0; i < k; i++) {
97 if (encoded_data[i])
98 free_fragment_buffer(encoded_data[i]);
99 }
100 check_and_free_buffer(encoded_data);
101 }
102
103 if (encoded_parity) {
104 for (i = 0; i < m; i++) {
105 if (encoded_parity[i])
106 free_fragment_buffer(encoded_parity[i]);
107 }
108 check_and_free_buffer(encoded_parity);
109 }
110
111 goto out;
112}
113
114/*
115 * Note that the caller should always check realloc_bm during success or
116 * failure to free buffers allocated here. We could free up in this function,
117 * but it is internal to this library and only used in a few places. In any
118 * case, the caller has to free up in the success case, so it may as well do
119 * so in the failure case.
120 */
121__attribute__ ((visibility ("internal")))
122int prepare_fragments_for_decode(
123 int k, int m,
124 char **data, char **parity,
125 int *missing_idxs,
126 int *orig_size, int *fragment_payload_size, int fragment_size,
127 struct ec_bm *realloc_bm)
128{
129 int i; /* a counter */
130 struct ec_bm missing_bm = NEW_BM; /* bitmap form of missing indexes list */
131 int orig_data_size = -1;
132 int payload_size = -1;
133
134 convert_list_to_bitmap(missing_idxs, &missing_bm);
135
136 /*
137 * Determine if each data fragment is:
138 * 1.) Alloc'd: if not, alloc new buffer (for missing fragments)
139 * 2.) Aligned to 16-byte boundaries: if not, alloc a new buffer
140 * memcpy the contents and free the old buffer
141 */
142 for (i = 0; i < k; i++) {
143 /*
144 * Allocate or replace with aligned buffer if the buffer was not
145 * aligned.
146 * DO NOT FREE: the python GC should free the original when cleaning up
147 * 'data_list'
148 */
149 if (NULL == data[i]) {
150 data[i] = alloc_fragment_buffer(fragment_size - sizeof(fragment_header_t));
151 if (NULL == data[i]) {
152 log_error("Could not allocate data buffer!");
153 return -ENOMEM;
154 }
155 bm_set_value(realloc_bm, i, 1);
156 } else if (!is_addr_aligned((unsigned long)data[i], 16)) {
157 char *tmp_buf = alloc_fragment_buffer(fragment_size - sizeof(fragment_header_t));
158 if (NULL == tmp_buf) {
159 log_error("Could not allocate temp buffer!");
160 return -ENOMEM;
161 }
162 memcpy(tmp_buf, data[i], fragment_size);
163 data[i] = tmp_buf;
164 bm_set_value(realloc_bm, i, 1);
165 }
166
167 /* Need to determine the size of the original data */
168 if (!bm_get_value(&missing_bm, i) && orig_data_size < 0) {
169 orig_data_size = get_orig_data_size(data[i]);
170 if (orig_data_size < 0) {
171 log_error("Invalid orig_data_size in fragment header!");
172 return -EBADHEADER;
173 }
174 payload_size = get_fragment_payload_size(data[i]);
175 if (payload_size < 0) {
176 log_error("Invalid fragment_size in fragment header!");
177 return -EBADHEADER;
178 }
179 }
180 }
181
182 /* Perform the same allocation, alignment checks on the parity fragments */
183 for (i = 0; i < m; i++) {
184 /*
185 * Allocate or replace with aligned buffer, if the buffer was not aligned.
186 * DO NOT FREE: the python GC should free the original when cleaning up 'data_list'
187 */
188 if (NULL == parity[i]) {
189 parity[i] = alloc_fragment_buffer(fragment_size-sizeof(fragment_header_t));
190 if (NULL == parity[i]) {
191 log_error("Could not allocate parity buffer!");
192 return -ENOMEM;
193 }
194 bm_set_value(realloc_bm, k + i, 1);
195 } else if (!is_addr_aligned((unsigned long)parity[i], 16)) {
196 char *tmp_buf = alloc_fragment_buffer(fragment_size-sizeof(fragment_header_t));
197 if (NULL == tmp_buf) {
198 log_error("Could not allocate temp buffer!");
199 return -ENOMEM;
200 }
201 memcpy(tmp_buf, parity[i], fragment_size);
202 parity[i] = tmp_buf;
203 bm_set_value(realloc_bm, k + i, 1);
204 }
205
206 /* Need to determine the size of the original data */
207 if (!bm_get_value(&missing_bm, k + i) && orig_data_size < 0) {
208 orig_data_size = get_orig_data_size(parity[i]);
209 if (orig_data_size < 0) {
210 log_error("Invalid orig_data_size in fragment header!");
211 return -EBADHEADER;
212 }
213 payload_size = get_fragment_payload_size(parity[i]);
214 if (payload_size < 0) {
215 log_error("Invalid fragment_size in fragment header!");
216 return -EBADHEADER;
217 }
218 }
219
220 }
221
222 *orig_size = orig_data_size;
223 *fragment_payload_size = payload_size;
224
225 return 0;
226}
227
229 int k, int m,
230 char **fragments, int num_fragments,
231 char **data, char **parity, int *missing)
232{
233 int i = 0;
234 int num_missing = 0;
235 int index;
236
237 /*
238 * Set all data and parity entries to NULL
239 */
240 for (i = 0; i < k; i++) {
241 data[i] = NULL;
242 }
243 for (i = 0; i < m; i++) {
244 parity[i] = NULL;
245 }
246
247 /*
248 * Fill in data and parity with available fragments
249 */
250 for (i = 0; i < num_fragments; i++) {
251 index = get_fragment_idx(fragments[i]);
252 if (index < 0 || index >= (k + m)) {
253 return -EBADHEADER;
254 }
255 if (index < k) {
256 data[index] = fragments[i];
257 } else {
258 parity[index - k] = fragments[i];
259 }
260 }
261
262 /*
263 * Fill in missing array with missing indexes
264 */
265 for (i = 0; i < k; i++) {
266 if (NULL == data[i]) {
267 missing[num_missing] = i;
268 num_missing++;
269 }
270 }
271 for (i = 0; i < m; i++) {
272 if (NULL == parity[i]) {
273 missing[num_missing] = i + k;
274 num_missing++;
275 }
276 }
277 return 0;
278}
279
280__attribute__ ((visibility ("internal")))
281int fragments_to_string(int k, int m,
282 char **fragments, int num_fragments,
283 char **orig_payload, uint64_t *payload_len)
284{
285 char *internal_payload = NULL;
286 char **data = NULL;
287 int orig_data_size = -1;
288 int i;
289 int index;
290 int data_size;
291 int num_data = 0;
292 int string_off = 0;
293 int ret = -1;
294
295 if (num_fragments < k) {
296 /*
297 * This is not necessarily an error condition, so *do not log here*
298 * We can maybe debug log, if necessary.
299 */
300 goto out;
301 }
302
303 data = (char **) get_aligned_buffer16(sizeof(char *) * k);
304
305 if (NULL == data) {
306 log_error("Could not allocate buffer for data!!");
307 ret = -ENOMEM;
308 goto out;
309 }
310
311 for (i = 0; i < num_fragments; i++) {
312 index = get_fragment_idx(fragments[i]);
313 data_size = get_fragment_payload_size(fragments[i]);
314 if ((index < 0) || (data_size < 0)) {
315 log_error("Invalid fragment header information!");
316 ret = -EBADHEADER;
317 goto out;
318 }
319
320 /* Validate the original data size */
321 if (orig_data_size < 0) {
322 orig_data_size = get_orig_data_size(fragments[i]);
323 } else {
324 if (get_orig_data_size(fragments[i]) != orig_data_size) {
325 log_error("Inconsistent orig_data_size in fragment header!");
326 ret = -EBADHEADER;
327 goto out;
328 }
329 }
330
331 /* Skip parity fragments, put data fragments in index order */
332 if (index >= k) {
333 continue;
334 } else {
335 /* Make sure we account for duplicates */
336 if (NULL == data[index]) {
337 data[index] = fragments[i];
338 num_data++;
339 }
340 }
341 }
342
343 /* We do not have enough data fragments to do this! */
344 if (num_data != k) {
345 /*
346 * This is not necessarily an error condition, so *do not log here*
347 * We can maybe debug log, if necessary.
348 */
349 goto out;
350 }
351
352 /* Create the string to return */
353 internal_payload = (char *) get_aligned_buffer16(orig_data_size);
354 if (NULL == internal_payload) {
355 log_error("Could not allocate buffer for decoded string!");
356 ret = -ENOMEM;
357 goto out;
358 }
359
360 /* Pass the original data length back */
361 *payload_len = orig_data_size;
362
363 /* Copy fragment data into cstring (fragments should be in index order) */
364 for (i = 0; i < num_data && orig_data_size > 0; i++) {
365 char* fragment_data = get_data_ptr_from_fragment(data[i]);
366 int fragment_size = get_fragment_payload_size(data[i]);
367 int payload_size = orig_data_size > fragment_size ? fragment_size : orig_data_size;
368 memcpy(internal_payload + string_off, fragment_data, payload_size);
369 orig_data_size -= payload_size;
370 string_off += payload_size;
371 }
372
373 /* Everything worked just fine */
374 ret = 0;
375
376out:
377 if (NULL != data) {
378 free(data);
379 }
380
381 *orig_payload = internal_payload;
382 return ret;
383}
384
385
char * get_data_ptr_from_fragment(char *buf)
__attribute__((visibility("internal")))
int get_fragment_partition(int k, int m, char **fragments, int num_fragments, char **data, char **parity, int *missing)