// Copyright (c) Vitaliy Filippov, 2019+ // License: VNPL-1.1 (see README.md for details) #define RMW_DEBUG #ifdef NO_ISAL #undef WITH_ISAL #endif #include #include "osd_rmw.cpp" #include "test_pattern.h" void dump_stripes(osd_rmw_stripe_t *stripes, int pg_size); void test1(); void test4(); void test5(); void test6(); void test7(); void test_rmw_4k_degraded_into_lost_to_normal(bool ec); void test8(); void test9(); void test10(); void test11(); void test12(); void test13(); void test14(); void test15(bool second); void test16(); void test_recover_22_d2(); void test_ec43_error_bruteforce(); void test_recover_53_d5(); void test_recover_22(); int main(int narg, char *args[]) { // Test 1 test1(); // Test 4 test4(); // Test 5 test5(); // Test 6 test6(); // Test 7 test7(); test_rmw_4k_degraded_into_lost_to_normal(false); test_rmw_4k_degraded_into_lost_to_normal(true); // Test 8 test8(); // Test 9 test9(); // Test 10 test10(); // Test 11 test11(); // Test 12 test12(); // Test 13 test13(); // Test 14 test14(); // Test 15 test15(false); test15(true); // Test 16 test16(); // Test 17 test_recover_22_d2(); // Error bruteforce test_ec43_error_bruteforce(); // Test 19 test_recover_53_d5(); // Test 20 test_recover_22(); // End printf("all ok\n"); return 0; } void dump_stripes(osd_rmw_stripe_t *stripes, int pg_size) { printf("request"); for (int i = 0; i < pg_size; i++) { printf(" {%uK-%uK}", stripes[i].req_start/1024, stripes[i].req_end/1024); } printf("\n"); printf("read"); for (int i = 0; i < pg_size; i++) { printf(" {%uK-%uK}", stripes[i].read_start/1024, stripes[i].read_end/1024); } printf("\n"); printf("write"); for (int i = 0; i < pg_size; i++) { printf(" {%uK-%uK}", stripes[i].write_start/1024, stripes[i].write_end/1024); } printf("\n"); } /*** 1. split(offset=128K-4K, len=8K) = [ [ 128K-4K, 128K ], [ 0, 4K ], [ 0, 0 ] ] read(offset=128K-4K, len=8K, osd_set=[1,0,3]) = { read: [ [ 0, 128K ], [ 0, 4K ], [ 0, 4K ] ] } cover_read(0, 128K, { req: [ 128K-4K, 4K ] }) = { read: [ 0, 128K-4K ] } ***/ void test1() { osd_num_t osd_set[3] = { 1, 0, 3 }; osd_rmw_stripe_t stripes[3] = {}; // Test 1.1 split_stripes(2, 128*1024, 128*1024-4096, 8192, stripes); assert(stripes[0].req_start == 128*1024-4096 && stripes[0].req_end == 128*1024); assert(stripes[1].req_start == 0 && stripes[1].req_end == 4096); assert(stripes[2].req_end == 0); // Test 1.2 for (int i = 0; i < 3; i++) { stripes[i].read_start = stripes[i].req_start; stripes[i].read_end = stripes[i].req_end; } assert(extend_missing_stripes(stripes, osd_set, 2, 3) == 0); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024); assert(stripes[2].read_start == 0 && stripes[2].read_end == 4096); // Test 1.3 stripes[0] = (osd_rmw_stripe_t){ .req_start = 128*1024-4096, .req_end = 128*1024 }; cover_read(0, 128*1024, stripes[0]); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024-4096); } /*** 4. write(offset=128K-4K, len=8K, osd_set=[1,0,3]) = { read: [ [ 0, 128K ], [ 4K, 128K ], [ 4K, 128K ] ], write: [ [ 128K-4K, 128K ], [ 0, 4K ], [ 0, 128K ] ], input buffer: [ write0, write1 ], rmw buffer: [ write2, read0, read1, read2 ], } + check write2 buffer ***/ void test4() { const uint32_t bmp = 4; unsigned bitmaps[3] = { 0 }; osd_num_t osd_set[3] = { 1, 0, 3 }; osd_rmw_stripe_t stripes[3] = {}; // Test 4.1 split_stripes(2, 128*1024, 128*1024-4096, 8192, stripes); for (int i = 0; i < 3; i++) stripes[i].bmp_buf = bitmaps+i; void* write_buf = malloc(8192); void* rmw_buf = calc_rmw(write_buf, stripes, osd_set, 3, 2, 2, osd_set, 128*1024, bmp); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024); assert(stripes[1].read_start == 4096 && stripes[1].read_end == 128*1024); assert(stripes[2].read_start == 4096 && stripes[2].read_end == 128*1024); assert(stripes[0].write_start == 128*1024-4096 && stripes[0].write_end == 128*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 4096); assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); assert(stripes[0].read_buf == (uint8_t*)rmw_buf+128*1024); assert(stripes[1].read_buf == (uint8_t*)rmw_buf+128*1024*2); assert(stripes[2].read_buf == (uint8_t*)rmw_buf+128*1024*3-4096); assert(stripes[0].write_buf == write_buf); assert(stripes[1].write_buf == (uint8_t*)write_buf+4096); assert(stripes[2].write_buf == rmw_buf); // Test 4.2 set_pattern(write_buf, 8192, PATTERN0); set_pattern(stripes[0].read_buf, 128*1024, PATTERN1); // old data set_pattern(stripes[1].read_buf, 128*1024-4096, UINT64_MAX); // didn't read it, it's missing set_pattern(stripes[2].read_buf, 128*1024-4096, 0); // old parity = 0 memset(stripes[0].bmp_buf, 0, bmp); memset(stripes[1].bmp_buf, 0, bmp); memset(stripes[2].bmp_buf, 0, bmp); calc_rmw_parity_xor(stripes, 3, osd_set, osd_set, 128*1024, bmp); assert(*(uint32_t*)stripes[0].bmp_buf == 0x80000000); assert(*(uint32_t*)stripes[1].bmp_buf == 0x00000001); assert(*(uint32_t*)stripes[2].bmp_buf == 0x80000001); // XOR check_pattern(stripes[2].write_buf, 4096, PATTERN0^PATTERN1); // new parity check_pattern(stripes[2].write_buf+4096, 128*1024-4096*2, 0); // new parity check_pattern(stripes[2].write_buf+128*1024-4096, 4096, PATTERN0^PATTERN1); // new parity free(rmw_buf); free(write_buf); } /*** 5. write(offset=0, len=128K+64K, osd_set=[1,0,3]) = { req: [ [ 0, 128K ], [ 0, 64K ], [ 0, 0 ] ], read: [ [ 64K, 128K ], [ 64K, 128K ], [ 64K, 128K ] ], write: [ [ 0, 128K ], [ 0, 64K ], [ 0, 128K ] ], input buffer: [ write0, write1 ], rmw buffer: [ write2, read0, read1, read2 ], } ***/ void test5() { osd_num_t osd_set[3] = { 1, 0, 3 }; osd_rmw_stripe_t stripes[3] = {}; // Test 5.1 split_stripes(2, 128*1024, 0, 64*1024*3, stripes); assert(stripes[0].req_start == 0 && stripes[0].req_end == 128*1024); assert(stripes[1].req_start == 0 && stripes[1].req_end == 64*1024); assert(stripes[2].req_end == 0); // Test 5.2 void *write_buf = malloc(64*1024*3); void *rmw_buf = calc_rmw(write_buf, stripes, osd_set, 3, 2, 2, osd_set, 128*1024, 0); assert(stripes[0].read_start == 64*1024 && stripes[0].read_end == 128*1024); assert(stripes[1].read_start == 64*1024 && stripes[1].read_end == 128*1024); assert(stripes[2].read_start == 64*1024 && stripes[2].read_end == 128*1024); assert(stripes[0].write_start == 0 && stripes[0].write_end == 128*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 64*1024); assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); assert(stripes[0].read_buf == (uint8_t*)rmw_buf+128*1024); assert(stripes[1].read_buf == (uint8_t*)rmw_buf+64*3*1024); assert(stripes[2].read_buf == (uint8_t*)rmw_buf+64*4*1024); assert(stripes[0].write_buf == write_buf); assert(stripes[1].write_buf == (uint8_t*)write_buf+128*1024); assert(stripes[2].write_buf == rmw_buf); free(rmw_buf); free(write_buf); } /*** 6. write(offset=0, len=128K+64K, osd_set=[1,2,3]) = { req: [ [ 0, 128K ], [ 0, 64K ], [ 0, 0 ] ], read: [ [ 0, 0 ], [ 64K, 128K ], [ 0, 0 ] ], write: [ [ 0, 128K ], [ 0, 64K ], [ 0, 128K ] ], input buffer: [ write0, write1 ], rmw buffer: [ write2, read1 ], } ***/ void test6() { osd_num_t osd_set[3] = { 1, 2, 3 }; osd_rmw_stripe_t stripes[3] = {}; // Test 6.1 split_stripes(2, 128*1024, 0, 64*1024*3, stripes); void *write_buf = malloc(64*1024*3); void *rmw_buf = calc_rmw(write_buf, stripes, osd_set, 3, 2, 3, osd_set, 128*1024, 0); assert(stripes[0].read_end == 0); assert(stripes[1].read_start == 64*1024 && stripes[1].read_end == 128*1024); assert(stripes[2].read_end == 0); assert(stripes[0].write_start == 0 && stripes[0].write_end == 128*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 64*1024); assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); assert(stripes[0].read_buf == 0); assert(stripes[1].read_buf == (uint8_t*)rmw_buf+128*1024); assert(stripes[2].read_buf == 0); assert(stripes[0].write_buf == write_buf); assert(stripes[1].write_buf == (uint8_t*)write_buf+128*1024); assert(stripes[2].write_buf == rmw_buf); free(rmw_buf); free(write_buf); } /*** 7. calc_rmw(offset=128K-4K, len=8K, osd_set=[1,0,3], write_set=[1,2,3]) = { read: [ [ 0, 128K ], [ 0, 128K ], [ 0, 128K ] ], write: [ [ 128K-4K, 128K ], [ 0, 4K ], [ 0, 128K ] ], input buffer: [ write0, write1 ], rmw buffer: [ write2, read0, read1, read2 ], } then, after calc_rmw_parity_xor(): { write: [ [ 128K-4K, 128K ], [ 0, 128K ], [ 0, 128K ] ], write1==read1, } + check write1 buffer + check write2 buffer ***/ void test7() { osd_num_t osd_set[3] = { 1, 0, 3 }; osd_num_t write_osd_set[3] = { 1, 2, 3 }; osd_rmw_stripe_t stripes[3] = {}; // Test 7.1 split_stripes(2, 128*1024, 128*1024-4096, 8192, stripes); void *write_buf = malloc(8192); void *rmw_buf = calc_rmw(write_buf, stripes, osd_set, 3, 2, 2, write_osd_set, 128*1024, 0); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024); assert(stripes[1].read_start == 0 && stripes[1].read_end == 128*1024); assert(stripes[2].read_start == 0 && stripes[2].read_end == 128*1024); assert(stripes[0].write_start == 128*1024-4096 && stripes[0].write_end == 128*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 4096); assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); assert(stripes[0].read_buf == (uint8_t*)rmw_buf+128*1024); assert(stripes[1].read_buf == (uint8_t*)rmw_buf+128*1024*2); assert(stripes[2].read_buf == (uint8_t*)rmw_buf+128*1024*3); assert(stripes[0].write_buf == write_buf); assert(stripes[1].write_buf == (uint8_t*)write_buf+4096); assert(stripes[2].write_buf == rmw_buf); // Test 7.2 set_pattern(write_buf, 8192, PATTERN0); set_pattern(stripes[0].read_buf, 128*1024, PATTERN1); // old data set_pattern(stripes[1].read_buf, 128*1024, UINT64_MAX); // didn't read it, it's missing set_pattern(stripes[2].read_buf, 128*1024, 0); // old parity = 0 calc_rmw_parity_xor(stripes, 3, osd_set, write_osd_set, 128*1024, 0); assert(stripes[0].write_start == 128*1024-4096 && stripes[0].write_end == 128*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 128*1024); assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); assert(stripes[1].write_buf == stripes[1].read_buf); check_pattern(stripes[1].write_buf, 4096, PATTERN0); check_pattern(stripes[1].write_buf+4096, 128*1024-4096, PATTERN1); check_pattern(stripes[2].write_buf, 4096, PATTERN0^PATTERN1); // new parity check_pattern(stripes[2].write_buf+4096, 128*1024-4096*2, 0); // new parity check_pattern(stripes[2].write_buf+128*1024-4096, 4096, PATTERN0^PATTERN1); // new parity free(rmw_buf); free(write_buf); } /*** 7/2. calc_rmw(offset=48K, len=4K, osd_set=[0,2,3], write_set=[1,2,3]) = { read: [ [ 0, 128K ], [ 0, 128K ], [ 0, 128K ] ], write: [ [ 48K, 52K ], [ 0, 0 ], [ 48K, 52K ] ], input buffer: [ write0 ], rmw buffer: [ write2, read0, read1, read2 ], } then, after calc_rmw_parity_xor/ec(): { write: [ [ 0, 128K ], [ 0, 0 ], [ 48K, 52K ] ], write0==read0, } + check write0, write2 buffers ***/ void test_rmw_4k_degraded_into_lost_to_normal(bool ec) { osd_num_t osd_set[3] = { 0, 2, 3 }; osd_num_t write_osd_set[3] = { 1, 2, 3 }; osd_rmw_stripe_t stripes[3] = {}; // Subtest 1 split_stripes(2, 128*1024, 48*1024, 4096, stripes); void *write_buf = malloc(4096); void *rmw_buf = calc_rmw(write_buf, stripes, osd_set, 3, 2, 3, write_osd_set, 128*1024, 0); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024); assert(stripes[1].read_start == 0 && stripes[1].read_end == 128*1024); assert(stripes[2].read_start == 0 && stripes[2].read_end == 128*1024); assert(stripes[0].write_start == 48*1024 && stripes[0].write_end == 52*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 0); assert(stripes[2].write_start == 48*1024 && stripes[2].write_end == 52*1024); assert(stripes[0].read_buf == (uint8_t*)rmw_buf+4*1024); assert(stripes[1].read_buf == (uint8_t*)rmw_buf+4*1024+128*1024); assert(stripes[2].read_buf == (uint8_t*)rmw_buf+4*1024+2*128*1024); assert(stripes[0].write_buf == write_buf); assert(stripes[1].write_buf == NULL); assert(stripes[2].write_buf == rmw_buf); // Subtest 2 set_pattern(write_buf, 4096, PATTERN2); set_pattern(stripes[1].read_buf, 128*1024, PATTERN1); set_pattern(stripes[2].read_buf, 128*1024, PATTERN0^PATTERN1); if (!ec) calc_rmw_parity_xor(stripes, 3, osd_set, write_osd_set, 128*1024, 0); else { use_ec(3, 2, true); calc_rmw_parity_ec(stripes, 3, 2, osd_set, write_osd_set, 128*1024, 0); use_ec(3, 2, false); } assert(stripes[0].write_start == 0 && stripes[0].write_end == 128*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 0); assert(stripes[2].write_start == 48*1024 && stripes[2].write_end == 52*1024); assert(stripes[0].write_buf == stripes[0].read_buf); assert(stripes[1].write_buf == NULL); assert(stripes[2].write_buf == rmw_buf); check_pattern(stripes[0].write_buf, 4096, PATTERN0); check_pattern(stripes[0].write_buf+48*1024, 4096, PATTERN2); check_pattern(stripes[2].write_buf, 4096, PATTERN2^PATTERN1); // new parity free(rmw_buf); free(write_buf); } /*** 8. calc_rmw(offset=0, len=128K+4K, osd_set=[0,2,3], write_set=[1,2,3]) = { read: [ [ 0, 0 ], [ 4K, 128K ], [ 0, 0 ] ], write: [ [ 0, 128K ], [ 0, 4K ], [ 0, 128K ] ], input buffer: [ write0, write1 ], rmw buffer: [ write2, read1 ], } + check write2 buffer ***/ void test8() { osd_num_t osd_set[3] = { 0, 2, 3 }; osd_num_t write_osd_set[3] = { 1, 2, 3 }; osd_rmw_stripe_t stripes[3] = {}; // Test 8.1 split_stripes(2, 128*1024, 0, 128*1024+4096, stripes); void *write_buf = malloc(128*1024+4096); void *rmw_buf = calc_rmw(write_buf, stripes, osd_set, 3, 2, 2, write_osd_set, 128*1024, 0); assert(stripes[0].read_start == 0 && stripes[0].read_end == 0); assert(stripes[1].read_start == 4096 && stripes[1].read_end == 128*1024); assert(stripes[2].read_start == 0 && stripes[2].read_end == 0); assert(stripes[0].write_start == 0 && stripes[0].write_end == 128*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 4096); assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); assert(stripes[0].read_buf == NULL); assert(stripes[1].read_buf == (uint8_t*)rmw_buf+128*1024); assert(stripes[2].read_buf == NULL); assert(stripes[0].write_buf == write_buf); assert(stripes[1].write_buf == (uint8_t*)write_buf+128*1024); assert(stripes[2].write_buf == rmw_buf); // Test 8.2 set_pattern(write_buf, 128*1024+4096, PATTERN0); set_pattern(stripes[1].read_buf, 128*1024-4096, PATTERN1); calc_rmw_parity_xor(stripes, 3, osd_set, write_osd_set, 128*1024, 0); assert(stripes[0].write_start == 0 && stripes[0].write_end == 128*1024); // recheck again assert(stripes[1].write_start == 0 && stripes[1].write_end == 4096); // recheck again assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); // recheck again assert(stripes[0].write_buf == write_buf); // recheck again assert(stripes[1].write_buf == (uint8_t*)write_buf+128*1024); // recheck again assert(stripes[2].write_buf == rmw_buf); // recheck again check_pattern(stripes[2].write_buf, 4096, 0); // new parity check_pattern(stripes[2].write_buf+4096, 128*1024-4096, PATTERN0^PATTERN1); // new parity free(rmw_buf); free(write_buf); } /*** 9. object recovery case: calc_rmw(offset=0, len=0, read_osd_set=[0,2,3], write_osd_set=[1,2,3]) = { read: [ [ 0, 128K ], [ 0, 128K ], [ 0, 128K ] ], write: [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], input buffer: NULL, rmw buffer: [ read0, read1, read2 ], } then, after calc_rmw_parity_xor(): { write: [ [ 0, 128K ], [ 0, 0 ], [ 0, 0 ] ], write0==read0, } + check write0 buffer ***/ void test9() { osd_num_t osd_set[3] = { 0, 2, 3 }; osd_num_t write_osd_set[3] = { 1, 2, 3 }; osd_rmw_stripe_t stripes[3] = {}; // Test 9.0 split_stripes(2, 128*1024, 64*1024, 0, stripes); assert(stripes[0].req_start == 0 && stripes[0].req_end == 0); assert(stripes[1].req_start == 0 && stripes[1].req_end == 0); assert(stripes[2].req_start == 0 && stripes[2].req_end == 0); // Test 9.1 void *write_buf = NULL; void *rmw_buf = calc_rmw(write_buf, stripes, osd_set, 3, 2, 3, write_osd_set, 128*1024, 0); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024); assert(stripes[1].read_start == 0 && stripes[1].read_end == 128*1024); assert(stripes[2].read_start == 0 && stripes[2].read_end == 128*1024); assert(stripes[0].write_start == 0 && stripes[0].write_end == 0); assert(stripes[1].write_start == 0 && stripes[1].write_end == 0); assert(stripes[2].write_start == 0 && stripes[2].write_end == 0); assert(stripes[0].read_buf == rmw_buf); assert(stripes[1].read_buf == (uint8_t*)rmw_buf+128*1024); assert(stripes[2].read_buf == (uint8_t*)rmw_buf+128*1024*2); assert(stripes[0].write_buf == NULL); assert(stripes[1].write_buf == NULL); assert(stripes[2].write_buf == NULL); // Test 9.2 set_pattern(stripes[1].read_buf, 128*1024, 0); set_pattern(stripes[2].read_buf, 128*1024, PATTERN1); calc_rmw_parity_xor(stripes, 3, osd_set, write_osd_set, 128*1024, 0); assert(stripes[0].write_start == 0 && stripes[0].write_end == 128*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 0); assert(stripes[2].write_start == 0 && stripes[2].write_end == 0); assert(stripes[0].write_buf == rmw_buf); assert(stripes[1].write_buf == NULL); assert(stripes[2].write_buf == NULL); check_pattern(stripes[0].read_buf, 128*1024, PATTERN1); check_pattern(stripes[0].write_buf, 128*1024, PATTERN1); free(rmw_buf); } /*** 10. full overwrite/recovery case: calc_rmw(offset=0, len=256K, read_osd_set=[1,0,0], write_osd_set=[1,2,3]) = { read: [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], write: [ [ 0, 128K ], [ 0, 128K ], [ 0, 128K ] ], input buffer: [ write0, write1 ], rmw buffer: [ write2 ], } then, after calc_rmw_parity_xor(): all the same + check write2 buffer ***/ void test10() { osd_num_t osd_set[3] = { 1, 0, 0 }; osd_num_t write_osd_set[3] = { 1, 2, 3 }; osd_rmw_stripe_t stripes[3] = {}; // Test 10.0 split_stripes(2, 128*1024, 0, 256*1024, stripes); assert(stripes[0].req_start == 0 && stripes[0].req_end == 128*1024); assert(stripes[1].req_start == 0 && stripes[1].req_end == 128*1024); assert(stripes[2].req_start == 0 && stripes[2].req_end == 0); // Test 10.1 void *write_buf = malloc(256*1024); void *rmw_buf = calc_rmw(write_buf, stripes, osd_set, 3, 2, 3, write_osd_set, 128*1024, 0); assert(rmw_buf); assert(stripes[0].read_start == 0 && stripes[0].read_end == 0); assert(stripes[1].read_start == 0 && stripes[1].read_end == 0); assert(stripes[2].read_start == 0 && stripes[2].read_end == 0); assert(stripes[0].write_start == 0 && stripes[0].write_end == 128*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 128*1024); assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); assert(stripes[0].read_buf == NULL); assert(stripes[1].read_buf == NULL); assert(stripes[2].read_buf == NULL); assert(stripes[0].write_buf == write_buf); assert(stripes[1].write_buf == (uint8_t*)write_buf+128*1024); assert(stripes[2].write_buf == rmw_buf); // Test 10.2 set_pattern(stripes[0].write_buf, 128*1024, PATTERN1); set_pattern(stripes[1].write_buf, 128*1024, PATTERN2); calc_rmw_parity_xor(stripes, 3, osd_set, write_osd_set, 128*1024, 0); assert(stripes[0].write_start == 0 && stripes[0].write_end == 128*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 128*1024); assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); assert(stripes[0].write_buf == write_buf); assert(stripes[1].write_buf == (uint8_t*)write_buf+128*1024); assert(stripes[2].write_buf == rmw_buf); check_pattern(stripes[2].write_buf, 128*1024, PATTERN1^PATTERN2); free(rmw_buf); free(write_buf); } /*** 11. partial recovery case: calc_rmw(offset=128K, len=128K, read_osd_set=[1,0,0], write_osd_set=[1,2,3]) = { read: [ [ 0, 128K ], [ 0, 0 ], [ 0, 0 ] ], write: [ [ 0, 0 ], [ 0, 128K ], [ 0, 128K ] ], input buffer: [ write1 ], rmw buffer: [ write2, read0 ], } then, after calc_rmw_parity_xor(): all the same + check write2 buffer ***/ void test11() { osd_num_t osd_set[3] = { 1, 0, 0 }; osd_num_t write_osd_set[3] = { 1, 2, 3 }; osd_rmw_stripe_t stripes[3] = {}; // Test 11.0 split_stripes(2, 128*1024, 128*1024, 256*1024, stripes); assert(stripes[0].req_start == 0 && stripes[0].req_end == 0); assert(stripes[1].req_start == 0 && stripes[1].req_end == 128*1024); assert(stripes[2].req_start == 0 && stripes[2].req_end == 0); // Test 11.1 void *write_buf = malloc(256*1024); void *rmw_buf = calc_rmw(write_buf, stripes, osd_set, 3, 2, 3, write_osd_set, 128*1024, 0); assert(rmw_buf); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024); assert(stripes[1].read_start == 0 && stripes[1].read_end == 0); assert(stripes[2].read_start == 0 && stripes[2].read_end == 0); assert(stripes[0].write_start == 0 && stripes[0].write_end == 0); assert(stripes[1].write_start == 0 && stripes[1].write_end == 128*1024); assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); assert(stripes[0].read_buf == (uint8_t*)rmw_buf+128*1024); assert(stripes[1].read_buf == NULL); assert(stripes[2].read_buf == NULL); assert(stripes[0].write_buf == NULL); assert(stripes[1].write_buf == write_buf); assert(stripes[2].write_buf == rmw_buf); // Test 11.2 set_pattern(stripes[0].read_buf, 128*1024, PATTERN1); set_pattern(stripes[1].write_buf, 128*1024, PATTERN2); calc_rmw_parity_xor(stripes, 3, osd_set, write_osd_set, 128*1024, 0); assert(stripes[0].write_start == 0 && stripes[0].write_end == 0); assert(stripes[1].write_start == 0 && stripes[1].write_end == 128*1024); assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); assert(stripes[0].write_buf == NULL); assert(stripes[1].write_buf == write_buf); assert(stripes[2].write_buf == rmw_buf); check_pattern(stripes[2].write_buf, 128*1024, PATTERN1^PATTERN2); free(rmw_buf); free(write_buf); } /*** 12. parity recovery case: calc_rmw(offset=0, len=0, read_osd_set=[1,2,0], write_osd_set=[1,2,3]) = { read: [ [ 0, 128K ], [ 0, 128K ], [ 0, 0 ] ], write: [ [ 0, 0 ], [ 0, 0 ], [ 0, 128K ] ], input buffer: [], rmw buffer: [ write2, read0, read1 ], } then, after calc_rmw_parity_xor(): all the same + check write2 buffer ***/ void test12() { osd_num_t osd_set[3] = { 1, 2, 0 }; osd_num_t write_osd_set[3] = { 1, 2, 3 }; osd_rmw_stripe_t stripes[3] = {}; // Test 12.0 split_stripes(2, 128*1024, 0, 0, stripes); assert(stripes[0].req_start == 0 && stripes[0].req_end == 0); assert(stripes[1].req_start == 0 && stripes[1].req_end == 0); assert(stripes[2].req_start == 0 && stripes[2].req_end == 0); // Test 12.1 void *rmw_buf = calc_rmw(NULL, stripes, osd_set, 3, 2, 3, write_osd_set, 128*1024, 0); assert(rmw_buf); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024); assert(stripes[1].read_start == 0 && stripes[1].read_end == 128*1024); assert(stripes[2].read_start == 0 && stripes[2].read_end == 0); assert(stripes[0].write_start == 0 && stripes[0].write_end == 0); assert(stripes[1].write_start == 0 && stripes[1].write_end == 0); assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); assert(stripes[0].read_buf == (uint8_t*)rmw_buf+128*1024); assert(stripes[1].read_buf == (uint8_t*)rmw_buf+2*128*1024); assert(stripes[2].read_buf == NULL); assert(stripes[0].write_buf == NULL); assert(stripes[1].write_buf == NULL); assert(stripes[2].write_buf == rmw_buf); // Test 12.2 set_pattern(stripes[0].read_buf, 128*1024, PATTERN1); set_pattern(stripes[1].read_buf, 128*1024, PATTERN2); calc_rmw_parity_xor(stripes, 3, osd_set, write_osd_set, 128*1024, 0); assert(stripes[0].write_start == 0 && stripes[0].write_end == 0); assert(stripes[1].write_start == 0 && stripes[1].write_end == 0); assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); assert(stripes[0].write_buf == NULL); assert(stripes[1].write_buf == NULL); assert(stripes[2].write_buf == rmw_buf); check_pattern(stripes[2].write_buf, 128*1024, PATTERN1^PATTERN2); free(rmw_buf); } /*** 13. basic jerasure 2+2 test calc_rmw(offset=128K-4K, len=8K, osd_set=[1,2,0,0], write_set=[1,2,3,4]) = { read: [ [ 0, 128K ], [ 0, 128K ], [ 0, 0 ], [ 0, 0 ] ], write: [ [ 128K-4K, 128K ], [ 0, 4K ], [ 0, 128K ], [ 0, 128K ] ], input buffer: [ write0, write1 ], rmw buffer: [ write2, write3, read0, read1 ], } then, after calc_rmw_parity_ec(): all the same then simulate read with read_osd_set=[0,0,3,4] and check read0,read1 buffers ***/ void test13() { use_ec(4, 2, true); osd_num_t osd_set[4] = { 1, 2, 0, 0 }; osd_num_t write_osd_set[4] = { 1, 2, 3, 4 }; osd_rmw_stripe_t stripes[4] = {}; // Test 13.0 void *write_buf = malloc_or_die(8192); split_stripes(2, 128*1024, 128*1024-4096, 8192, stripes); assert(stripes[0].req_start == 128*1024-4096 && stripes[0].req_end == 128*1024); assert(stripes[1].req_start == 0 && stripes[1].req_end == 4096); assert(stripes[2].req_start == 0 && stripes[2].req_end == 0); assert(stripes[3].req_start == 0 && stripes[3].req_end == 0); // Test 13.1 void *rmw_buf = calc_rmw(write_buf, stripes, osd_set, 4, 2, 4, write_osd_set, 128*1024, 0); assert(rmw_buf); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024-4096); assert(stripes[1].read_start == 4096 && stripes[1].read_end == 128*1024); assert(stripes[2].read_start == 0 && stripes[2].read_end == 0); assert(stripes[3].read_start == 0 && stripes[3].read_end == 0); assert(stripes[0].write_start == 128*1024-4096 && stripes[0].write_end == 128*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 4096); assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); assert(stripes[3].write_start == 0 && stripes[3].write_end == 128*1024); assert(stripes[0].read_buf == (uint8_t*)rmw_buf+2*128*1024); assert(stripes[1].read_buf == (uint8_t*)rmw_buf+3*128*1024-4096); assert(stripes[2].read_buf == NULL); assert(stripes[3].read_buf == NULL); assert(stripes[0].write_buf == write_buf); assert(stripes[1].write_buf == (uint8_t*)write_buf+4096); assert(stripes[2].write_buf == rmw_buf); assert(stripes[3].write_buf == (uint8_t*)rmw_buf+128*1024); // Test 13.2 - encode set_pattern(write_buf, 8192, PATTERN3); set_pattern(stripes[0].read_buf, 128*1024-4096, PATTERN1); set_pattern(stripes[1].read_buf, 128*1024-4096, PATTERN2); calc_rmw_parity_ec(stripes, 4, 2, osd_set, write_osd_set, 128*1024, 0); assert(stripes[0].write_start == 128*1024-4096 && stripes[0].write_end == 128*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 4096); assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); assert(stripes[3].write_start == 0 && stripes[3].write_end == 128*1024); assert(stripes[0].write_buf == write_buf); assert(stripes[1].write_buf == (uint8_t*)write_buf+4096); assert(stripes[2].write_buf == rmw_buf); assert(stripes[3].write_buf == (uint8_t*)rmw_buf+128*1024); // Test 13.3 - full decode and verify osd_num_t read_osd_set[4] = { 0, 0, 3, 4 }; memset(stripes, 0, sizeof(stripes)); split_stripes(2, 128*1024, 0, 256*1024, stripes); assert(stripes[0].req_start == 0 && stripes[0].req_end == 128*1024); assert(stripes[1].req_start == 0 && stripes[1].req_end == 128*1024); assert(stripes[2].req_start == 0 && stripes[2].req_end == 0); assert(stripes[3].req_start == 0 && stripes[3].req_end == 0); for (int role = 0; role < 4; role++) { stripes[role].read_start = stripes[role].req_start; stripes[role].read_end = stripes[role].req_end; } assert(extend_missing_stripes(stripes, read_osd_set, 2, 4) == 0); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024); assert(stripes[1].read_start == 0 && stripes[1].read_end == 128*1024); assert(stripes[2].read_start == 0 && stripes[2].read_end == 128*1024); assert(stripes[3].read_start == 0 && stripes[3].read_end == 128*1024); void *read_buf = alloc_read_buffer(stripes, 4, 0); assert(read_buf); assert(stripes[0].read_buf == read_buf); assert(stripes[1].read_buf == (uint8_t*)read_buf+128*1024); assert(stripes[2].read_buf == (uint8_t*)read_buf+2*128*1024); assert(stripes[3].read_buf == (uint8_t*)read_buf+3*128*1024); memcpy((uint8_t*)read_buf+2*128*1024, rmw_buf, 128*1024); memcpy((uint8_t*)read_buf+3*128*1024, (uint8_t*)rmw_buf+128*1024, 128*1024); reconstruct_stripes_ec(stripes, 4, 2, 0); check_pattern(stripes[0].read_buf, 128*1024-4096, PATTERN1); check_pattern(stripes[0].read_buf+128*1024-4096, 4096, PATTERN3); check_pattern(stripes[1].read_buf, 4096, PATTERN3); check_pattern(stripes[1].read_buf+4096, 128*1024-4096, PATTERN2); free(read_buf); // Test 13.4 - partial decode (only 1st chunk) and verify memset(stripes, 0, sizeof(stripes)); split_stripes(2, 128*1024, 0, 128*1024, stripes); assert(stripes[0].req_start == 0 && stripes[0].req_end == 128*1024); assert(stripes[1].req_start == 0 && stripes[1].req_end == 0); assert(stripes[2].req_start == 0 && stripes[2].req_end == 0); assert(stripes[3].req_start == 0 && stripes[3].req_end == 0); for (int role = 0; role < 4; role++) { stripes[role].read_start = stripes[role].req_start; stripes[role].read_end = stripes[role].req_end; } assert(extend_missing_stripes(stripes, read_osd_set, 2, 4) == 0); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024); assert(stripes[1].read_start == 0 && stripes[1].read_end == 0); assert(stripes[2].read_start == 0 && stripes[2].read_end == 128*1024); assert(stripes[3].read_start == 0 && stripes[3].read_end == 128*1024); read_buf = alloc_read_buffer(stripes, 4, 0); assert(read_buf); assert(stripes[0].read_buf == read_buf); assert(stripes[1].read_buf == NULL); assert(stripes[2].read_buf == (uint8_t*)read_buf+128*1024); assert(stripes[3].read_buf == (uint8_t*)read_buf+2*128*1024); memcpy((uint8_t*)read_buf+128*1024, rmw_buf, 128*1024); memcpy((uint8_t*)read_buf+2*128*1024, (uint8_t*)rmw_buf+128*1024, 128*1024); reconstruct_stripes_ec(stripes, 4, 2, 0); check_pattern(stripes[0].read_buf, 128*1024-4096, PATTERN1); check_pattern(stripes[0].read_buf+128*1024-4096, 4096, PATTERN3); free(read_buf); // Huh done free(rmw_buf); free(write_buf); use_ec(4, 2, false); } /*** 14. basic jerasure 2+1 test calc_rmw(offset=128K-4K, len=8K, osd_set=[1,2,0], write_set=[1,2,3]) = { read: [ [ 0, 128K ], [ 0, 128K ], [ 0, 0 ] ], write: [ [ 128K-4K, 128K ], [ 0, 4K ], [ 0, 128K ] ], input buffer: [ write0, write1 ], rmw buffer: [ write2, read0, read1 ], } then, after calc_rmw_parity_ec(): all the same then simulate read with read_osd_set=[0,2,3] and check read0 buffer ***/ void test14() { const int bmp = 4; use_ec(3, 2, true); osd_num_t osd_set[3] = { 1, 2, 0 }; osd_num_t write_osd_set[3] = { 1, 2, 3 }; osd_rmw_stripe_t stripes[3] = {}; unsigned bitmaps[3] = { 0 }; // Test 14.0 void *write_buf = malloc_or_die(8192); split_stripes(2, 128*1024, 128*1024-4096, 8192, stripes); assert(stripes[0].req_start == 128*1024-4096 && stripes[0].req_end == 128*1024); assert(stripes[1].req_start == 0 && stripes[1].req_end == 4096); assert(stripes[2].req_start == 0 && stripes[2].req_end == 0); // Test 14.1 void *rmw_buf = calc_rmw(write_buf, stripes, osd_set, 3, 2, 3, write_osd_set, 128*1024, bmp); for (int i = 0; i < 3; i++) stripes[i].bmp_buf = bitmaps+i; assert(rmw_buf); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024-4096); assert(stripes[1].read_start == 4096 && stripes[1].read_end == 128*1024); assert(stripes[2].read_start == 0 && stripes[2].read_end == 0); assert(stripes[0].write_start == 128*1024-4096 && stripes[0].write_end == 128*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 4096); assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); assert(stripes[0].read_buf == (uint8_t*)rmw_buf+128*1024); assert(stripes[1].read_buf == (uint8_t*)rmw_buf+2*128*1024-4096); assert(stripes[2].read_buf == NULL); assert(stripes[0].write_buf == write_buf); assert(stripes[1].write_buf == (uint8_t*)write_buf+4096); assert(stripes[2].write_buf == rmw_buf); // Test 14.2 - encode set_pattern(write_buf, 8192, PATTERN3); set_pattern(stripes[0].read_buf, 128*1024-4096, PATTERN1); set_pattern(stripes[1].read_buf, 128*1024-4096, PATTERN2); memset(stripes[0].bmp_buf, 0, bmp); memset(stripes[1].bmp_buf, 0, bmp); memset(stripes[2].bmp_buf, 0, bmp); calc_rmw_parity_ec(stripes, 3, 2, osd_set, write_osd_set, 128*1024, bmp); assert(*(uint32_t*)stripes[0].bmp_buf == 0x80000000); assert(*(uint32_t*)stripes[1].bmp_buf == 0x00000001); assert(*(uint32_t*)stripes[2].bmp_buf == 0x80000001); // jerasure 2+1 is still just XOR assert(stripes[0].write_start == 128*1024-4096 && stripes[0].write_end == 128*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 4096); assert(stripes[2].write_start == 0 && stripes[2].write_end == 128*1024); assert(stripes[0].write_buf == write_buf); assert(stripes[1].write_buf == (uint8_t*)write_buf+4096); assert(stripes[2].write_buf == rmw_buf); // Test 14.3 - decode and verify osd_num_t read_osd_set[4] = { 0, 2, 3 }; memset(stripes, 0, sizeof(stripes)); split_stripes(2, 128*1024, 0, 128*1024, stripes); assert(stripes[0].req_start == 0 && stripes[0].req_end == 128*1024); assert(stripes[1].req_start == 0 && stripes[1].req_end == 0); assert(stripes[2].req_start == 0 && stripes[2].req_end == 0); for (int role = 0; role < 3; role++) { stripes[role].read_start = stripes[role].req_start; stripes[role].read_end = stripes[role].req_end; } assert(extend_missing_stripes(stripes, read_osd_set, 2, 3) == 0); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024); assert(stripes[1].read_start == 0 && stripes[1].read_end == 128*1024); assert(stripes[2].read_start == 0 && stripes[2].read_end == 128*1024); void *read_buf = alloc_read_buffer(stripes, 3, 0); for (int i = 0; i < 3; i++) stripes[i].bmp_buf = bitmaps+i; assert(read_buf); assert(stripes[0].read_buf == read_buf); assert(stripes[1].read_buf == (uint8_t*)read_buf+128*1024); assert(stripes[2].read_buf == (uint8_t*)read_buf+2*128*1024); set_pattern(stripes[1].read_buf, 4096, PATTERN3); set_pattern(stripes[1].read_buf+4096, 128*1024-4096, PATTERN2); memcpy(stripes[2].read_buf, rmw_buf, 128*1024); reconstruct_stripes_ec(stripes, 3, 2, bmp); check_pattern(stripes[0].read_buf, 128*1024-4096, PATTERN1); check_pattern(stripes[0].read_buf+128*1024-4096, 4096, PATTERN3); free(read_buf); // Huh done free(rmw_buf); free(write_buf); use_ec(3, 2, false); } /*** 15. EC 2+2 partial overwrite with 1 missing stripe calc_rmw(offset=64K+28K, len=4K, osd_set=[1,2,3,0], write_set=[1,2,3,0]) = { read: [ [ 28K, 32K ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], write: [ [ 0, 0 ], [ 28K, 32K ], [ 28K, 32K ], [ 0, 0 ] ], input buffer: [ write1 ], rmw buffer: [ write2, read0 ], } ***/ void test15(bool second) { const int bmp = 64*1024 / 4096 / 8; use_ec(4, 2, true); osd_num_t osd_set[4] = { 1, 2, (osd_num_t)(second ? 0 : 3), (osd_num_t)(second ? 4 : 0) }; osd_rmw_stripe_t stripes[4] = {}; unsigned bitmaps[4] = { 0 }; // Test 15.0 void *write_buf = malloc_or_die(4096); split_stripes(2, 64*1024, (64+28)*1024, 4096, stripes); assert(stripes[0].req_start == 0 && stripes[0].req_end == 0); assert(stripes[1].req_start == 28*1024 && stripes[1].req_end == 32*1024); assert(stripes[2].req_start == 0 && stripes[2].req_end == 0); assert(stripes[3].req_start == 0 && stripes[3].req_end == 0); // Test 15.1 void *rmw_buf = calc_rmw(write_buf, stripes, osd_set, 4, 2, 3, osd_set, 64*1024, bmp); for (int i = 0; i < 4; i++) stripes[i].bmp_buf = bitmaps+i; assert(rmw_buf); assert(stripes[0].read_start == 28*1024 && stripes[0].read_end == 32*1024); assert(stripes[1].read_start == 0 && stripes[1].read_end == 0); assert(stripes[2].read_start == 0 && stripes[2].read_end == 0); assert(stripes[3].read_start == 0 && stripes[3].read_end == 0); assert(stripes[0].write_start == 0 && stripes[0].write_end == 0); assert(stripes[1].write_start == 28*1024 && stripes[1].write_end == 32*1024); assert(stripes[2+second].write_start == 28*1024 && stripes[2+second].write_end == 32*1024); assert(stripes[3-second].write_start == 0 && stripes[3-second].write_end == 0); assert(stripes[0].read_buf == (uint8_t*)rmw_buf+4*1024); assert(stripes[1].read_buf == NULL); assert(stripes[2].read_buf == NULL); assert(stripes[3].read_buf == NULL); assert(stripes[0].write_buf == NULL); assert(stripes[1].write_buf == (uint8_t*)write_buf); assert(stripes[2+second].write_buf == rmw_buf); assert(stripes[3-second].write_buf == NULL); // Test 15.2 - encode set_pattern(write_buf, 4*1024, PATTERN1); set_pattern(stripes[0].read_buf, 4*1024, PATTERN2); memset(stripes[0].bmp_buf, 0, bmp); memset(stripes[1].bmp_buf, 0, bmp); memset(stripes[2+second].write_buf, 0, 4096); calc_rmw_parity_ec(stripes, 4, 2, osd_set, osd_set, 64*1024, bmp); assert(second || *(uint32_t*)stripes[2].bmp_buf == 0x80); assert(stripes[0].write_start == 0 && stripes[0].write_end == 0); assert(stripes[1].write_start == 28*1024 && stripes[1].write_end == 32*1024); assert(stripes[2+second].write_start == 28*1024 && stripes[2+second].write_end == 32*1024); assert(stripes[3-second].write_start == 0 && stripes[3-second].write_end == 0); assert(stripes[0].write_buf == NULL); assert(stripes[1].write_buf == (uint8_t*)write_buf); assert(stripes[2+second].write_buf == rmw_buf); assert(stripes[3-second].write_buf == NULL); // first parity is always xor :), second isn't... check_pattern(stripes[2+second].write_buf, 4*1024, second ? 0xb79a59a0ce8b9b81 : PATTERN1^PATTERN2); // Done free(rmw_buf); free(write_buf); use_ec(4, 2, false); } /*** 16. EC 2+2 write one parity block with another missing calc_rmw(offset=0, len=0, osd_set=[1,2,0,0], write_set=[1,2,0,3]) = { read: [ [ 0, 128K ], [ 0, 128K ], [ 0, 0 ], [ 0, 0 ] ], write: [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 128K ] ], input buffer: [], rmw buffer: [ write3, read0, read1 ], } ***/ void test16() { const int bmp = 128*1024 / 4096 / 8; use_ec(4, 2, true); osd_num_t osd_set[4] = { 1, 2, 0, 0 }; osd_num_t write_osd_set[4] = { 1, 2, 0, 3 }; osd_rmw_stripe_t stripes[4] = {}; unsigned bitmaps[4] = { 0 }; // Test 16.0 void *write_buf = NULL; split_stripes(2, 128*1024, 0, 0, stripes); assert(stripes[0].req_start == 0 && stripes[0].req_end == 0); assert(stripes[1].req_start == 0 && stripes[1].req_end == 0); assert(stripes[2].req_start == 0 && stripes[2].req_end == 0); assert(stripes[3].req_start == 0 && stripes[3].req_end == 0); // Test 16.1 void *rmw_buf = calc_rmw(write_buf, stripes, osd_set, 4, 2, 3, write_osd_set, 128*1024, bmp); for (int i = 0; i < 4; i++) stripes[i].bmp_buf = bitmaps+i; assert(rmw_buf); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024); assert(stripes[1].read_start == 0 && stripes[1].read_end == 128*1024); assert(stripes[2].read_start == 0 && stripes[2].read_end == 0); assert(stripes[3].read_start == 0 && stripes[3].read_end == 0); assert(stripes[0].write_start == 0 && stripes[0].write_end == 0); assert(stripes[1].write_start == 0 && stripes[1].write_end == 0); assert(stripes[2].write_start == 0 && stripes[2].write_end == 0); assert(stripes[3].write_start == 0 && stripes[3].write_end == 128*1024); assert(stripes[0].read_buf == (uint8_t*)rmw_buf+128*1024); assert(stripes[1].read_buf == (uint8_t*)rmw_buf+256*1024); assert(stripes[2].read_buf == NULL); assert(stripes[3].read_buf == NULL); assert(stripes[0].write_buf == NULL); assert(stripes[1].write_buf == NULL); assert(stripes[2].write_buf == NULL); assert(stripes[3].write_buf == rmw_buf); // Test 16.2 - encode set_pattern(stripes[0].read_buf, 128*1024, PATTERN1); set_pattern(stripes[1].read_buf, 128*1024, PATTERN2); memset(stripes[0].bmp_buf, 0xff, bmp); memset(stripes[1].bmp_buf, 0xff, bmp); calc_rmw_parity_ec(stripes, 4, 2, osd_set, write_osd_set, 128*1024, bmp); assert(*(uint32_t*)stripes[2].bmp_buf == 0); assert(*(uint32_t*)stripes[3].bmp_buf == 0xF1F1F1F1); assert(stripes[0].write_start == 0 && stripes[0].write_end == 0); assert(stripes[1].write_start == 0 && stripes[1].write_end == 0); assert(stripes[2].write_start == 0 && stripes[2].write_end == 0); assert(stripes[3].write_start == 0 && stripes[3].write_end == 128*1024); assert(stripes[0].write_buf == NULL); assert(stripes[1].write_buf == NULL); assert(stripes[2].write_buf == NULL); assert(stripes[3].write_buf == rmw_buf); check_pattern(stripes[3].write_buf, 128*1024, 0x7eb9ae9cd8e652c3); // 2nd EC chunk // Test 16.3 - decode and verify osd_num_t read_osd_set[4] = { 0, 2, 0, 3 }; memset(stripes, 0, sizeof(stripes)); split_stripes(2, 128*1024, 0, 256*1024, stripes); assert(stripes[0].req_start == 0 && stripes[0].req_end == 128*1024); assert(stripes[1].req_start == 0 && stripes[1].req_end == 128*1024); assert(stripes[2].req_start == 0 && stripes[2].req_end == 0); assert(stripes[3].req_start == 0 && stripes[3].req_end == 0); for (int role = 0; role < 4; role++) { stripes[role].read_start = stripes[role].req_start; stripes[role].read_end = stripes[role].req_end; } assert(extend_missing_stripes(stripes, read_osd_set, 2, 4) == 0); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024); assert(stripes[1].read_start == 0 && stripes[1].read_end == 128*1024); assert(stripes[2].read_start == 0 && stripes[2].read_end == 0); assert(stripes[3].read_start == 0 && stripes[3].read_end == 128*1024); void *read_buf = alloc_read_buffer(stripes, 4, 0); for (int i = 0; i < 4; i++) stripes[i].bmp_buf = bitmaps+i; assert(read_buf); assert(stripes[0].read_buf == read_buf); assert(stripes[1].read_buf == (uint8_t*)read_buf+128*1024); assert(stripes[3].read_buf == (uint8_t*)read_buf+2*128*1024); set_pattern(stripes[1].read_buf, 128*1024, PATTERN2); memcpy(stripes[3].read_buf, rmw_buf, 128*1024); memset(stripes[0].bmp_buf, 0xa8, bmp); memset(stripes[2].bmp_buf, 0xb7, bmp); assert(bitmaps[1] == 0xFFFFFFFF); assert(bitmaps[3] == 0xF1F1F1F1); reconstruct_stripes_ec(stripes, 4, 2, bmp); assert(*(uint32_t*)stripes[3].bmp_buf == 0xF1F1F1F1); assert(bitmaps[0] == 0xFFFFFFFF); check_pattern(stripes[0].read_buf, 128*1024, PATTERN1); free(read_buf); // Done free(rmw_buf); free(write_buf); use_ec(4, 2, false); } /*** 17. EC 2+2 recover second data block ***/ void test_recover_22_d2() { const int bmp = 128*1024 / 4096 / 8; use_ec(4, 2, true); osd_num_t osd_set[4] = { 1, 0, 3, 4 }; osd_rmw_stripe_t stripes[4] = {}; unsigned bitmaps[4] = { 0 }; // Read 0-256K split_stripes(2, 128*1024, 0, 256*1024, stripes); assert(stripes[0].req_start == 0 && stripes[0].req_end == 128*1024); assert(stripes[1].req_start == 0 && stripes[1].req_end == 128*1024); assert(stripes[2].req_start == 0 && stripes[2].req_end == 0); assert(stripes[3].req_start == 0 && stripes[3].req_end == 0); uint8_t *data_buf = (uint8_t*)malloc_or_die(128*1024*4); for (int i = 0; i < 4; i++) { stripes[i].read_start = stripes[i].req_start; stripes[i].read_end = stripes[i].req_end; stripes[i].read_buf = data_buf + i*128*1024; stripes[i].bmp_buf = bitmaps + i; } // Read using parity assert(extend_missing_stripes(stripes, osd_set, 2, 4) == 0); assert(stripes[2].read_start == 0 && stripes[2].read_end == 128*1024); assert(stripes[3].read_start == 0 && stripes[3].read_end == 0); bitmaps[0] = 0xffffffff; bitmaps[2] = 0; set_pattern(stripes[0].read_buf, 128*1024, PATTERN1); set_pattern(stripes[2].read_buf, 128*1024, PATTERN1^PATTERN2); // Reconstruct reconstruct_stripes_ec(stripes, 4, 2, bmp); check_pattern(stripes[1].read_buf, 128*1024, PATTERN2); assert(bitmaps[1] == 0xFFFFFFFF); free(data_buf); // Done use_ec(4, 2, false); } /*** 18. EC 4+2 error location bruteforce ***/ static void assert_eq_vec(const std::vector & b, const std::vector & a) { printf("Expect ["); for (int i = 0; i < a.size(); i++) printf(" %d", a[i]); printf(" ] have ["); for (int i = 0; i < b.size(); i++) printf(" %d", b[i]); printf(" ]\n"); assert(a == b); } void test_ec43_error_bruteforce() { use_ec(7, 4, true); osd_num_t osd_set[7] = { 1, 2, 3, 4, 5, 6, 7 }; osd_rmw_stripe_t stripes[7] = {}; split_stripes(4, 4096, 0, 4096 * 4, stripes); uint8_t *write_buf = (uint8_t*)malloc_or_die(4096 * 7); set_pattern(write_buf+0*4096, 4096, PATTERN0); set_pattern(write_buf+1*4096, 4096, PATTERN1); set_pattern(write_buf+2*4096, 4096, PATTERN2); set_pattern(write_buf+3*4096, 4096, PATTERN3); uint8_t *rmw_buf = (uint8_t*)calc_rmw(write_buf, stripes, osd_set, 7, 4, 7, osd_set, 4096, 0); calc_rmw_parity_ec(stripes, 7, 4, osd_set, osd_set, 4096, 0); check_pattern(stripes[4].write_buf, 4096, PATTERN0^PATTERN1^PATTERN2^PATTERN3); check_pattern(stripes[5].write_buf, 4096, 0xfcee568ba36371ac); // 2nd EC chunk check_pattern(stripes[6].write_buf, 4096, 0x139274739ae6f387); // 3rd EC chunk memcpy(write_buf+4*4096, stripes[4].write_buf, 4096); memcpy(write_buf+5*4096, stripes[5].write_buf, 4096); memcpy(write_buf+6*4096, stripes[6].write_buf, 4096); // Try to locate errors for (int i = 0; i < 7; i++) { stripes[i].read_start = 0; stripes[i].read_end = 4096; stripes[i].read_buf = write_buf+i*4096; stripes[i].write_buf = NULL; } // All good chunks auto res = ec_find_good(stripes, 7, 4, false, 4096, 0, 100); assert_eq_vec(res, std::vector({0, 1, 2, 3, 4, 5, 6})); // 1 missing chunk set_pattern(write_buf+1*4096, 4096, 0); res = ec_find_good(stripes, 7, 4, false, 4096, 0, 100); assert_eq_vec(res, std::vector({0, 2, 3, 4, 5, 6})); // 2 missing chunks set_pattern(write_buf+1*4096, 4096, 0); set_pattern(write_buf+5*4096, 4096, 0); res = ec_find_good(stripes, 7, 4, false, 4096, 0, 100); assert_eq_vec(res, std::vector({0, 2, 3, 4, 6})); // 3 missing chunks set_pattern(write_buf+1*4096, 4096, 0); set_pattern(write_buf+5*4096, 4096, 0); set_pattern(write_buf+6*4096, 4096, 0); res = ec_find_good(stripes, 7, 4, false, 4096, 0, 100); assert_eq_vec(res, std::vector()); // Done free(rmw_buf); free(write_buf); use_ec(7, 4, false); } /*** 19. EC 5+3 recover 5th data block but not 4th ***/ void test_recover_53_d5() { const int bmp = 128*1024 / 4096 / 8; use_ec(8, 5, true); osd_num_t osd_set[8] = { 1, 2, 3, 0, 0, 6, 7, 8 }; osd_rmw_stripe_t stripes[8] = {}; unsigned bitmaps[8] = { 0 }; // Read 512+128K split_stripes(5, 128*1024, 512*1024, 128*1024, stripes); assert(stripes[0].req_start == 0 && stripes[0].req_end == 0); assert(stripes[1].req_start == 0 && stripes[1].req_end == 0); assert(stripes[2].req_start == 0 && stripes[2].req_end == 0); assert(stripes[3].req_start == 0 && stripes[3].req_end == 0); assert(stripes[4].req_start == 0 && stripes[4].req_end == 128*1024); uint8_t *data_buf = (uint8_t*)malloc_or_die(128*1024*8); for (int i = 0; i < 8; i++) { stripes[i].read_start = stripes[i].req_start; stripes[i].read_end = stripes[i].req_end; stripes[i].read_buf = data_buf + i*128*1024; stripes[i].bmp_buf = bitmaps + i; } // Read using parity assert(extend_missing_stripes(stripes, osd_set, 5, 8) == 0); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024); assert(stripes[1].read_start == 0 && stripes[1].read_end == 128*1024); assert(stripes[2].read_start == 0 && stripes[2].read_end == 128*1024); assert(stripes[3].read_start == 0 && stripes[3].read_end == 0); assert(stripes[4].read_start == 0 && stripes[4].read_end == 128*1024); assert(stripes[5].read_start == 0 && stripes[5].read_end == 128*1024); assert(stripes[6].read_start == 0 && stripes[6].read_end == 128*1024); assert(stripes[7].read_start == 0 && stripes[7].read_end == 0); bitmaps[0] = 0xffffffff; bitmaps[1] = 0xffffffff; bitmaps[2] = 0xffffffff; bitmaps[3] = 0; bitmaps[4] = 0; bitmaps[5] = 0xffffffff; bitmaps[6] = 0x64646464; bitmaps[7] = 0; set_pattern(stripes[0].read_buf, 128*1024, 0x70a549add9a2280a); set_pattern(stripes[1].read_buf, 128*1024, 0xa70a549add9a2280); set_pattern(stripes[2].read_buf, 128*1024, 0x0a70a549add9a228); set_pattern(stripes[3].read_buf, 128*1024, 0); // 0x80a70a549add9a22 set_pattern(stripes[4].read_buf, 128*1024, 0); // 0x280a70a549add9a2 set_pattern(stripes[5].read_buf, 128*1024, 0x7572c28f7a91eb22); // xor set_pattern(stripes[6].read_buf, 128*1024, 0xb4542b32a560fe26); // 2nd EC chunk set_pattern(stripes[7].read_buf, 128*1024, 0); // Reconstruct reconstruct_stripes_ec(stripes, 8, 5, bmp); check_pattern(stripes[4].read_buf, 128*1024, 0x280a70a549add9a2); assert(bitmaps[4] == 0xFFFFFFFF); free(data_buf); // Done use_ec(8, 5, false); } void test_recover_22() { const int bmp = 128*1024 / 4096 / 8; use_ec(4, 2, true); osd_num_t osd_set[4] = { 1, 2, 3, 4 }; osd_num_t write_osd_set[4] = { 5, 0, 3, 0 }; osd_rmw_stripe_t stripes[4] = {}; unsigned bitmaps[4] = { 0 }; // split void *write_buf = (uint8_t*)malloc_or_die(4096); set_pattern(write_buf, 4096, PATTERN0); split_stripes(2, 128*1024, 120*1024, 4096, stripes); assert(stripes[0].req_start == 120*1024 && stripes[0].req_end == 124*1024); assert(stripes[1].req_start == 0 && stripes[1].req_end == 0); assert(stripes[2].req_start == 0 && stripes[2].req_end == 0); assert(stripes[3].req_start == 0 && stripes[3].req_end == 0); // calc_rmw void *rmw_buf = calc_rmw(write_buf, stripes, osd_set, 4, 2, 2, write_osd_set, 128*1024, bmp); for (int i = 0; i < 4; i++) stripes[i].bmp_buf = bitmaps+i; assert(rmw_buf); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024); assert(stripes[1].read_start == 120*1024 && stripes[1].read_end == 124*1024); assert(stripes[2].read_start == 0 && stripes[2].read_end == 0); assert(stripes[3].read_start == 0 && stripes[3].read_end == 0); assert(stripes[0].write_start == 120*1024 && stripes[0].write_end == 124*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 0); assert(stripes[2].write_start == 120*1024 && stripes[2].write_end == 124*1024); assert(stripes[3].write_start == 0 && stripes[3].write_end == 0); assert(stripes[0].read_buf == (uint8_t*)rmw_buf+4*1024); assert(stripes[1].read_buf == (uint8_t*)rmw_buf+132*1024); assert(stripes[2].read_buf == NULL); assert(stripes[3].read_buf == NULL); assert(stripes[0].write_buf == write_buf); assert(stripes[1].write_buf == NULL); assert(stripes[2].write_buf == (uint8_t*)rmw_buf); assert(stripes[3].write_buf == NULL); // encode set_pattern(stripes[0].read_buf, 128*1024, PATTERN1); set_pattern(stripes[1].read_buf, 4*1024, PATTERN2); memset(stripes[0].bmp_buf, 0xff, bmp); memset(stripes[1].bmp_buf, 0xff, bmp); calc_rmw_parity_ec(stripes, 4, 2, osd_set, write_osd_set, 128*1024, bmp); assert(*(uint32_t*)stripes[2].bmp_buf == 0); assert(stripes[0].write_start == 0 && stripes[0].write_end == 128*1024); assert(stripes[1].write_start == 0 && stripes[1].write_end == 0); assert(stripes[2].write_start == 120*1024 && stripes[2].write_end == 124*1024); assert(stripes[3].write_start == 0 && stripes[3].write_end == 0); assert(stripes[0].write_buf == stripes[0].read_buf); assert(stripes[1].write_buf == NULL); assert(stripes[2].write_buf == (uint8_t*)rmw_buf); assert(stripes[3].write_buf == NULL); check_pattern(stripes[2].write_buf, 4*1024, PATTERN0^PATTERN2); // decode and verify memset(stripes, 0, sizeof(stripes)); split_stripes(2, 128*1024, 0, 256*1024, stripes); assert(stripes[0].req_start == 0 && stripes[0].req_end == 128*1024); assert(stripes[1].req_start == 0 && stripes[1].req_end == 128*1024); assert(stripes[2].req_start == 0 && stripes[2].req_end == 0); assert(stripes[3].req_start == 0 && stripes[3].req_end == 0); for (int role = 0; role < 4; role++) { stripes[role].read_start = stripes[role].req_start; stripes[role].read_end = stripes[role].req_end; } assert(extend_missing_stripes(stripes, write_osd_set, 2, 4) == 0); assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024); assert(stripes[1].read_start == 0 && stripes[1].read_end == 128*1024); assert(stripes[2].read_start == 0 && stripes[2].read_end == 128*1024); assert(stripes[3].read_start == 0 && stripes[3].read_end == 0); void *read_buf = alloc_read_buffer(stripes, 4, 0); for (int i = 0; i < 4; i++) stripes[i].bmp_buf = bitmaps+i; assert(read_buf); assert(stripes[0].read_buf == read_buf); assert(stripes[1].read_buf == (uint8_t*)read_buf+128*1024); assert(stripes[2].read_buf == (uint8_t*)read_buf+2*128*1024); set_pattern(stripes[0].read_buf, 128*1024, PATTERN1); set_pattern(stripes[0].read_buf+120*1024, 4*1024, PATTERN0); set_pattern(stripes[2].read_buf, 128*1024, PATTERN1^PATTERN2); set_pattern(stripes[2].read_buf+120*1024, 4*1024, PATTERN0^PATTERN2); memset(stripes[0].bmp_buf, 0xff, bmp); memset(stripes[2].bmp_buf, 0, bmp); bitmaps[1] = 0; bitmaps[3] = 0; reconstruct_stripes_ec(stripes, 4, 2, bmp); assert(bitmaps[0] == 0xFFFFFFFF); assert(*(uint32_t*)stripes[1].bmp_buf == 0xFFFFFFFF); check_pattern(stripes[1].read_buf, 128*1024, PATTERN2); free(read_buf); // Done free(rmw_buf); free(write_buf); use_ec(4, 2, false); }