Merge "feature: LRC (locally repairable code) backend"

This commit is contained in:
Zuul
2026-03-13 16:41:24 +00:00
committed by Gerrit Code Review
9 changed files with 1269 additions and 48 deletions

View File

@@ -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
-----------------------------

View File

@@ -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 */

View File

@@ -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;
}
}

View File

@@ -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 \

View File

@@ -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.

View 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),
};

View File

@@ -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,
};

View File

@@ -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;
}

View File

@@ -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