Jerasure接口分析

530 阅读11分钟

在Ubuntu安装Jerasure2.0

准备

1.下载GF-Complete

github.com/ceph/gf-com…

2.下载Jerasure

github.com/tsuraan/Jer…

2.安装autoconf automake

sudo apt-get install automake autoconf

2.安装libtool

sudo apt-get install libtool

配置

分别进入GF-Complete和Jerasure目录

1.在项目根目录运行

autoreconf -if

项目目录下会多出m4文件目录, config.h.in文件, Makefile.in文件, configure脚本, compile脚本, depcomp脚本等文件;

2.接着运行

./configure

进行配置生成makefile文件,譬如enbale/disbale一些特性,设置交叉编译平台(例如--host=linux-mips),设置编译安装目录(例如--prefix=path_to_your_build_directory)具体可以查看help信息;

3.执行

make

运行Makefile文件

4.执行

sudo make install

此时进入Jerasure的Examples里面有了可执行文件,但是此时运行这些文件会出现错误:

error while loading shared libraries: libXXXXXXX.so.1: cannot open shared object file: No such file or directory

需要目录加入到共享库的配置文件中

sudo sh -c "echo '/usr/local/lib' >> /etc/ld.so.conf"

sudo ldconfig

执行完以上操作,再到Examples里就可以成功运行示例了。

错误解决方法

在执行autoconf的时候出现以下错误:

error: possibly undefined macro: AM_INIT_AUTOMAKE

If this token and others are legitimate, please use m4_pattern_allow.

See the Autoconf documentation.

configure.ac:25: error: possibly undefined macro: AM_PROG_CC_C_O

configure.ac:27: error: possibly undefined macro: AC_LIBTOOL_WIN32_DLL

configure.ac:28: error: possibly undefined macro: AC_PROG_LIBTOOL

configure.ac:30: error: possibly undefined macro: AM_PROG_LEX

configure.ac:100: error: possibly undefined macro: AM_CONDITIONAL

解决方法:

运行

autoreconf --install

Jerasure库分析

库的结构模块

Jerasure库包括以下5个模块:

  • galois.h/.c提供伽罗华域的算术运算。
  • jerasure.h/.c提供了绝大部分的核心函数。包括矩阵的编解码,位矩阵变换,矩阵转置和位矩阵转置。
  • reedsol.h/.c支持RS编解码和优化和的RS码。
  • cauchy.h/.c 支持cauchy RS编解码和最优cauchy编码。
  • cauchy_best_r6.h/.c 基于cauchy矩阵的RAID-6优化。
  • liberation.h/.c 支持Liberartion RAID-6编码, Blaum-Roth 编码,和Liber8tion RAID-6编码。 Liberation是一种低密度MDS。这三种编码采用位矩阵来实现,其性能远优于现有的RS和EVENNODD,在某种情况下也优于目前已知的最好的RDP编码。

对于rs编码来说我们只需要了解前三个模块的功能就行,下面主要来分析前三个模块的功能接口。

Jerasure-2.0库常见的参数和其含义:

参数名数据类型含义
kint数据盘个数
mint校验盘个数
wint字长
packetsizeint包大小(必须是sizeof(long)的整数倍)
sizeint每个设备要编码/解码的字节总数。 这必须是sizeof(long)的倍数。 如果使用位矩阵,则它必须是packetssize * w的倍数。 如果希望对不符合这些限制的数据块进行编码,则必须用零填充数据块,以便满足这些限制。
matrixint *这是一个具有k * m个元素的数组,表示编码矩阵-即分布矩阵的最后m行。 它的元素必须在0到2w−1之间。第i行和第j列中的元素在`matrix [i * k + j]中。
bitmatrixint *这是wmwk元素的数组,组成二进制分配矩阵BDM的最后wm行。 第i行和第j列中的元素位于bitmatrix [i * k * w + j]中
dataptrschar **这是k个指针数组,指向大小为字节的编码数据。 其中每一个必须是长字对齐的。
coding_ptrschar **这是m个指针数组,指向大小为字节的编码数据。 其中每一个必须是长字对齐的。
erasuresint *这是一组ID已删除的设备。 Id是介于0到k + m-1之间的数字。 如果擦除数为e,则擦除的元素0到e−1标识被擦除的设备,并且erasures [e]必须等于-1。
erasedint *这是指定擦除的替代方法。 它是一个k+m的元素数组。 数组的元素i代表ID为i的设备。 如果erased[i]等于0,则设备i正在工作;如果等于1,则其被擦除。
schduleint **这是一个5元素整数数组,用于优化位矩阵的编码计算。 如果计划中有o个操作,则计划必须至少包含o + 1个元素,并且schedule [o][0]应当等于-1。
cacheint ***三维数组,用于保存一系列缓存地址,用于对RAID6解码进行优化。
row_k_onesbool布尔类型,用于对满足m>1的解码过程进行优化。解码时,如果对应编码矩阵第一行全部为1或者对应的二进制编码矩阵前w行构成k个单位矩阵,则设置此标志位有助于提升解码速度。
decoding_matrixint *这是用于解码的k×k矩阵或wk×wk位矩阵。 它是通过使用分布矩阵的相关行并将其求逆而构造的矩阵。
dm_idsint *一维数组,用于指定仍然正常的磁盘编号,帮助生成解码矩阵。

Galois域算术运算

库:galois.h\galois.c

  • galois_single_multiply(int a, int b, int w) 以及galois_single_divide(int a ,int b, int w)

GF(2w)上执行单元素的乘法和除法。

  • galois_region_xor(char *r1, char *r2, char *r3, int nbytes)

此XOR对字节的两个区域r1和r2进行求和,并将总和放入r3。 请注意,如果我们用总和替换区域之一,则r3可能等于r1或r2。
Nbytes必须是机器长字大小的倍数。

  • galois_w08_region_multiply(char *region, int multby, int nbytes, char *r2, int add):

这将整个字节区域乘以GF(28)中的常数multby。 如果r2为NULL,则区域将被覆盖。 否则,如果add为零,则将乘积放在r2中。 如果add不为零,则将乘积与r2中的字节进行异或。

  • galois_w16_region_multiply()和galois_w32_region_multiply()

与上述函数类似,分别对应GF(216)和GF(232)

  • galois_change_technique(gf_t *gf, int w)

这使您可以从GF-Complete创建自己的Galois Field算术的自定义实现。 为此,请参阅GF-Complete手册中的create_gf_from_argv()和gf_init_hard()。 这些过程允许您创建gf_t,然后调用galois_change _technique()实现。

  • galois_init_field()和glois_init_composite_field()

会从GF-Complete创建gf_t指针。我们建议,使用create_gf_from_argv()和gf_init_hard()代替。

  • galois_get_field_ptr(int w)

返回一个目前jerasure使用中的指向gf_t的指针,针对指定的w。

编码和解码

库:jerasure.c\jerasure.h

  • void jerasure_do_parity(k,data_ptrs, char *parity_ptr, size)

这将从数据ptrs访问的k个内存区域中的每个区域计算数据大小字节的奇偶校验。 它将结果放入奇偶校验ptr指向的大小字节中。 像每个数据ptrs一样,奇偶校验ptr必须是长字对齐的,并且大小必须是sizeof(long)的倍数。

编码

  • void jerasure_matrix_encode(k,m,w,bitmatrix,data_ptrs,coding_ptrs,size,packetsize)

这使用位矩阵进行编码。 现在w可以是1到32之间的任何数字。

  • void jerasure_schedule_encode(k, m, w, schedule, data ptrs, coding ptrs, size, packetsize):

此编码使用从jerasure_dumb_bitmatrix_to_schedule()或jerasure_smart_bitmatrix_schedule()创建的调度进行编码。

解码

这些函数中的每一个都返回一个整数,如果成功则返回0,否则返回-1。 如果擦除太多,则解码可能会失败。

  • int jerasure_matrix_decode(k, m, w matrix, row_k_ones, erasures, data ptrs, coding ptrs, size)

此函数使用GF(2w)中的矩阵进行解码。 通过创建解码矩阵并执行矩阵/矢量乘积,然后对所有已擦除的编码设备进行重新编码,可以完成此工作。 完成后,将丢弃解码矩阵。 如果要访问解码矩阵,则应使用下面的jerasure make decoding matrix()

  • int jerasure_bitmatrix_decode(k, m, w bitmatrix, row k ones, erasures, data ptrs, coding ptrs, size, packetsize)

注意,它不做任何调度-它只是创建解码位矩阵,并直接使用它来进行解码。 同样,完成后它会丢弃解码位矩阵。

  • int jerasure_schedule_decode_lazy(k, m, w bitmatrix, erasures, data ptrs, coding ptrs, size, packetsize, int smart)

这是通过根据解码矩阵创建一个schedule并将其解码来进行解码的。 如果smart是1,则使用 bitmatrix来创建计划。 否则,将使用dumb bitmatrix。 请注意,没有使用变量row_k_ones,因为如果smart为1,则创建的schedule无论如何都会找到该优化。 此过程完成后,将释放计划和分配给解码的所有数据结构。

  • int jerasure_schedule_decode_cache(k, m, w cache, erasures, data ptrs, coding ptrs, size, packetsize)

当m = 2时,使用schedule缓存进行解码。

  • int jerasure_make_decoding_matrix(k, m, w matrix, erased, decoding_matrix, dm_ids

创建解码矩阵。 请注意,解码矩阵和dm id均应分配并传递给此过程,以填充它们。解码矩阵应具有k2个整数,而dm i ds应具有k整数。

  • int jerasure_make_decoding_bitmatrix(k, m, w matrix, erased, decoding_matrix, dm_ids)

创建解码位矩阵。 同样,应同时定位解码矩阵和dm_id,并将其传递给此过程,以填充它们。此时间解码矩阵应具有k2w2整数,而dm i d仍具有k个整数。

  • int jerasure_erasures_to_erased(k, m, erasures)

将上面定义的erasure规范转换为上面定义的erased规范。

点积操作

  • void jerasure_matrix_dotprod(k, w, int ******matrix_row, int ****src_ids, int dest_id, data_ptrs, coding_ptrs, size)

这将一行编码/解码矩阵乘以数据/幸存者。 源设备的ID(与矢量元素的ID相对应)位于src_id中。 目标设备的ID在目标ID中。 当矩阵中遇到一个1时,将执行正确的XOR /复制操作。

  • *void jerasure bitmatrix dotprod(k, w, int bitmatrix row, int src ids, int dest id, data ptrs, coding ptrs,size, packetsize)

这是位矩阵的类似过程。 它根据由bitmatrix行指定的矩阵的w行执行w点乘积。

  • void jerasure_do_scheduled_operations(char **ptrs, schedule, packetsize):

这将对ptrs指定的指针执行计划。 尽管未指定w,但它以w(packetsize)个字节执行调度。 假定ptrs是与计划匹配的正确大小。 通常,这是k + m。

经典RS码

Vandermonde分布矩阵

  • int *reed_sol_vandermonde_coding_matrix(k,m,w)

这将基于扩展的范德蒙德矩阵返回GF(2w)中分布矩阵的最后m行。 这是一个m×k矩阵,可以与jerasure.c中的矩阵例程一起使用。 此矩阵的第一行保证全为1。 第一列也保证全为1。

  • int *reed sol_extended_vandermonde_matrix(int rows, int cols, w)

这会创建一个扩展的范德蒙德矩阵。

  • int *reed_sol_big_vandermonde_distribution_matrix(int rows, int cols, w)

这将扩展矩阵转化为分布矩阵。

文件编码解码

./Example/encode.c

  • encoder.c编码文件:

./encoder 'inputfile' k m 'coding_technique' w (packetsize) (buffersize)

‘inputfile’: 输入文件或负数S:要编码的文件或负数S,指示应使用大小为-S的随机文件而不是现有文件

k:将文件划分的数据块的数量

m:根据数据块生成的校验块的数量

coding_technique:使用的编码算法。

  • “reed_sol_van”:范德蒙德RS码,w=8,16,32
  • “reed_sol_r6_op”:针对RAID-6优化的RS码,m=2,w=8,16,32
  • “cauchy_orig”:原生柯西编码
  • “cauchy_good”:优化的柯西编码
  • “liberation”:最小密度RAID-6中的liberation,k小于等于w,w大于2,且为质数
  • “blaum_roth”:最小密度RAID-6中的blaum roth,k小于等于w,w大于2,且w+1为质数
  • “liber8tion”:最小密度RAID-6中的liber8tion,k小于等于w,w=8,m=2
  • “no_coding”:无编码

w:word size。

packet size:就是packet size 。一般为4的整数倍。

buffer size:每次处理的数据大小,例如1024。

例子:

./encoder /home/durantthorvalds/jerasure-master/test.pdf 6 2 reed_sol_van 8 1024 500000

Encoding (MB/sec): 3294.5325077314

En_Total (MB/sec): 372.5363687737

drwxrwxrwx 5 durantthorvalds durantthorvalds 4096 2月 1 16:01 ..

-rw-rw-r-- 1 durantthorvalds durantthorvalds 2637824 2月 1 16:01 test_k1.pdf

-rw-rw-r-- 1 durantthorvalds durantthorvalds 2637824 2月 1 16:01 test_k2.pdf

-rw-rw-r-- 1 durantthorvalds durantthorvalds 2637824 2月 1 16:01 test_k3.pdf

-rw-rw-r-- 1 durantthorvalds durantthorvalds 2637824 2月 1 16:01 test_k4.pdf

-rw-rw-r-- 1 durantthorvalds durantthorvalds 2637824 2月 1 16:01 test_k5.pdf

-rw-rw-r-- 1 durantthorvalds durantthorvalds 2637824 2月 1 16:01 test_k6.pdf

-rw-rw-r-- 1 durantthorvalds durantthorvalds 2637824 2月 1 16:01 test_m1.pdf

-rw-rw-r-- 1 durantthorvalds durantthorvalds 2637824 2月 1 16:01 test_m2.pdf

-rw-rw-r-- 1 durantthorvalds durantthorvalds 90 2月 1 16:01 test_meta.txt

packetsize 为1k。这儿的6个数据文件大小刚好为源文件的大小.注意文件大小既是8的倍数,也是1024的倍数。

按照上述说明执行命令后,我们会发现在Examples文件夹中创建了一个Coding文件夹,顾名思义,这里存放着编码好的数据块和编码块,以及一个meta文件,存放文件的编码信息。每个数据块文件都会被命名为”_k#”(数据块)和”_m#”(校验块)然后跟着源文件的扩展名。例如 40kb-image.jpg 就会生成一个 40kb-image_k1.jpg。

test_meta.txt是这次encoding的相关参数,这些参数将会用于decoding过程。

/home/durantthorvalds/jerasure-master/test.pdf 15431554 6 2 8 1024 688128 reed_sol_van 4 23

  • decoder解码文件:

./decoder 'inputfile'****

在解码之前,我们假设一种不幸的情况,有两个文件块丢失了。

durantthorvalds@ubuntu:~/jerasure-master/Examples/Codingrmtestk1.pdftestm1.pdfdurantthorvalds@ubuntu: /jerasuremaster/Examples rm test_k1.pdf test_m1.pdf durantthorvalds@ubuntu:~/jerasure-master/Examples ./decoder /home/durantthorvalds/jerasure-master/test.pdf Decoding (MB/sec): 3815.5760207509

De_Total (MB/sec): 818.9580808033

durantthorvalds@ubuntu:~/jerasure-master/Examples$ diff Coding/test_decoded.pdf

/home/durantthorvalds/jerasure-master/test.pdf

diff没有输出表示两文件完全相同。

另外如果损坏文件数超过m,解码也会失败!