Merge "feature: LRC (locally repairable code) backend"
This commit is contained in:
@@ -106,6 +106,22 @@ Provided by isa-l
|
||||
submatrix, then calculate `E = inv(V′) × V`. This makes a systematic code
|
||||
that is optimal for all `k` and `m`.
|
||||
|
||||
- `isa_l_rs_lrc` (added in liberasurecode 1.8.0)
|
||||
|
||||
Uses the Reed-Solomon functions provided by isa-l with an encoding matrix
|
||||
provided by liberasurecode. Similar to `isa_l_rs_vand_inv`, but adds a new
|
||||
parameter `l` for the number of "local parities". To construct the encoding
|
||||
matrix, start with an `isa_l_rs_vand_inv` encoding matrix. The first `m - l`
|
||||
parity lines are left as "global parities".
|
||||
The last `l` lines are all crafted from the "next" global parity, this is
|
||||
done in order to combine them and get one global parity and ensure the
|
||||
original data may be decoded from any `k + l - 1` unique fragments.
|
||||
The last `l` lines are each assigned a group of `⌊k / l⌋` or `⌈k / l⌉` data
|
||||
fragments; within each line, the columns corresponding to those data
|
||||
fragments are retained and all others are set to zero. This reduces the
|
||||
minimum number of fragments required to reconstruct data or local parity
|
||||
fragments, provided the other fragments in the group are available.
|
||||
|
||||
- `isa_l_rs_cauchy` (added in liberasurecode 1.4.0, pyeclib 1.4.0)
|
||||
|
||||
Uses the Reed-Solomon functions provided by isa-l with
|
||||
@@ -125,8 +141,8 @@ Proprietary
|
||||
Classifications
|
||||
===============
|
||||
|
||||
Required Fragments
|
||||
------------------
|
||||
Required Fragments to Decode
|
||||
----------------------------
|
||||
### n ≡ k
|
||||
|
||||
Most supported backends are optimal erasure codes, where any `k` fragments
|
||||
@@ -138,6 +154,11 @@ The flat XOR codes require more than `k` fragments to decode in the general
|
||||
case. In particular, `flat_xor_hd3` requires at least `n ≡ k + m - 2`
|
||||
fragments and `flat_xor_hd4` requires at least `n ≡ k + m - 3`.
|
||||
|
||||
LRC codes are intentionally not optimal, as each local parity is only useful
|
||||
in recovering the original data if there is at least one data fragment missing
|
||||
in the same local group. However, decoding will always succeed with
|
||||
`n ≡ k + l - 1` unique fragments.
|
||||
|
||||
Systematic vs. Non-systematic
|
||||
-----------------------------
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ typedef enum {
|
||||
EC_BACKEND_ISA_L_RS_CAUCHY = 7,
|
||||
EC_BACKEND_LIBPHAZR = 8,
|
||||
EC_BACKEND_ISA_L_RS_VAND_INV = 9,
|
||||
EC_BACKEND_ISA_L_RS_LRC = 10,
|
||||
EC_BACKENDS_MAX,
|
||||
} ec_backend_id_t;
|
||||
|
||||
@@ -80,6 +81,9 @@ struct ec_args {
|
||||
struct {
|
||||
uint64_t arg1; /* sample arg */
|
||||
} null_args; /* args specific to the null codes */
|
||||
struct {
|
||||
int l; /* number of local parities */
|
||||
} lrc_args; /* args specific to locally recoverable codes */
|
||||
struct {
|
||||
uint64_t x, y; /* reserved for future expansion */
|
||||
uint64_t z, a; /* reserved for future expansion */
|
||||
|
||||
@@ -57,6 +57,7 @@ typedef struct {
|
||||
unsigned char *encode_tables;
|
||||
int k;
|
||||
int m;
|
||||
int l; //local parities
|
||||
int w;
|
||||
} isa_l_descriptor;
|
||||
|
||||
@@ -71,3 +72,67 @@ int isa_l_element_size(void* desc);
|
||||
int isa_l_exit(void *desc);
|
||||
void * isa_l_common_init(struct ec_backend_args *args, void *backend_sohandle,
|
||||
const char* gen_matrix_func_name);
|
||||
|
||||
/* global helper functions */
|
||||
static inline int get_num_missing_elements(int *missing_idxs)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (missing_idxs[i] > -1) {
|
||||
i++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline void mult_and_xor_row(unsigned char *to_row,
|
||||
unsigned char *from_row,
|
||||
unsigned char val,
|
||||
int num_elems,
|
||||
gf_mul_func gf_mul)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_elems; i++) {
|
||||
to_row[i] ^= gf_mul(val, from_row[i]);
|
||||
}
|
||||
}
|
||||
/* LRC helper functions */
|
||||
static inline int local_group_size(int k, int l, int n) {
|
||||
int extra = k % l;
|
||||
if (n < extra) {
|
||||
return (k / l) + 1;
|
||||
} else {
|
||||
return k / l;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int local_group_data_lower(int k, int l, int n) {
|
||||
int extra = k % l;
|
||||
int group_size = (k / l) + 1;
|
||||
if (n < extra) {
|
||||
return n * group_size;
|
||||
} else {
|
||||
return extra * group_size + (n - extra) * (group_size - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int local_group_data_upper(int k, int l, int n) {
|
||||
return local_group_data_lower(k, l, n + 1);
|
||||
}
|
||||
|
||||
static inline int local_group_for_data(int k, int l, int n) {
|
||||
int extra = k % l;
|
||||
/**
|
||||
* Start off assuming larger groups; we'll adjust them
|
||||
* smaller later if needed
|
||||
*/
|
||||
int group_size = (k / l) + 1;
|
||||
if (n < extra * group_size) {
|
||||
return n / group_size;
|
||||
} else {
|
||||
n -= extra * group_size;
|
||||
group_size--;
|
||||
return extra + n / group_size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ liberasurecode_la_SOURCES = \
|
||||
backends/isa-l/isa_l_common.c \
|
||||
backends/isa-l/isa_l_rs_vand.c \
|
||||
backends/isa-l/isa_l_rs_vand_inv.c \
|
||||
backends/isa-l/isa_l_rs_lrc.c \
|
||||
backends/isa-l/isa_l_rs_cauchy.c \
|
||||
backends/rs_vand/liberasurecode_rs_vand.c \
|
||||
backends/shss/shss.c \
|
||||
|
||||
@@ -68,7 +68,6 @@ static unsigned char* isa_l_get_decode_matrix(int k, int m, unsigned char *encod
|
||||
}
|
||||
l++;
|
||||
}
|
||||
|
||||
if (i != k) {
|
||||
free(decode_matrix);
|
||||
decode_matrix = NULL;
|
||||
@@ -77,30 +76,6 @@ static unsigned char* isa_l_get_decode_matrix(int k, int m, unsigned char *encod
|
||||
return decode_matrix;
|
||||
}
|
||||
|
||||
static int get_num_missing_elements(int *missing_idxs)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (missing_idxs[i] > -1) {
|
||||
i++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static void mult_and_xor_row(unsigned char *to_row,
|
||||
unsigned char *from_row,
|
||||
unsigned char val,
|
||||
int num_elems,
|
||||
gf_mul_func gf_mul)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_elems; i++) {
|
||||
to_row[i] ^= gf_mul(val, from_row[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Add in missing parity rows and adjust the inverse_rows to
|
||||
* be used for parity.
|
||||
|
||||
872
src/backends/isa-l/isa_l_rs_lrc.c
Normal file
872
src/backends/isa-l/isa_l_rs_lrc.c
Normal file
@@ -0,0 +1,872 @@
|
||||
/*
|
||||
* Copyright 2025 aitassou
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY
|
||||
* THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* isa_l_rs_lrc backend implementation
|
||||
*
|
||||
* vi: set noai tw=79 ts=4 sw=4:
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "erasurecode_backend.h"
|
||||
#include "erasurecode_helpers.h"
|
||||
#include "isa_l_common.h"
|
||||
|
||||
#define ISA_L_RS_LRC_LIB_MAJOR 1
|
||||
#define ISA_L_RS_LRC_LIB_MINOR 0
|
||||
#define ISA_L_RS_LRC_LIB_REV 0
|
||||
#define ISA_L_RS_LRC_LIB_VER_STR "1.0"
|
||||
#define ISA_L_RS_LRC_LIB_NAME "isa_l_rs_vand"
|
||||
#if defined(__MACOS__) || defined(__MACOSX__) || defined(__OSX__) || defined(__APPLE__)
|
||||
#define ISA_L_RS_LRC_SO_NAME "libisal" LIBERASURECODE_SO_SUFFIX ".dylib"
|
||||
#else
|
||||
#define ISA_L_RS_LRC_SO_NAME "libisal" LIBERASURECODE_SO_SUFFIX ".so.2"
|
||||
#endif
|
||||
|
||||
/* Forward declarations */
|
||||
struct ec_backend_common backend_isa_l_rs_lrc;
|
||||
|
||||
static int gen_encoding_matrix(isa_l_descriptor * desc, int m, int k) {
|
||||
int i, j, ret = 1;
|
||||
unsigned char p, gen = 2;
|
||||
unsigned char *tmp = NULL;
|
||||
unsigned char *tmp_inv_k = NULL;
|
||||
int n = m + k;
|
||||
int l = desc->l; //local parities
|
||||
int r = m - l; //global parities
|
||||
|
||||
/* Build a (k+m)*k Vandermonde matrix, A */
|
||||
tmp = malloc(sizeof(char) * n * k);
|
||||
if (tmp == NULL) {
|
||||
goto error_free;
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
p = 1;
|
||||
for (j = 0; j < k; j++) {
|
||||
tmp[k * i + j] = p;
|
||||
p = desc->gf_mul(p, gen);
|
||||
}
|
||||
if (i < k + r) {
|
||||
gen = desc->gf_mul(gen, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/* It starts with a k*k submatrix, A'; calculate inv(A') */
|
||||
tmp_inv_k = malloc(sizeof(char) * k * k);
|
||||
if (tmp_inv_k == NULL) {
|
||||
goto error_free;
|
||||
}
|
||||
int im_ret = desc->gf_invert_matrix(tmp, tmp_inv_k, k);
|
||||
if (im_ret < 0) {
|
||||
/**
|
||||
* Should never happen as it's a proper Vandermonde matrix,
|
||||
* but belt & bracers...
|
||||
*/
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
/**
|
||||
* Now we're ready to build the encoding matrix: inv(A') * A.
|
||||
* Save some multiplies by going straight to I for the start.
|
||||
*/
|
||||
memset(desc->matrix, 0, k * n);
|
||||
for (i = 0; i < k; i++)
|
||||
desc->matrix[k * i + i] = 1;
|
||||
|
||||
/* Then multiply inv(A') by the rest of A for the parities */
|
||||
for (i = k; i < n; i++) {
|
||||
for (j = 0; j < k; j++) {
|
||||
p = 0;
|
||||
for (int u = 0; u < k; u++) {
|
||||
p ^= desc->gf_mul(tmp[(i*k)+u], tmp_inv_k[(u*k)+j]);
|
||||
}
|
||||
desc->matrix[(i*k)+j] = p;
|
||||
}
|
||||
}
|
||||
|
||||
int group_offset = 0;
|
||||
for (i = 0; i < l; i++) {
|
||||
int frag_num = k + r + i;
|
||||
int group_size = local_group_size(k, l, i);
|
||||
for (j = 0; j < k; j++) {
|
||||
if ( j < group_offset || j >= group_offset + group_size)
|
||||
desc->matrix[k * frag_num + j] = 0;
|
||||
}
|
||||
group_offset += group_size;
|
||||
}
|
||||
ret = 0;
|
||||
error_free:
|
||||
free(tmp_inv_k);
|
||||
free(tmp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void * isa_l_rs_lrc_init(struct ec_backend_args *args,
|
||||
void *backend_sohandle)
|
||||
{
|
||||
isa_l_descriptor *desc = NULL;
|
||||
|
||||
desc = (isa_l_descriptor *)malloc(sizeof(isa_l_descriptor));
|
||||
if (NULL == desc) {
|
||||
return NULL;
|
||||
}
|
||||
/* Set this early so we can have a single error path */
|
||||
desc->matrix = NULL;
|
||||
|
||||
desc->k = args->uargs.k;
|
||||
desc->m = args->uargs.m;
|
||||
desc->l = args->uargs.priv_args1.lrc_args.l;
|
||||
if (desc->l < 1 || desc->l > desc->m || (2 * desc->l > desc->k)) {
|
||||
goto error;
|
||||
}
|
||||
if (args->uargs.w <= 0)
|
||||
args->uargs.w = ISA_L_W;
|
||||
desc->w = args->uargs.w;
|
||||
|
||||
/* validate EC arguments */
|
||||
{
|
||||
long long max_symbols = 1LL << desc->w;
|
||||
if ((desc->k + desc->m) > max_symbols) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ISO C forbids casting a void* to a function pointer.
|
||||
* Since dlsym return returns a void*, we use this union to
|
||||
* "transform" the void* to a function pointer.
|
||||
*/
|
||||
union {
|
||||
ec_encode_data_func encodep;
|
||||
ec_init_tables_func init_tablesp;
|
||||
gf_gen_encoding_matrix_func gen_matrixp;
|
||||
gf_invert_matrix_func invert_matrixp;
|
||||
gf_mul_func gf_mulp;
|
||||
void *vptr;
|
||||
} func_handle = {.vptr = NULL};
|
||||
|
||||
/* fill in function addresses */
|
||||
func_handle.vptr = NULL;
|
||||
func_handle.vptr = dlsym(backend_sohandle, "ec_encode_data");
|
||||
desc->ec_encode_data = func_handle.encodep;
|
||||
if (NULL == desc->ec_encode_data) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
func_handle.vptr = NULL;
|
||||
func_handle.vptr = dlsym(backend_sohandle, "ec_init_tables");
|
||||
desc->ec_init_tables = func_handle.init_tablesp;
|
||||
if (NULL == desc->ec_init_tables) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
func_handle.vptr = NULL;
|
||||
func_handle.vptr = dlsym(backend_sohandle, "gf_invert_matrix");
|
||||
desc->gf_invert_matrix = func_handle.invert_matrixp;
|
||||
if (NULL == desc->gf_invert_matrix) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
func_handle.vptr = NULL;
|
||||
func_handle.vptr = dlsym(backend_sohandle, "gf_mul");
|
||||
desc->gf_mul = func_handle.gf_mulp;
|
||||
if (NULL == desc->gf_mul) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
desc->matrix = malloc(sizeof(char) * desc->k * (desc->k + desc->m));
|
||||
if (NULL == desc->matrix) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (0 != gen_encoding_matrix(desc, desc->m, desc->k)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the tables for encoding
|
||||
*/
|
||||
desc->encode_tables = malloc(sizeof(unsigned char) *
|
||||
(desc->k * desc->m * 32));
|
||||
if (NULL == desc->encode_tables) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
desc->ec_init_tables(desc->k, desc->m,
|
||||
&desc->matrix[desc->k * desc->k],
|
||||
desc->encode_tables);
|
||||
|
||||
return desc;
|
||||
|
||||
error:
|
||||
free(desc->matrix);
|
||||
free(desc);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int isa_l_rs_lrc_check_reconstruct_fragments(void *desc, int *missing_idxs, int destination_idx) {
|
||||
isa_l_descriptor *d = (isa_l_descriptor*)desc;
|
||||
uint64_t missing_bm = convert_list_to_bitmap(missing_idxs);
|
||||
int missing_locals, local_group;
|
||||
if (destination_idx < d->k) {
|
||||
local_group = local_group_for_data(d->k, d->l, destination_idx);
|
||||
int local_parity_index = d->k + d->m - d->l + local_group;
|
||||
missing_locals = (1 << local_parity_index) & missing_bm;
|
||||
for (
|
||||
int i = local_group_data_lower(d->k, d->l, local_group);
|
||||
i < local_group_data_upper(d->k, d->l, local_group);
|
||||
i++
|
||||
) {
|
||||
if (i != destination_idx)
|
||||
missing_locals |= (1 << i) & missing_bm;
|
||||
}
|
||||
if (!missing_locals) {
|
||||
return 0;
|
||||
}
|
||||
} else if (destination_idx >= d->k + d->m - d->l) {
|
||||
local_group = destination_idx - d->k - d->m + d->l;
|
||||
missing_locals = 0;
|
||||
for (
|
||||
int i = local_group_data_lower(d->k, d->l, local_group);
|
||||
i < local_group_data_upper(d->k, d->l, local_group);
|
||||
i++
|
||||
) {
|
||||
missing_locals |= (1 << i) & missing_bm;
|
||||
}
|
||||
if (!missing_locals) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// if we haven't returned yet, we can't do local-only reconstruction
|
||||
int useful_frags = 0, can_use_local_parity = 0;
|
||||
for (int i = 0; i < d->k + d->m; i++) {
|
||||
if (i < d->k) {
|
||||
if ((1 << i) & missing_bm) {
|
||||
local_group = local_group_for_data(d->k, d->l, i);
|
||||
can_use_local_parity |= 1 << (d->k + d->m - d->l + local_group);
|
||||
} else {
|
||||
useful_frags++;
|
||||
}
|
||||
} else if (i >= d->k + d->m - d->l) {
|
||||
if ((1 << i) & can_use_local_parity && !((1 << i) & missing_bm)) {
|
||||
useful_frags++;
|
||||
}
|
||||
} else {
|
||||
if (!((1 << i) & missing_bm)) {
|
||||
useful_frags++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (useful_frags < d->k) {
|
||||
return -EINSUFFFRAGS;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For the time being, we only claim compatibility with versions that
|
||||
* match exactly
|
||||
*/
|
||||
static bool isa_l_rs_lrc_is_compatible_with(uint32_t version) {
|
||||
return version == backend_isa_l_rs_lrc.ec_backend_version;
|
||||
}
|
||||
|
||||
static unsigned char* get_lrc_inverse_rows(int k,
|
||||
int m,
|
||||
int min_range,
|
||||
int max_range,
|
||||
int missing_local_parity,
|
||||
unsigned char *decode_inverse,
|
||||
unsigned char* encode_matrix,
|
||||
uint64_t missing_bm,
|
||||
gf_mul_func gf_mul)
|
||||
{
|
||||
int num_missing_elements = 0;
|
||||
for (int i = 0; i < EC_MAX_FRAGMENTS; i++)
|
||||
if ((1LLU << i) & missing_bm)
|
||||
num_missing_elements++;
|
||||
unsigned char *inverse_rows = (unsigned char*)malloc(sizeof(unsigned
|
||||
char*) * k * num_missing_elements);
|
||||
int i, j, l = 0;
|
||||
|
||||
if (NULL == inverse_rows) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int matrix_size = max_range - min_range;
|
||||
|
||||
int encode_matrix_size = (matrix_size == 0 ||matrix_size == k || missing_local_parity) ? k : matrix_size;
|
||||
|
||||
int n = k + m;
|
||||
|
||||
memset(inverse_rows, 0, sizeof(unsigned
|
||||
char*) * matrix_size * num_missing_elements);
|
||||
|
||||
/*
|
||||
* Fill in rows for missing data
|
||||
*/
|
||||
for (i = 0; i < matrix_size; i++) {
|
||||
if ((1 << i) & (missing_bm>>min_range)) {
|
||||
for (j = 0; j < matrix_size; j++) {
|
||||
inverse_rows[(l * matrix_size) + j] = decode_inverse[(i * matrix_size) + j];
|
||||
}
|
||||
l++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Process missing parity.
|
||||
*
|
||||
* Start with an all-zero row.
|
||||
*
|
||||
* For each data element, if the data element is:
|
||||
*
|
||||
* Available: XOR the corresponding coefficient from the
|
||||
* encoding matrix.
|
||||
*
|
||||
* Unavailable: multiply corresponding coefficient with
|
||||
* the row that corresponds to the missing data in inverse_rows
|
||||
* and XOR the resulting row with this row.
|
||||
*/
|
||||
for (i = k; i < n; i++) {
|
||||
// Parity is missing
|
||||
if ((1 << i) & (missing_bm)) {
|
||||
int d_idx_avail = 0;
|
||||
int d_idx_unavail = 0;
|
||||
for (j = min_range; j < max_range; j++) {
|
||||
// This data is available, so we can use the encode matrix
|
||||
if (((1 << j) & (missing_bm)) == 0) {
|
||||
inverse_rows[(l * matrix_size) + d_idx_avail] ^= encode_matrix[(i * encode_matrix_size) + j];
|
||||
d_idx_avail++;
|
||||
} else {
|
||||
mult_and_xor_row(&inverse_rows[l * matrix_size],
|
||||
&inverse_rows[d_idx_unavail * matrix_size],
|
||||
encode_matrix[(i * encode_matrix_size) + j],
|
||||
k,
|
||||
gf_mul);
|
||||
d_idx_unavail++;
|
||||
}
|
||||
}
|
||||
l++;
|
||||
}
|
||||
}
|
||||
return inverse_rows;
|
||||
}
|
||||
|
||||
static unsigned char* isa_l_lrc_get_decode_matrix(int k, int m, unsigned local_parity, unsigned char *encode_matrix, uint64_t missing_bm, int *used_idxs, int *use_combined_parity)
|
||||
{
|
||||
int i = 0, j, locate = 0;
|
||||
int n = k + m;
|
||||
int global_parity = m - local_parity;
|
||||
int group_offset = 0;
|
||||
uint64_t missing_local_parity = 0;
|
||||
uint64_t use_parity = 0;
|
||||
|
||||
int total_missing = 0;
|
||||
|
||||
unsigned char *decode_matrix = malloc(sizeof(unsigned char) * k * k);
|
||||
if( NULL == decode_matrix ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (int v = 0; v < local_parity; v++) {
|
||||
int group_size = local_group_size(k, local_parity, v);
|
||||
for (int u = group_offset; u < group_offset + group_size; u++) {
|
||||
if ((1 << u) & missing_bm) {
|
||||
use_parity |= (1 << (k + global_parity + v));
|
||||
}
|
||||
}
|
||||
group_offset += group_size;
|
||||
|
||||
missing_local_parity |= (1 << (k + global_parity + v)) & missing_bm;
|
||||
}
|
||||
|
||||
for (locate = 0; i < k && locate < k + global_parity; locate++) {
|
||||
if (((1 << locate) & missing_bm)) {
|
||||
total_missing++;
|
||||
continue;
|
||||
}
|
||||
for (j = 0; j < k; j++) {
|
||||
decode_matrix[(k * i) + j] = encode_matrix[(k * locate) + j];
|
||||
}
|
||||
used_idxs[locate] = 1;
|
||||
i++;
|
||||
}
|
||||
// we can simplify here as total_missing counts only missing data + global parity
|
||||
if (i < k && !missing_local_parity && (total_missing == global_parity + 1)) {
|
||||
// Set flag to indicate we can use combined parity in case of
|
||||
// g + 1 errors and no local parity is missing
|
||||
*use_combined_parity = 1;
|
||||
// We can combine all the local parities into a single global parity
|
||||
group_offset = 0;
|
||||
for (int v = 0; v < local_parity; v++) {
|
||||
int group_size = local_group_size(k, local_parity, v);
|
||||
for (int u = group_offset; u < group_offset + group_size; u++) {
|
||||
decode_matrix[(i * k) + u] = encode_matrix[((locate + v) * k) + u];
|
||||
}
|
||||
group_offset += group_size;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (i < k) {
|
||||
// Still not enough? Well, let's add what local parities we have,
|
||||
// see if we can get lucky
|
||||
for (locate = k + global_parity; i < k && locate < n; locate++) {
|
||||
if (use_parity & (1 << locate) && !((1 << locate) & missing_bm)) {
|
||||
for (j = 0; j < k; j++) {
|
||||
decode_matrix[(k * i) + j] = encode_matrix[(k * locate) + j];
|
||||
}
|
||||
used_idxs[locate] = 1;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i != k) {
|
||||
free(decode_matrix);
|
||||
decode_matrix = NULL;
|
||||
}
|
||||
return decode_matrix;
|
||||
}
|
||||
|
||||
|
||||
static int isa_l_lrc_decode(void *desc, char **data, char **parity,
|
||||
int *missing_idxs, int blocksize)
|
||||
{
|
||||
isa_l_descriptor *isa_l_desc = (isa_l_descriptor*)desc;
|
||||
|
||||
unsigned char *g_tbls = NULL;
|
||||
unsigned char *decode_matrix = NULL;
|
||||
unsigned char *decode_inverse = NULL;
|
||||
unsigned char *inverse_rows = NULL;
|
||||
unsigned char **decoded_elements = NULL;
|
||||
unsigned char **available_fragments = NULL;
|
||||
int k = isa_l_desc->k;
|
||||
int m = isa_l_desc->m;
|
||||
int local_parity = isa_l_desc->l;
|
||||
int n = k + m;
|
||||
int ret = -1;
|
||||
int i, j;
|
||||
unsigned char *combined_local_parities = NULL;
|
||||
int use_combined_parity = 0;
|
||||
|
||||
int num_missing_elements = get_num_missing_elements(missing_idxs);
|
||||
uint64_t missing_bm = convert_list_to_bitmap(missing_idxs);
|
||||
|
||||
int *used_idxs = calloc(n, sizeof(int));
|
||||
if(NULL == used_idxs) {
|
||||
goto out;
|
||||
}
|
||||
decode_matrix = isa_l_lrc_get_decode_matrix(k, m, local_parity, isa_l_desc->matrix, missing_bm, used_idxs, &use_combined_parity);
|
||||
|
||||
if (NULL == decode_matrix) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
decode_inverse = (unsigned char*)malloc(sizeof(unsigned char) * k * k);
|
||||
|
||||
if (NULL == decode_inverse) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
int im_ret = isa_l_desc->gf_invert_matrix(decode_matrix, decode_inverse, k);
|
||||
if (im_ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Generate g_tbls from computed decode matrix (k x k) matrix
|
||||
g_tbls = malloc(sizeof(unsigned char) * (k * m * 32));
|
||||
if (NULL == g_tbls) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
inverse_rows = get_lrc_inverse_rows(k, m, 0, k, 0, decode_inverse, isa_l_desc->matrix, missing_bm, isa_l_desc->gf_mul);
|
||||
|
||||
decoded_elements = (unsigned char**)malloc(sizeof(unsigned char*)*num_missing_elements);
|
||||
if (NULL == decoded_elements) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
available_fragments = (unsigned char**)malloc(sizeof(unsigned char*)*k);
|
||||
if (NULL == available_fragments) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
uint64_t missing_local_parities = 0;
|
||||
for (j = n - local_parity; j < n; j++) {
|
||||
missing_local_parities |= (missing_bm & (1 << j));
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < n - local_parity && j < k; i++) {
|
||||
if (missing_bm & (1 << i)) {
|
||||
continue;
|
||||
}
|
||||
if (i < k) {
|
||||
available_fragments[j] = (unsigned char*)data[i];
|
||||
j++;
|
||||
} else {
|
||||
if (used_idxs[i]) {
|
||||
available_fragments[j] = (unsigned char*)parity[i - k];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (j < k && !missing_local_parities && use_combined_parity) {
|
||||
combined_local_parities = calloc(blocksize, sizeof(unsigned char));
|
||||
if (NULL == combined_local_parities) {
|
||||
goto out;
|
||||
}
|
||||
for (i = n - local_parity; i < n; i++) {
|
||||
for (int x = 0; x < blocksize; x++) {
|
||||
combined_local_parities[x] ^= parity[i - k][x];
|
||||
}
|
||||
}
|
||||
available_fragments[j] = combined_local_parities;
|
||||
j++;
|
||||
}
|
||||
for (i = n - local_parity; i < n && j < k; i++) {
|
||||
if (used_idxs[i]) {
|
||||
available_fragments[j] = (unsigned char*)parity[i-k];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
// Grab pointers to memory needed for missing data fragments
|
||||
j = 0;
|
||||
for (i = 0; i < k; i++) {
|
||||
if (missing_bm & (1 << i)) {
|
||||
decoded_elements[j] = (unsigned char*)data[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
for (i = k; i < n; i++) {
|
||||
if (missing_bm & (1 << i)) {
|
||||
decoded_elements[j] = (unsigned char*)parity[i - k];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
isa_l_desc->ec_init_tables(k, num_missing_elements, inverse_rows, g_tbls);
|
||||
|
||||
isa_l_desc->ec_encode_data(blocksize, k, num_missing_elements, g_tbls, available_fragments,
|
||||
decoded_elements);
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
free(g_tbls);
|
||||
free(combined_local_parities);
|
||||
free(decode_matrix);
|
||||
free(decode_inverse);
|
||||
free(inverse_rows);
|
||||
free(decoded_elements);
|
||||
free(available_fragments);
|
||||
free(used_idxs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned char* isa_l_lrc_get_reconstruct_matrix(
|
||||
int k, int m, unsigned local_parity, int destination_idx,
|
||||
unsigned char *encode_matrix, uint64_t *missing_bm, int *used_idxs,
|
||||
int *min_col, int *max_col, int *mx_size, int *missing_local_parity, int *use_combined_parity)
|
||||
{
|
||||
unsigned char *decode_matrix = NULL;
|
||||
uint64_t useful_mask = 0;
|
||||
|
||||
int min_range=0, max_range=0;
|
||||
if (destination_idx < k) {
|
||||
// reconstructing a data frag; see if we can stay local
|
||||
int local_group = local_group_for_data(k, local_parity, destination_idx);
|
||||
min_range = local_group_data_lower(k, local_parity, local_group);
|
||||
max_range = local_group_data_upper(k, local_parity, local_group);
|
||||
int local_parity_idx = k + m - local_parity + local_group;
|
||||
int missing_local = (1 << local_parity_idx) & *missing_bm;
|
||||
for (int i = min_range; !missing_local && i < max_range; i++) {
|
||||
useful_mask |= 1 << i;
|
||||
if (i == destination_idx) {
|
||||
// We already knew we were missing *that* one...
|
||||
continue;
|
||||
}
|
||||
missing_local |= (1 << i) & *missing_bm;
|
||||
}
|
||||
if (!missing_local) {
|
||||
// We have everything we need!
|
||||
useful_mask |= 1 << local_parity_idx;
|
||||
*missing_bm &= useful_mask;
|
||||
*mx_size = max_range - min_range;
|
||||
decode_matrix = malloc(sizeof(unsigned char) * (*mx_size) * (*mx_size));
|
||||
if (NULL == decode_matrix) {
|
||||
return NULL;
|
||||
}
|
||||
int col = 0;
|
||||
for (int enc_idx = min_range; enc_idx < max_range; enc_idx++) {
|
||||
if (enc_idx == destination_idx)
|
||||
continue;
|
||||
for (int j = min_range; j < max_range; j++) {
|
||||
decode_matrix[(*mx_size * col) + j - min_range] = encode_matrix[(k * enc_idx) + j];
|
||||
}
|
||||
used_idxs[enc_idx] = 1;
|
||||
col++;
|
||||
}
|
||||
// add local parity
|
||||
for (int j = min_range; j < max_range; j++) {
|
||||
decode_matrix[*mx_size * col + j - min_range] = encode_matrix[(k * local_parity_idx) + j];
|
||||
}
|
||||
used_idxs[local_parity_idx] = 1;
|
||||
}
|
||||
}
|
||||
if (destination_idx >= k + m - local_parity) {
|
||||
// reconstructing a local parity frag; see if we can use local data
|
||||
int local_group = destination_idx - k - m + local_parity;
|
||||
min_range = local_group_data_lower(k, local_parity, local_group);
|
||||
max_range = local_group_data_upper(k, local_parity, local_group);
|
||||
int missing_local = 0;
|
||||
for (int i = min_range; !missing_local && i < max_range; i++) {
|
||||
useful_mask |= 1 << i;
|
||||
missing_local |= (1 << i) & *missing_bm;
|
||||
}
|
||||
if (!missing_local) {
|
||||
// We have everything we need!
|
||||
useful_mask |= 1 << destination_idx;
|
||||
*missing_bm &= useful_mask;
|
||||
*missing_local_parity = 1;
|
||||
*mx_size = max_range - min_range;
|
||||
decode_matrix = malloc(sizeof(unsigned char) * (*mx_size) * (*mx_size));
|
||||
if (NULL == decode_matrix) {
|
||||
return NULL;
|
||||
}
|
||||
for (int i = min_range; i < max_range; i++) {
|
||||
for (int j = min_range; j < max_range; j++) {
|
||||
decode_matrix[*mx_size * (i - min_range) + j - min_range] = encode_matrix[(k * i) + j];
|
||||
}
|
||||
used_idxs[i] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (decode_matrix == NULL) {
|
||||
decode_matrix = isa_l_lrc_get_decode_matrix(k, m, local_parity,
|
||||
encode_matrix, *missing_bm, used_idxs, use_combined_parity);
|
||||
if (decode_matrix) {
|
||||
*mx_size = k;
|
||||
}
|
||||
min_range = 0;
|
||||
max_range = k;
|
||||
}
|
||||
|
||||
*min_col = min_range;
|
||||
*max_col = max_range;
|
||||
return decode_matrix;
|
||||
}
|
||||
|
||||
static int isa_l_lrc_reconstruct(void *desc, char **data, char **parity,
|
||||
int *missing_idxs, int destination_idx, int blocksize)
|
||||
{
|
||||
isa_l_descriptor *isa_l_desc = (isa_l_descriptor*) desc;
|
||||
unsigned char *g_tbls = NULL;
|
||||
unsigned char *decode_matrix = NULL;
|
||||
unsigned char *decode_inverse = NULL;
|
||||
unsigned char *inverse_rows = NULL;
|
||||
unsigned char *reconstruct_buf = NULL;
|
||||
unsigned char **available_fragments = NULL;
|
||||
int k = isa_l_desc->k;
|
||||
int m = isa_l_desc->m;
|
||||
int local_parity = isa_l_desc->l;
|
||||
int n = k + m;
|
||||
int ret = -1;
|
||||
int i, j;
|
||||
uint64_t missing_bm = convert_list_to_bitmap(missing_idxs);
|
||||
int inverse_row = -1;
|
||||
int min_range = 0;
|
||||
int max_range = 0;
|
||||
int matrix_size = k;
|
||||
int *used_idxs = calloc(n, sizeof(int));
|
||||
int missing_local_parity = 0;
|
||||
unsigned char * combined_local_parities = NULL;
|
||||
int use_combined_parity = 0;
|
||||
|
||||
if( NULL == used_idxs) {
|
||||
goto out;
|
||||
}
|
||||
/**
|
||||
* Get available elements and compute the inverse of their
|
||||
* corresponding rows.
|
||||
*/
|
||||
decode_matrix = isa_l_lrc_get_reconstruct_matrix(k, m, local_parity, destination_idx, isa_l_desc->matrix, &missing_bm, used_idxs, &min_range, &max_range, &matrix_size, &missing_local_parity, &use_combined_parity);
|
||||
if (NULL == decode_matrix) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
decode_inverse = (unsigned char*)malloc(sizeof(unsigned char) * matrix_size * matrix_size);
|
||||
|
||||
if (NULL == decode_inverse) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
int im_ret = isa_l_desc->gf_invert_matrix(decode_matrix, decode_inverse, matrix_size);
|
||||
if (im_ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
int nb_parity = (matrix_size == k)? m: 1;
|
||||
unsigned char * encode = (matrix_size == k || missing_local_parity)? isa_l_desc->matrix:decode_matrix;
|
||||
|
||||
/**
|
||||
* Get the row needed to reconstruct
|
||||
*/
|
||||
inverse_rows = get_lrc_inverse_rows(k, m, min_range, max_range, missing_local_parity, decode_inverse, encode, missing_bm, isa_l_desc->gf_mul);
|
||||
|
||||
// Generate g_tbls from computed decode matrix (k x k) matrix
|
||||
g_tbls = malloc(sizeof(unsigned char) * (matrix_size * nb_parity * 32));
|
||||
if (NULL == g_tbls) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in the available elements
|
||||
*/
|
||||
available_fragments = (unsigned char**)malloc(sizeof(unsigned char*)*matrix_size);
|
||||
if (NULL == available_fragments) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
j = 0;
|
||||
if (matrix_size == k) {
|
||||
for (i = 0; i < n - local_parity && j < k; i++) {
|
||||
if (missing_bm & (1 << i)) {
|
||||
continue;
|
||||
}
|
||||
if (i < k) {
|
||||
available_fragments[j] = (unsigned char*)data[i];
|
||||
j++;
|
||||
} else {
|
||||
if (used_idxs[i]) {
|
||||
available_fragments[j] = (unsigned char*)parity[i - k];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (j < k && !missing_local_parity && use_combined_parity) {
|
||||
combined_local_parities = calloc(blocksize, sizeof(unsigned char));
|
||||
if (NULL == combined_local_parities) {
|
||||
goto out;
|
||||
}
|
||||
for (i = n - local_parity; i < n; i++) {
|
||||
for (int x = 0; x < blocksize; x++) {
|
||||
combined_local_parities[x] ^= parity[i - k][x];
|
||||
}
|
||||
}
|
||||
available_fragments[j] = combined_local_parities;
|
||||
j++;
|
||||
}
|
||||
for (i = n - local_parity; i < n && j < k; i++) {
|
||||
if (missing_bm & (1 << i)) {
|
||||
continue;
|
||||
}
|
||||
if (used_idxs[i]) {
|
||||
available_fragments[j] = (unsigned char*)parity[i - k];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < n; i++) {
|
||||
if (used_idxs[i]) {
|
||||
if (i <k) {
|
||||
available_fragments[j] = (unsigned char*)data[i];
|
||||
} else {
|
||||
available_fragments[j] = (unsigned char*)parity[i - k];
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy pointer of buffer to reconstruct
|
||||
*/
|
||||
j = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
if (missing_bm & (1 << i)) {
|
||||
if (i == destination_idx) {
|
||||
if (i < k) {
|
||||
reconstruct_buf = (unsigned char*)data[i];
|
||||
} else {
|
||||
reconstruct_buf = (unsigned char*)parity[i - k];
|
||||
}
|
||||
inverse_row = j;
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the reconstruction
|
||||
*/
|
||||
isa_l_desc->ec_init_tables(matrix_size, 1, &inverse_rows[inverse_row * matrix_size], g_tbls);
|
||||
isa_l_desc->ec_encode_data(blocksize, matrix_size, 1, g_tbls, available_fragments,
|
||||
&reconstruct_buf);
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
free(g_tbls);
|
||||
free(combined_local_parities);
|
||||
free(decode_matrix);
|
||||
free(decode_inverse);
|
||||
free(inverse_rows);
|
||||
free(available_fragments);
|
||||
free(used_idxs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct ec_backend_op_stubs isa_l_rs_lrc_op_stubs = {
|
||||
.INIT = isa_l_rs_lrc_init,
|
||||
.EXIT = isa_l_exit,
|
||||
.ISSYSTEMATIC = 1,
|
||||
.ENCODE = isa_l_encode,
|
||||
.DECODE = isa_l_lrc_decode,
|
||||
.FRAGSNEEDED = isa_l_min_fragments,
|
||||
.RECONSTRUCT = isa_l_lrc_reconstruct,
|
||||
.ELEMENTSIZE = isa_l_element_size,
|
||||
.ISCOMPATIBLEWITH = isa_l_rs_lrc_is_compatible_with,
|
||||
.GETMETADATASIZE = get_backend_metadata_size_zero,
|
||||
.GETENCODEOFFSET = get_encode_offset_zero,
|
||||
.CHECKRECONSTRUCTFRAGMENTS = isa_l_rs_lrc_check_reconstruct_fragments,
|
||||
};
|
||||
|
||||
__attribute__ ((visibility ("internal")))
|
||||
struct ec_backend_common backend_isa_l_rs_lrc = {
|
||||
.id = EC_BACKEND_ISA_L_RS_LRC,
|
||||
.name = ISA_L_RS_LRC_LIB_NAME,
|
||||
.soname = ISA_L_RS_LRC_SO_NAME,
|
||||
.soversion = ISA_L_RS_LRC_LIB_VER_STR,
|
||||
.ops = &isa_l_rs_lrc_op_stubs,
|
||||
.ec_backend_version = _VERSION(ISA_L_RS_LRC_LIB_MAJOR,
|
||||
ISA_L_RS_LRC_LIB_MINOR,
|
||||
ISA_L_RS_LRC_LIB_REV),
|
||||
};
|
||||
@@ -53,6 +53,7 @@ extern struct ec_backend_common backend_liberasurecode_rs_vand;
|
||||
extern struct ec_backend_common backend_isa_l_rs_cauchy;
|
||||
extern struct ec_backend_common backend_libphazr;
|
||||
extern struct ec_backend_common backend_isa_l_rs_vand_inv;
|
||||
extern struct ec_backend_common backend_isa_l_rs_lrc;
|
||||
|
||||
static ec_backend_t ec_backends_supported[] = {
|
||||
(ec_backend_t) &backend_null,
|
||||
@@ -65,6 +66,7 @@ static ec_backend_t ec_backends_supported[] = {
|
||||
(ec_backend_t) &backend_isa_l_rs_cauchy,
|
||||
(ec_backend_t) &backend_libphazr,
|
||||
(ec_backend_t) &backend_isa_l_rs_vand_inv,
|
||||
(ec_backend_t) &backend_isa_l_rs_lrc,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
@@ -35,8 +35,10 @@
|
||||
#include "erasurecode_helpers_ext.h"
|
||||
#include "erasurecode_preprocessing.h"
|
||||
|
||||
static int total_decoding_errors = 0;
|
||||
static int total_reconstrcut_errors = 0;
|
||||
|
||||
char *create_buffer(int size, int fill)
|
||||
char *create_buffer(int size)
|
||||
{
|
||||
char *buf = malloc(size);
|
||||
if (buf == NULL) {
|
||||
@@ -62,9 +64,7 @@ int *create_skips_array(struct ec_args *args, int skip)
|
||||
return NULL;
|
||||
}
|
||||
memset(buf, 0, array_size);
|
||||
if (skip >= 0 && skip < num) {
|
||||
buf[skip] = 1;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ out:
|
||||
return num_frags;
|
||||
}
|
||||
|
||||
static void encode_decode_test_impl(const ec_backend_id_t be_id,
|
||||
int encode_decode_test_impl(const ec_backend_id_t be_id,
|
||||
struct ec_args *args,
|
||||
int *skip)
|
||||
{
|
||||
@@ -131,15 +131,15 @@ static void encode_decode_test_impl(const ec_backend_id_t be_id,
|
||||
|
||||
if (-EBACKENDNOTAVAIL == desc) {
|
||||
fprintf(stderr, "Backend library not available!\n");
|
||||
return;
|
||||
return desc;
|
||||
} else if ((args->k + args->m) > EC_MAX_FRAGMENTS) {
|
||||
fprintf(stderr, "data + parity is greater than %d!\n", EC_MAX_FRAGMENTS);
|
||||
assert(-EINVALIDPARAMS == desc);
|
||||
return;
|
||||
return desc;
|
||||
} else
|
||||
assert(desc > 0);
|
||||
|
||||
orig_data = create_buffer(orig_data_size, 'x');
|
||||
orig_data = create_buffer(orig_data_size);
|
||||
assert(orig_data != NULL);
|
||||
rc = liberasurecode_encode(desc, orig_data, orig_data_size,
|
||||
&encoded_data, &encoded_parity, &encoded_fragment_len);
|
||||
@@ -179,6 +179,11 @@ static void encode_decode_test_impl(const ec_backend_id_t be_id,
|
||||
rc = liberasurecode_decode(desc, avail_frags, num_avail_frags,
|
||||
encoded_fragment_len, 1,
|
||||
&decoded_data, &decoded_data_len);
|
||||
if (rc == -1 ) {
|
||||
total_decoding_errors++;
|
||||
return rc;
|
||||
}
|
||||
|
||||
assert(0 == rc);
|
||||
assert(decoded_data_len == orig_data_size);
|
||||
assert(memcmp(decoded_data, orig_data, orig_data_size) == 0);
|
||||
@@ -192,6 +197,7 @@ static void encode_decode_test_impl(const ec_backend_id_t be_id,
|
||||
assert(0 == liberasurecode_instance_destroy(desc));
|
||||
free(orig_data);
|
||||
free(avail_frags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -199,6 +205,11 @@ static void test_decode_with_missing_multi_data_parity(
|
||||
const ec_backend_id_t be_id, struct ec_args *args, uint64_t nb_iter)
|
||||
{
|
||||
uint64_t i;
|
||||
int max_num_missing = args->m;
|
||||
if (be_id == EC_BACKEND_ISA_L_RS_LRC) {
|
||||
max_num_missing = (args->m - args->priv_args1.lrc_args.l + 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < nb_iter; i++) {
|
||||
int *skip = create_skips_array(args,-1);
|
||||
assert(skip != NULL);
|
||||
@@ -210,38 +221,153 @@ static void test_decode_with_missing_multi_data_parity(
|
||||
skip[value] = 1;
|
||||
count++;
|
||||
}
|
||||
|
||||
if(count == args->m) {
|
||||
if(count == max_num_missing) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
encode_decode_test_impl(be_id, args, skip);
|
||||
}
|
||||
|
||||
int err = encode_decode_test_impl(be_id, args, skip);
|
||||
if (err) {
|
||||
printf("skip\n");
|
||||
for (int i = 0; i < args->k + args->m; i++)
|
||||
if (skip[i])
|
||||
printf("i= %d val=%d ",i , skip[i]);
|
||||
//break;
|
||||
}
|
||||
free(skip);
|
||||
}
|
||||
printf("total decoding errors %d\n", total_decoding_errors);
|
||||
}
|
||||
|
||||
static int reconstruct_test_impl(const ec_backend_id_t be_id,
|
||||
struct ec_args *args,
|
||||
int *skip)
|
||||
{
|
||||
int rc = 0;
|
||||
int desc = -1;
|
||||
int orig_data_size = 1024 * 1024;
|
||||
char *orig_data = NULL;
|
||||
char **encoded_data = NULL, **encoded_parity = NULL;
|
||||
uint64_t encoded_fragment_len = 0;
|
||||
char **avail_frags = NULL;
|
||||
int num_avail_frags = 0;
|
||||
int i = 0;
|
||||
char *out = NULL;
|
||||
|
||||
desc = liberasurecode_instance_create(be_id, args);
|
||||
if (-EBACKENDNOTAVAIL == desc) {
|
||||
fprintf(stderr, "Backend library not available!\n");
|
||||
return -1;
|
||||
}
|
||||
assert(desc > 0);
|
||||
|
||||
orig_data = create_buffer(orig_data_size);
|
||||
assert(orig_data != NULL);
|
||||
rc = liberasurecode_encode(desc, orig_data, orig_data_size,
|
||||
&encoded_data, &encoded_parity, &encoded_fragment_len);
|
||||
assert(rc == 0);
|
||||
out = malloc(encoded_fragment_len);
|
||||
assert(out != NULL);
|
||||
char *cmp = NULL;
|
||||
|
||||
num_avail_frags = create_frags_array(&avail_frags, encoded_data, encoded_parity, args, skip);
|
||||
|
||||
if (i < args->k) {
|
||||
cmp = encoded_data[i];
|
||||
}
|
||||
else {
|
||||
cmp = encoded_parity[i - args->k];
|
||||
}
|
||||
memset(out, 0, encoded_fragment_len);
|
||||
rc = liberasurecode_reconstruct_fragment(desc, avail_frags, num_avail_frags, encoded_fragment_len, i, out);
|
||||
if (rc == -1 ) {
|
||||
total_reconstrcut_errors++;
|
||||
return rc;
|
||||
}
|
||||
assert(rc == 0);
|
||||
for (int x= 0; x < encoded_fragment_len; x++){
|
||||
if (out[x] != cmp[x]){
|
||||
printf(" out(%c) x(%d) \n", out[x], x);
|
||||
total_reconstrcut_errors++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(memcmp(out, cmp, encoded_fragment_len) == 0);
|
||||
free(avail_frags);
|
||||
|
||||
free(orig_data);
|
||||
free(out);
|
||||
liberasurecode_encode_cleanup(desc, encoded_data, encoded_parity);
|
||||
liberasurecode_instance_destroy(desc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void test_multi_reconstruct(const ec_backend_id_t be_id,
|
||||
struct ec_args *args, int nb_iter)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
int max_num_missing = args->m;
|
||||
if (be_id == EC_BACKEND_ISA_L_RS_LRC) {
|
||||
max_num_missing = (args->m - args->priv_args1.lrc_args.l + 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < nb_iter; i++) {
|
||||
int *skip = create_skips_array(args,-1);
|
||||
assert(skip != NULL);
|
||||
int count = 0;
|
||||
while(true) {
|
||||
int value = rand() % (args->k + args->m) ;
|
||||
|
||||
if (skip[value] != 1){
|
||||
skip[value] = 1;
|
||||
count++;
|
||||
}
|
||||
if(count == max_num_missing) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int err = reconstruct_test_impl(be_id, args, skip);
|
||||
if (err) {
|
||||
printf("skip\n");
|
||||
for (int i = 0; i < args->k + args->m; i++)
|
||||
if (skip[i])
|
||||
printf("i= %d val=%d ",i , skip[i]);
|
||||
//break;
|
||||
}
|
||||
free(skip);
|
||||
}
|
||||
printf("total reconstruct errors %d\n", total_decoding_errors);
|
||||
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 4) {
|
||||
if (argc != 6) {
|
||||
printf("Stress Test with m missing positions for RS(k,m).\n");
|
||||
printf("Number of iterations {nb_iter} should be at least ~ (k+m)!/(k!)(m!).\n");
|
||||
printf("Usage: %s <message_length> <parity_length> <nb_iter>\n", argv[0]);
|
||||
printf("Usage: %s <backend_id> <data_length> <total_parity_length> <local_parity_length> <nb_iter>\n", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
int k = atoi(argv[1]);
|
||||
int m = atoi(argv[2]);
|
||||
u_int64_t nb_iter = atoll(argv[3]);
|
||||
int backend = atoi(argv[1]);
|
||||
int k = atoi(argv[2]);
|
||||
int m = atoi(argv[3]);
|
||||
int l = atoi(argv[4]);
|
||||
|
||||
u_int64_t nb_iter = atoll(argv[5]);
|
||||
struct ec_args isa_l_km_args = {
|
||||
.k = k,
|
||||
.m = m,
|
||||
.w = 8,
|
||||
.hd = m+1,
|
||||
.priv_args1.lrc_args.l = l,
|
||||
};
|
||||
|
||||
// Test is ok if no Assertion `0 == rc' occurs
|
||||
// We can make backend configurable and test EC_BACKEND_ISA_L_RS_VAND
|
||||
test_decode_with_missing_multi_data_parity(EC_BACKEND_ISA_L_RS_VAND_INV, &isa_l_km_args, nb_iter);
|
||||
|
||||
test_decode_with_missing_multi_data_parity(backend, &isa_l_km_args, nb_iter);
|
||||
test_multi_reconstruct(backend, &isa_l_km_args, nb_iter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#define JERASURE_RS_CAUCHY_BACKEND "jerasure_rs_cauchy"
|
||||
#define ISA_L_RS_VAND_BACKEND "isa_l_rs_vand"
|
||||
#define ISA_L_RS_VAND_INV_BACKEND "isa_l_rs_vand_inv"
|
||||
#define ISA_L_RS_LRC_BACKEND "isa_l_rs_lrc"
|
||||
#define ISA_L_RS_CAUCHY_BACKEND "isa_l_rs_cauchy"
|
||||
#define SHSS_BACKEND "shss"
|
||||
#define RS_VAND_BACKEND "liberasurecode_rs_vand"
|
||||
@@ -197,6 +198,37 @@ struct ec_args *isa_l_test_args[] = { &isa_l_args,
|
||||
&isa_l_85_args,
|
||||
NULL };
|
||||
|
||||
struct ec_args isa_l_lrc_75_args = {
|
||||
.k = 7,
|
||||
.m = 5,
|
||||
.w = 8,
|
||||
.hd =6,
|
||||
.priv_args1.lrc_args.l = 2,
|
||||
};
|
||||
struct ec_args isa_l_lrc_84_args = {
|
||||
.k = 8,
|
||||
.m = 4,
|
||||
.w = 8,
|
||||
.hd = 5,
|
||||
.priv_args1.lrc_args.l = 2,
|
||||
};
|
||||
|
||||
struct ec_args isa_l_lrc_123_args = {
|
||||
.k = 12,
|
||||
.m = 12,
|
||||
.w = 8,
|
||||
.hd =13,
|
||||
.priv_args1.lrc_args.l = 3,
|
||||
};
|
||||
struct ec_args isa_l_lrc_155_args = {
|
||||
.k = 15,
|
||||
.m = 5,
|
||||
.w = 8,
|
||||
.hd =5,
|
||||
.priv_args1.lrc_args.l = 2,
|
||||
};
|
||||
struct ec_args *isa_l_lrc_test_args[] = { &isa_l_lrc_75_args, &isa_l_lrc_84_args, &isa_l_lrc_123_args,
|
||||
&isa_l_lrc_155_args, NULL };
|
||||
int priv = 128;
|
||||
struct ec_args shss_args = {
|
||||
.k = 6,
|
||||
@@ -316,6 +348,8 @@ char * get_name_from_backend_id(ec_backend_id_t be) {
|
||||
return ISA_L_RS_VAND_BACKEND;
|
||||
case EC_BACKEND_ISA_L_RS_VAND_INV:
|
||||
return ISA_L_RS_VAND_INV_BACKEND;
|
||||
case EC_BACKEND_ISA_L_RS_LRC:
|
||||
return ISA_L_RS_LRC_BACKEND;
|
||||
case EC_BACKEND_ISA_L_RS_CAUCHY:
|
||||
return ISA_L_RS_CAUCHY_BACKEND;
|
||||
case EC_BACKEND_SHSS:
|
||||
@@ -358,6 +392,9 @@ struct ec_args *create_ec_args(ec_backend_id_t be, ec_checksum_type_t ct, int ba
|
||||
case EC_BACKEND_ISA_L_RS_VAND_INV:
|
||||
backend_args_array = isa_l_test_args;
|
||||
break;
|
||||
case EC_BACKEND_ISA_L_RS_LRC:
|
||||
backend_args_array = isa_l_lrc_test_args;
|
||||
break;
|
||||
case EC_BACKEND_ISA_L_RS_CAUCHY:
|
||||
backend_args_array = isa_l_test_args;
|
||||
break;
|
||||
@@ -1158,7 +1195,7 @@ static void encode_decode_test_impl(const ec_backend_id_t be_id,
|
||||
* and 5 are assumed unavailable.
|
||||
*
|
||||
* We only mark at most 2 as unavailable, as we cannot guarantee every situation
|
||||
* will be able to habndle 3 failures.
|
||||
* will be able to handle 3 failures.
|
||||
*/
|
||||
static void reconstruct_test_impl(const ec_backend_id_t be_id,
|
||||
struct ec_args *args,
|
||||
@@ -1473,8 +1510,13 @@ static void test_decode_with_missing_parity(const ec_backend_id_t be_id,
|
||||
static void test_decode_with_missing_multi_data(const ec_backend_id_t be_id,
|
||||
struct ec_args *args)
|
||||
{
|
||||
int max_num_missing = args->k <= (args->hd - 1) ? args->k : args->hd - 1;
|
||||
|
||||
int i,j;
|
||||
int max_num_missing = args->k <= (args->hd - 1) ? args->k : args->hd - 1;
|
||||
// for LRC backend, we test up to g+1 missing data, g is the nubmer of global parities.
|
||||
if (be_id == EC_BACKEND_ISA_L_RS_LRC) {
|
||||
max_num_missing = (args->m - args->priv_args1.lrc_args.l + 1);
|
||||
}
|
||||
for (i = 0; i < args->k - max_num_missing + 1; i++) {
|
||||
int *skip = create_skips_array(args,-1);
|
||||
assert(skip != NULL);
|
||||
@@ -1507,6 +1549,9 @@ static void test_decode_with_missing_multi_data_parity(
|
||||
{
|
||||
int i,j;
|
||||
int max_num_missing = args->hd - 1;
|
||||
if (be_id == EC_BACKEND_ISA_L_RS_LRC) {
|
||||
max_num_missing = (args->m - args->priv_args1.lrc_args.l + 1);
|
||||
}
|
||||
int end = (args->k + args->m) - max_num_missing + 1;
|
||||
for (i = 0; i < end; i++) {
|
||||
int *skip = create_skips_array(args,-1);
|
||||
@@ -2138,6 +2183,112 @@ static void test_metadata_crcs_be(void)
|
||||
assert(is_invalid_fragment_header((fragment_header_t *) header) == 1);
|
||||
}
|
||||
|
||||
static void test_isa_l_rs_lrc_local_only_reconstruct(void)
|
||||
{
|
||||
int rc = 0;
|
||||
int desc = -1;
|
||||
int orig_data_size = 1024 * 1024;
|
||||
char *orig_data = NULL;
|
||||
char **encoded_data = NULL, **encoded_parity = NULL;
|
||||
uint64_t encoded_fragment_len = 0;
|
||||
char **avail_frags = NULL;
|
||||
int num_avail_frags = 0;
|
||||
char *out = NULL;
|
||||
int skip[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 1, // local data group 1
|
||||
1, 1, 1, 1, 1, 1, 1, // local data group 2
|
||||
1, 1, 1, // global parities
|
||||
0, 1, // local parities
|
||||
};
|
||||
|
||||
desc = liberasurecode_instance_create(EC_BACKEND_ISA_L_RS_LRC, &isa_l_lrc_155_args);
|
||||
if (-EBACKENDNOTAVAIL == desc) {
|
||||
fprintf(stderr, "Backend library not available!\n");
|
||||
return;
|
||||
}
|
||||
assert(desc > 0);
|
||||
|
||||
orig_data = create_buffer(orig_data_size, 'x');
|
||||
assert(orig_data != NULL);
|
||||
rc = liberasurecode_encode(desc, orig_data, orig_data_size,
|
||||
&encoded_data, &encoded_parity, &encoded_fragment_len);
|
||||
assert(rc == 0);
|
||||
out = malloc(encoded_fragment_len);
|
||||
assert(out != NULL);
|
||||
char *cmp = encoded_data[7];
|
||||
num_avail_frags = create_frags_array(&avail_frags, encoded_data,
|
||||
encoded_parity, &isa_l_lrc_155_args, skip);
|
||||
memset(out, 0, encoded_fragment_len);
|
||||
rc = liberasurecode_reconstruct_fragment(
|
||||
desc, avail_frags, num_avail_frags, encoded_fragment_len, 7, out);
|
||||
assert(rc == 0);
|
||||
assert(memcmp(out, cmp, encoded_fragment_len) == 0);
|
||||
free(avail_frags);
|
||||
|
||||
free(orig_data);
|
||||
free(out);
|
||||
liberasurecode_encode_cleanup(desc, encoded_data, encoded_parity);
|
||||
liberasurecode_instance_destroy(desc);
|
||||
}
|
||||
|
||||
static void test_isa_l_rs_lrc_combine_local_frags(void)
|
||||
{
|
||||
int rc = 0;
|
||||
int desc = -1;
|
||||
int orig_data_size = 1024 * 1024;
|
||||
char *orig_data = NULL;
|
||||
char **encoded_data = NULL, **encoded_parity = NULL;
|
||||
uint64_t encoded_fragment_len = 0;
|
||||
char *decoded_data = NULL;
|
||||
uint64_t decoded_data_len = 0;
|
||||
char **avail_frags = NULL;
|
||||
int num_avail_frags = 0;
|
||||
char *out = NULL;
|
||||
int skip[] = {
|
||||
0, 0, 1, 0, 0, 0, 0, 1, // local data group 1
|
||||
0, 0, 1, 0, 1, 0, 0, // local data group 2
|
||||
0, 0, 0, // global parities
|
||||
0, 0, // local parities
|
||||
};
|
||||
|
||||
desc = liberasurecode_instance_create(EC_BACKEND_ISA_L_RS_LRC, &isa_l_lrc_155_args);
|
||||
if (-EBACKENDNOTAVAIL == desc) {
|
||||
fprintf(stderr, "Backend library not available!\n");
|
||||
return;
|
||||
}
|
||||
assert(desc > 0);
|
||||
|
||||
orig_data = create_buffer(orig_data_size, 'x');
|
||||
assert(orig_data != NULL);
|
||||
rc = liberasurecode_encode(desc, orig_data, orig_data_size,
|
||||
&encoded_data, &encoded_parity, &encoded_fragment_len);
|
||||
assert(rc == 0);
|
||||
out = malloc(encoded_fragment_len);
|
||||
assert(out != NULL);
|
||||
num_avail_frags = create_frags_array(&avail_frags, encoded_data,
|
||||
encoded_parity, &isa_l_lrc_155_args, skip);
|
||||
memset(out, 0, encoded_fragment_len);
|
||||
|
||||
rc = liberasurecode_decode(desc, avail_frags, num_avail_frags,
|
||||
encoded_fragment_len, 1,
|
||||
&decoded_data, &decoded_data_len);
|
||||
assert(0 == rc);
|
||||
assert(decoded_data_len == orig_data_size);
|
||||
assert(memcmp(decoded_data, orig_data, orig_data_size) == 0);
|
||||
|
||||
rc = liberasurecode_reconstruct_fragment(
|
||||
desc, avail_frags, num_avail_frags, encoded_fragment_len, 2, out);
|
||||
assert(rc == 0);
|
||||
assert(memcmp(out, encoded_data[2], encoded_fragment_len) == 0);
|
||||
free(avail_frags);
|
||||
|
||||
free(orig_data);
|
||||
free(out);
|
||||
liberasurecode_encode_cleanup(desc, encoded_data, encoded_parity);
|
||||
liberasurecode_decode_cleanup(desc, decoded_data);
|
||||
liberasurecode_instance_destroy(desc);
|
||||
}
|
||||
|
||||
//static void test_verify_str
|
||||
|
||||
/* An individual test, useful to ensure the reported name
|
||||
@@ -2209,6 +2360,10 @@ struct testcase testcases[] = {
|
||||
// ISA-L rs vand inv tests
|
||||
TEST_SUITE(EC_BACKEND_ISA_L_RS_VAND_INV),
|
||||
TEST({.with_args = test_decode_with_missing_multi_data_parity_fail_with_isal}, EC_BACKEND_ISA_L_RS_VAND_INV, 0),
|
||||
// ISA-L rs lrc tests
|
||||
TEST_SUITE(EC_BACKEND_ISA_L_RS_LRC),
|
||||
TEST({.no_args = test_isa_l_rs_lrc_local_only_reconstruct}, EC_BACKENDS_MAX, 0),
|
||||
TEST({.no_args = test_isa_l_rs_lrc_combine_local_frags}, EC_BACKENDS_MAX, 0),
|
||||
// shss tests
|
||||
TEST_SUITE(EC_BACKEND_SHSS),
|
||||
// Internal RS Vand backend tests
|
||||
|
||||
Reference in New Issue
Block a user