]> git.proxmox.com Git - ceph.git/blame - ceph/src/erasure-code/jerasure/ErasureCodeJerasure.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / erasure-code / jerasure / ErasureCodeJerasure.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph distributed storage system
5 *
6 * Copyright (C) 2013,2014 Cloudwatt <libre.licensing@cloudwatt.com>
7 * Copyright (C) 2014 Red Hat <contact@redhat.com>
8 *
9 * Author: Loic Dachary <loic@dachary.org>
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 */
17
18#include "common/debug.h"
19#include "ErasureCodeJerasure.h"
31f18b77 20
31f18b77 21
7c673cae
FG
22extern "C" {
23#include "jerasure.h"
24#include "reed_sol.h"
25#include "galois.h"
26#include "cauchy.h"
27#include "liberation.h"
28}
29
30#define LARGEST_VECTOR_WORDSIZE 16
31
32#define dout_context g_ceph_context
33#define dout_subsys ceph_subsys_osd
34#undef dout_prefix
35#define dout_prefix _prefix(_dout)
36
37static ostream& _prefix(std::ostream* _dout)
38{
39 return *_dout << "ErasureCodeJerasure: ";
40}
41
7c673cae
FG
42
43int ErasureCodeJerasure::init(ErasureCodeProfile& profile, ostream *ss)
44{
45 int err = 0;
46 dout(10) << "technique=" << technique << dendl;
47 profile["technique"] = technique;
7c673cae
FG
48 err |= parse(profile, ss);
49 if (err)
50 return err;
51 prepare();
224ce89b 52 return ErasureCode::init(profile, ss);
7c673cae
FG
53}
54
55int ErasureCodeJerasure::parse(ErasureCodeProfile &profile,
56 ostream *ss)
57{
58 int err = ErasureCode::parse(profile, ss);
59 err |= to_int("k", profile, &k, DEFAULT_K, ss);
60 err |= to_int("m", profile, &m, DEFAULT_M, ss);
61 err |= to_int("w", profile, &w, DEFAULT_W, ss);
62 if (chunk_mapping.size() > 0 && (int)chunk_mapping.size() != k + m) {
63 *ss << "mapping " << profile.find("mapping")->second
64 << " maps " << chunk_mapping.size() << " chunks instead of"
65 << " the expected " << k + m << " and will be ignored" << std::endl;
66 chunk_mapping.clear();
67 err = -EINVAL;
68 }
11fdf7f2 69 err |= sanity_check_k_m(k, m, ss);
7c673cae
FG
70 return err;
71}
72
73unsigned int ErasureCodeJerasure::get_chunk_size(unsigned int object_size) const
74{
75 unsigned alignment = get_alignment();
76 if (per_chunk_alignment) {
77 unsigned chunk_size = object_size / k;
78 if (object_size % k)
79 chunk_size++;
80 dout(20) << "get_chunk_size: chunk_size " << chunk_size
81 << " must be modulo " << alignment << dendl;
11fdf7f2 82 ceph_assert(alignment <= chunk_size);
7c673cae
FG
83 unsigned modulo = chunk_size % alignment;
84 if (modulo) {
85 dout(10) << "get_chunk_size: " << chunk_size
86 << " padded to " << chunk_size + alignment - modulo << dendl;
87 chunk_size += alignment - modulo;
88 }
89 return chunk_size;
90 } else {
91 unsigned tail = object_size % alignment;
92 unsigned padded_length = object_size + ( tail ? ( alignment - tail ) : 0 );
11fdf7f2 93 ceph_assert(padded_length % k == 0);
7c673cae
FG
94 return padded_length / k;
95 }
96}
97
98int ErasureCodeJerasure::encode_chunks(const set<int> &want_to_encode,
99 map<int, bufferlist> *encoded)
100{
101 char *chunks[k + m];
102 for (int i = 0; i < k + m; i++)
103 chunks[i] = (*encoded)[i].c_str();
104 jerasure_encode(&chunks[0], &chunks[k], (*encoded)[0].length());
105 return 0;
106}
107
108int ErasureCodeJerasure::decode_chunks(const set<int> &want_to_read,
109 const map<int, bufferlist> &chunks,
110 map<int, bufferlist> *decoded)
111{
112 unsigned blocksize = (*chunks.begin()).second.length();
113 int erasures[k + m + 1];
114 int erasures_count = 0;
115 char *data[k];
116 char *coding[m];
117 for (int i = 0; i < k + m; i++) {
118 if (chunks.find(i) == chunks.end()) {
119 erasures[erasures_count] = i;
120 erasures_count++;
121 }
122 if (i < k)
123 data[i] = (*decoded)[i].c_str();
124 else
125 coding[i - k] = (*decoded)[i].c_str();
126 }
127 erasures[erasures_count] = -1;
128
11fdf7f2 129 ceph_assert(erasures_count > 0);
7c673cae
FG
130 return jerasure_decode(erasures, data, coding, blocksize);
131}
132
133bool ErasureCodeJerasure::is_prime(int value)
134{
135 int prime55[] = {
136 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,
137 73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,
138 151,157,163,167,173,179,
139 181,191,193,197,199,211,223,227,229,233,239,241,251,257
140 };
141 int i;
142 for (i = 0; i < 55; i++)
143 if (value == prime55[i])
144 return true;
145 return false;
146}
147
148//
149// ErasureCodeJerasureReedSolomonVandermonde
150//
151void ErasureCodeJerasureReedSolomonVandermonde::jerasure_encode(char **data,
152 char **coding,
153 int blocksize)
154{
155 jerasure_matrix_encode(k, m, w, matrix, data, coding, blocksize);
156}
157
158int ErasureCodeJerasureReedSolomonVandermonde::jerasure_decode(int *erasures,
159 char **data,
160 char **coding,
161 int blocksize)
162{
163 return jerasure_matrix_decode(k, m, w, matrix, 1,
164 erasures, data, coding, blocksize);
165}
166
167unsigned ErasureCodeJerasureReedSolomonVandermonde::get_alignment() const
168{
169 if (per_chunk_alignment) {
170 return w * LARGEST_VECTOR_WORDSIZE;
171 } else {
172 unsigned alignment = k*w*sizeof(int);
173 if ( ((w*sizeof(int))%LARGEST_VECTOR_WORDSIZE) )
174 alignment = k*w*LARGEST_VECTOR_WORDSIZE;
175 return alignment;
176 }
177}
178
179int ErasureCodeJerasureReedSolomonVandermonde::parse(ErasureCodeProfile &profile,
180 ostream *ss)
181{
182 int err = 0;
183 err |= ErasureCodeJerasure::parse(profile, ss);
184 if (w != 8 && w != 16 && w != 32) {
185 *ss << "ReedSolomonVandermonde: w=" << w
186 << " must be one of {8, 16, 32} : revert to " << DEFAULT_W << std::endl;
187 profile["w"] = "8";
188 err |= to_int("w", profile, &w, DEFAULT_W, ss);
189 err = -EINVAL;
190 }
191 err |= to_bool("jerasure-per-chunk-alignment", profile,
192 &per_chunk_alignment, "false", ss);
193 return err;
194}
195
196void ErasureCodeJerasureReedSolomonVandermonde::prepare()
197{
198 matrix = reed_sol_vandermonde_coding_matrix(k, m, w);
199}
200
201//
202// ErasureCodeJerasureReedSolomonRAID6
203//
204void ErasureCodeJerasureReedSolomonRAID6::jerasure_encode(char **data,
205 char **coding,
206 int blocksize)
207{
208 reed_sol_r6_encode(k, w, data, coding, blocksize);
209}
210
211int ErasureCodeJerasureReedSolomonRAID6::jerasure_decode(int *erasures,
212 char **data,
213 char **coding,
214 int blocksize)
215{
216 return jerasure_matrix_decode(k, m, w, matrix, 1, erasures, data, coding, blocksize);
217}
218
219unsigned ErasureCodeJerasureReedSolomonRAID6::get_alignment() const
220{
221 if (per_chunk_alignment) {
222 return w * LARGEST_VECTOR_WORDSIZE;
223 } else {
224 unsigned alignment = k*w*sizeof(int);
225 if ( ((w*sizeof(int))%LARGEST_VECTOR_WORDSIZE) )
226 alignment = k*w*LARGEST_VECTOR_WORDSIZE;
227 return alignment;
228 }
229}
230
231int ErasureCodeJerasureReedSolomonRAID6::parse(ErasureCodeProfile &profile,
232 ostream *ss)
233{
234 int err = ErasureCodeJerasure::parse(profile, ss);
235 profile.erase("m");
236 m = 2;
237 if (w != 8 && w != 16 && w != 32) {
238 *ss << "ReedSolomonRAID6: w=" << w
239 << " must be one of {8, 16, 32} : revert to 8 " << std::endl;
240 profile["w"] = "8";
241 err |= to_int("w", profile, &w, DEFAULT_W, ss);
242 err = -EINVAL;
243 }
244 return err;
245}
246
247void ErasureCodeJerasureReedSolomonRAID6::prepare()
248{
249 matrix = reed_sol_r6_coding_matrix(k, w);
250}
251
252//
253// ErasureCodeJerasureCauchy
254//
255void ErasureCodeJerasureCauchy::jerasure_encode(char **data,
256 char **coding,
257 int blocksize)
258{
259 jerasure_schedule_encode(k, m, w, schedule,
260 data, coding, blocksize, packetsize);
261}
262
263int ErasureCodeJerasureCauchy::jerasure_decode(int *erasures,
264 char **data,
265 char **coding,
266 int blocksize)
267{
268 return jerasure_schedule_decode_lazy(k, m, w, bitmatrix,
269 erasures, data, coding, blocksize, packetsize, 1);
270}
271
272unsigned ErasureCodeJerasureCauchy::get_alignment() const
273{
274 if (per_chunk_alignment) {
275 unsigned alignment = w * packetsize;
276 unsigned modulo = alignment % LARGEST_VECTOR_WORDSIZE;
277 if (modulo)
278 alignment += LARGEST_VECTOR_WORDSIZE - modulo;
279 return alignment;
280 } else {
281 unsigned alignment = k*w*packetsize*sizeof(int);
282 if ( ((w*packetsize*sizeof(int))%LARGEST_VECTOR_WORDSIZE) )
283 alignment = k*w*packetsize*LARGEST_VECTOR_WORDSIZE;
284 return alignment;
285 }
286}
287
288int ErasureCodeJerasureCauchy::parse(ErasureCodeProfile &profile,
289 ostream *ss)
290{
291 int err = ErasureCodeJerasure::parse(profile, ss);
292 err |= to_int("packetsize", profile, &packetsize, DEFAULT_PACKETSIZE, ss);
293 err |= to_bool("jerasure-per-chunk-alignment", profile,
294 &per_chunk_alignment, "false", ss);
295 return err;
296}
297
298void ErasureCodeJerasureCauchy::prepare_schedule(int *matrix)
299{
300 bitmatrix = jerasure_matrix_to_bitmatrix(k, m, w, matrix);
301 schedule = jerasure_smart_bitmatrix_to_schedule(k, m, w, bitmatrix);
302}
303
b32b8144
FG
304ErasureCodeJerasureCauchy::~ErasureCodeJerasureCauchy()
305{
306 if (bitmatrix)
307 free(bitmatrix);
308 if (schedule)
309 jerasure_free_schedule(schedule);
310}
311
7c673cae
FG
312//
313// ErasureCodeJerasureCauchyOrig
314//
315void ErasureCodeJerasureCauchyOrig::prepare()
316{
317 int *matrix = cauchy_original_coding_matrix(k, m, w);
318 prepare_schedule(matrix);
319 free(matrix);
320}
321
322//
323// ErasureCodeJerasureCauchyGood
324//
325void ErasureCodeJerasureCauchyGood::prepare()
326{
327 int *matrix = cauchy_good_general_coding_matrix(k, m, w);
328 prepare_schedule(matrix);
329 free(matrix);
330}
331
332//
333// ErasureCodeJerasureLiberation
334//
335ErasureCodeJerasureLiberation::~ErasureCodeJerasureLiberation()
336{
337 if (bitmatrix)
338 free(bitmatrix);
339 if (schedule)
340 jerasure_free_schedule(schedule);
341}
342
343void ErasureCodeJerasureLiberation::jerasure_encode(char **data,
344 char **coding,
345 int blocksize)
346{
347 jerasure_schedule_encode(k, m, w, schedule, data,
348 coding, blocksize, packetsize);
349}
350
351int ErasureCodeJerasureLiberation::jerasure_decode(int *erasures,
352 char **data,
353 char **coding,
354 int blocksize)
355{
356 return jerasure_schedule_decode_lazy(k, m, w, bitmatrix, erasures, data,
357 coding, blocksize, packetsize, 1);
358}
359
360unsigned ErasureCodeJerasureLiberation::get_alignment() const
361{
362 unsigned alignment = k*w*packetsize*sizeof(int);
363 if ( ((w*packetsize*sizeof(int))%LARGEST_VECTOR_WORDSIZE) )
364 alignment = k*w*packetsize*LARGEST_VECTOR_WORDSIZE;
365 return alignment;
366}
367
368bool ErasureCodeJerasureLiberation::check_k(ostream *ss) const
369{
370 if (k > w) {
371 *ss << "k=" << k << " must be less than or equal to w=" << w << std::endl;
372 return false;
373 } else {
374 return true;
375 }
376}
377
378bool ErasureCodeJerasureLiberation::check_w(ostream *ss) const
379{
380 if (w <= 2 || !is_prime(w)) {
381 *ss << "w=" << w << " must be greater than two and be prime" << std::endl;
382 return false;
383 } else {
384 return true;
385 }
386}
387
388bool ErasureCodeJerasureLiberation::check_packetsize_set(ostream *ss) const
389{
390 if (packetsize == 0) {
391 *ss << "packetsize=" << packetsize << " must be set" << std::endl;
392 return false;
393 } else {
394 return true;
395 }
396}
397
398bool ErasureCodeJerasureLiberation::check_packetsize(ostream *ss) const
399{
400 if ((packetsize%(sizeof(int))) != 0) {
401 *ss << "packetsize=" << packetsize
402 << " must be a multiple of sizeof(int) = " << sizeof(int) << std::endl;
403 return false;
404 } else {
405 return true;
406 }
407}
408
409int ErasureCodeJerasureLiberation::revert_to_default(ErasureCodeProfile &profile,
410 ostream *ss)
411{
412 int err = 0;
413 *ss << "reverting to k=" << DEFAULT_K << ", w="
414 << DEFAULT_W << ", packetsize=" << DEFAULT_PACKETSIZE << std::endl;
415 profile["k"] = DEFAULT_K;
416 err |= to_int("k", profile, &k, DEFAULT_K, ss);
417 profile["w"] = DEFAULT_W;
418 err |= to_int("w", profile, &w, DEFAULT_W, ss);
419 profile["packetsize"] = DEFAULT_PACKETSIZE;
420 err |= to_int("packetsize", profile, &packetsize, DEFAULT_PACKETSIZE, ss);
421 return err;
422}
423
424int ErasureCodeJerasureLiberation::parse(ErasureCodeProfile &profile,
425 ostream *ss)
426{
427 int err = ErasureCodeJerasure::parse(profile, ss);
428 err |= to_int("packetsize", profile, &packetsize, DEFAULT_PACKETSIZE, ss);
429
430 bool error = false;
431 if (!check_k(ss))
432 error = true;
433 if (!check_w(ss))
434 error = true;
435 if (!check_packetsize_set(ss) || !check_packetsize(ss))
436 error = true;
437 if (error) {
438 revert_to_default(profile, ss);
439 err = -EINVAL;
440 }
441 return err;
442}
443
444void ErasureCodeJerasureLiberation::prepare()
445{
446 bitmatrix = liberation_coding_bitmatrix(k, w);
447 schedule = jerasure_smart_bitmatrix_to_schedule(k, m, w, bitmatrix);
448}
449
450//
451// ErasureCodeJerasureBlaumRoth
452//
453bool ErasureCodeJerasureBlaumRoth::check_w(ostream *ss) const
454{
11fdf7f2 455 // back in Firefly, w = 7 was the default and produced usable
7c673cae
FG
456 // chunks. Tolerate this value for backward compatibility.
457 if (w == 7)
458 return true;
459 if (w <= 2 || !is_prime(w+1)) {
460 *ss << "w=" << w << " must be greater than two and "
461 << "w+1 must be prime" << std::endl;
462 return false;
463 } else {
464 return true;
465 }
466}
467
468void ErasureCodeJerasureBlaumRoth::prepare()
469{
470 bitmatrix = blaum_roth_coding_bitmatrix(k, w);
471 schedule = jerasure_smart_bitmatrix_to_schedule(k, m, w, bitmatrix);
472}
473
474//
475// ErasureCodeJerasureLiber8tion
476//
477int ErasureCodeJerasureLiber8tion::parse(ErasureCodeProfile &profile,
478 ostream *ss)
479{
480 int err = ErasureCodeJerasure::parse(profile, ss);
481 profile.erase("m");
482 err |= to_int("m", profile, &m, DEFAULT_M, ss);
483 profile.erase("w");
484 err |= to_int("w", profile, &w, DEFAULT_W, ss);
485 err |= to_int("packetsize", profile, &packetsize, DEFAULT_PACKETSIZE, ss);
486
487 bool error = false;
488 if (!check_k(ss))
489 error = true;
490 if (!check_packetsize_set(ss))
491 error = true;
492 if (error) {
493 revert_to_default(profile, ss);
494 err = -EINVAL;
495 }
496 return err;
497}
498
499void ErasureCodeJerasureLiber8tion::prepare()
500{
501 bitmatrix = liber8tion_coding_bitmatrix(k);
502 schedule = jerasure_smart_bitmatrix_to_schedule(k, m, w, bitmatrix);
503}