在Ubuntu安装Jerasure2.0
准备
1.下载GF-Complete
2.下载Jerasure
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库常见的参数和其含义:
| 参数名 | 数据类型 | 含义 |
|---|---|---|
| k | int | 数据盘个数 |
| m | int | 校验盘个数 |
| w | int | 字长 |
| packetsize | int | 包大小(必须是sizeof(long)的整数倍) |
| size | int | 每个设备要编码/解码的字节总数。 这必须是sizeof(long)的倍数。 如果使用位矩阵,则它必须是packetssize * w的倍数。 如果希望对不符合这些限制的数据块进行编码,则必须用零填充数据块,以便满足这些限制。 |
| matrix | int * | 这是一个具有k * m个元素的数组,表示编码矩阵-即分布矩阵的最后m行。 它的元素必须在0到2w−1之间。第i行和第j列中的元素在`matrix [i * k + j]中。 |
| bitmatrix | int * | 这是w⋅m⋅w⋅k元素的数组,组成二进制分配矩阵BDM的最后wm行。 第i行和第j列中的元素位于bitmatrix [i * k * w + j]中 |
| dataptrs | char ** | 这是k个指针数组,指向大小为字节的编码数据。 其中每一个必须是长字对齐的。 |
| coding_ptrs | char ** | 这是m个指针数组,指向大小为字节的编码数据。 其中每一个必须是长字对齐的。 |
| erasures | int * | 这是一组ID已删除的设备。 Id是介于0到k + m-1之间的数字。 如果擦除数为e,则擦除的元素0到e−1标识被擦除的设备,并且erasures [e]必须等于-1。 |
| erased | int * | 这是指定擦除的替代方法。 它是一个k+m的元素数组。 数组的元素i代表ID为i的设备。 如果erased[i]等于0,则设备i正在工作;如果等于1,则其被擦除。 |
| schdule | int ** | 这是一个5元素整数数组,用于优化位矩阵的编码计算。 如果计划中有o个操作,则计划必须至少包含o + 1个元素,并且schedule [o][0]应当等于-1。 |
| cache | int *** | 三维数组,用于保存一系列缓存地址,用于对RAID6解码进行优化。 |
| row_k_ones | bool | 布尔类型,用于对满足m>1的解码过程进行优化。解码时,如果对应编码矩阵第一行全部为1或者对应的二进制编码矩阵前w行构成k个单位矩阵,则设置此标志位有助于提升解码速度。 |
| decoding_matrix | int * | 这是用于解码的k×k矩阵或wk×wk位矩阵。 它是通过使用分布矩阵的相关行并将其求逆而构造的矩阵。 |
| dm_ids | int * | 一维数组,用于指定仍然正常的磁盘编号,帮助生成解码矩阵。 |
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/Coding ./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,解码也会失败!